Как вытащить данные из lParam?

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
Glyckmen
Обычный пользователь
Обычный пользователь
 
Сообщения: 72
Зарегистрирован: 30.04.2006 (Вс) 15:32
Откуда: Санкт-Петербург

Как вытащить данные из lParam?

Сообщение Glyckmen » 07.06.2006 (Ср) 13:45

У меня такая ситуация. Имеется внешняя библиотека DLL написанная на DELPHI с двумя функциями. Во время работы функции происходит отсылка сообщений типа WM_COPYDATA (сделано для возможности реализовать прогрессбар), сообщения я перехватываю (с этим уже нет проблем :D ) , но появились проблемы с извлечением данных из этого сообщения.
Привожу часть описания библиотеки (от автора библиотеки):
Добавились новые параметры:
Wnd - это THandle (HWnd) окна или любого другого контрола, который будет обрабатывать сообщения. Введен этот параметр для возможности организовать ProgressBar. Во время выполнения функций посылаются сообщения
SendMessage(Wnd, WM_COPYDATA, 0, LParam(@cd));
где cd: TCopyDataStruct;
В cd.dwData ханится информация о том, сколько kb обработано. При этом максимальное значение прогрессбара должно равняться размеру входного файла. В примере показано, как это работает. Способ конечно не очень, но другого не придумал.

по этому описанию я сделал следующее:
Код: Выделить всё
Public Const WM_COPYDATA = &H4A
Public OldWndProc As Long

Public Type COPYDATASTRUCT
        dwData As Long
        cbData As Long
        lpData As Long
End Type

Public cd As COPYDATASTRUCT

Function WindowProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Dim lReturn As Long
lReturn = CallWindowProc(OldWndProc, hwnd, Msg, wParam, lParam)
Select Case Msg
    Case WM_COPYDATA
          LSet cd = lParam
          Debug.Print lParam
          Debug.Print "Обработано- "; cd.dwData; " байт"
End Select
WindowProc = lReturn
End Function

На строке LSet cd = lParam происходит вылет из VB, если эту строку закоментить то все проходит, только cd.dwData=0
Пробовал LSet, Set и просто без оператора cd=lParam результат один.
Вот кусок кода демонстрационной программы работы с библиотекой на DELPHI как она перехватывает и извлекает данные из сообщения от DLL и там все работает.
Код на DELPHI:
Код: Выделить всё
procedure TForm1.WMCopyData(var Msg: TMessage);
var
  cd: PCopyDataStruct;
begin
  //if Msg.Msg=WM_COPYDATA then
    begin
      cd := PCopyDataStruct(Msg.LParam);
      Progressbar1.Position:=(cd.dwData);
    end;
end;

Подскажите как мне взять нужные данные из lParam в VB6?

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 07.06.2006 (Ср) 13:51

делов то:

объявляешь:

Код: Выделить всё
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)



вместо

Код: Выделить всё
LSet cd = lParam


пишешь

Код: Выделить всё
CopyMemory cd, ByVal lParam, LenB(cd)
Весь мир матрица, а мы в нем потоки байтов!

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 07.06.2006 (Ср) 13:54

<Удалено, ибо пока писал уже ответили>
Последний раз редактировалось keks-n 07.06.2006 (Ср) 13:55, всего редактировалось 1 раз.
Изображение

Glyckmen
Обычный пользователь
Обычный пользователь
 
Сообщения: 72
Зарегистрирован: 30.04.2006 (Вс) 15:32
Откуда: Санкт-Петербург

Сообщение Glyckmen » 07.06.2006 (Ср) 13:54

!Viper!
Спасибо, щас попробую!

Glyckmen
Обычный пользователь
Обычный пользователь
 
Сообщения: 72
Зарегистрирован: 30.04.2006 (Вс) 15:32
Откуда: Санкт-Петербург

Сообщение Glyckmen » 07.06.2006 (Ср) 14:23

!Viper! Все равно вылетает в этом месте. :(
keks-n Обявил все параметры функции CopyMemory как ByVal, только не понимаю как передать указатель на структуру. А так все равно вылетает! :( :( :(


PS: Все переменные одного типа Long. При выводе Debug.Print lParam там хранится число, оно всегда одинаковое (в моем случае всегда = 1234564). Во время выполнения функции DLL посылаются всего 4 сообщения.
PSS: Правда теперь вылетает только на CopyMemory, а раньше уже вылетало при загрузке формы.

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Сообщение Twister » 07.06.2006 (Ср) 14:39

не понимаю как передать указатель на структуру
VarPtr?
CopyMemory cd, ByVal lParam, LenB(cd)

Надо
Код: Выделить всё
CopyMemory ByVal VarPtr(cd), ByVal lParam, Len(cd)
Вообщем, почитай эту статью, в ней идет активная работа с памятью и указателями...
А я все практикую лечение травами...

Glyckmen
Обычный пользователь
Обычный пользователь
 
Сообщения: 72
Зарегистрирован: 30.04.2006 (Вс) 15:32
Откуда: Санкт-Петербург

Сообщение Glyckmen » 07.06.2006 (Ср) 20:05

Все равно ничего не получается! :(
В данном случае структура cd имеет 12 байт, а lParam 4 байта, при попытке скопировать функцией CopyMemory происходит выкидыш из VB6, такое происходит даже в пустом приложении:
Код: Выделить всё
Option Explicit
Private Declare Function CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal length As Long)
Private Type COPYDATASTRUCT
        dwData As Long
        cbData As Long
        lpData As Long
End Type
Private cd As COPYDATASTRUCT
Dim lParam As Long

Private Sub Command1_Click()
lParam = 1234564
CopyMemory ByVal VarPtr(cd), ByVal lParam, ByVal Len(lParam)
Debug.Print cd.dwData
End Sub

Кто хочет тот пусть попробует этот код и убедится что происходит вылет из среды разработки.
Может подскажите что тут не так или может есть другой способ получить данные (см. 1 пост)

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 07.06.2006 (Ср) 20:16

Вылет здесь потому, что по адресу 1234564 ничего нет, а не потому, что этот адрес занимает 4 байта.


Кроме того, если в WindowProc обрабатывается только WM_COPYDATA, то можно переобъявить lParam как ByRef COPYDATASTRUCT, и не париться.
Изображение

Glyckmen
Обычный пользователь
Обычный пользователь
 
Сообщения: 72
Зарегистрирован: 30.04.2006 (Вс) 15:32
Откуда: Санкт-Петербург

Сообщение Glyckmen » 07.06.2006 (Ср) 20:37

Кроме того, если в WindowProc обрабатывается только WM_COPYDATA, то можно переобъявить lParam как ByRef COPYDATASTRUCT, и не париться.

А вот с этого места можно по подробней!

ЗЫ: Не сочтите за назойливость но я пока не все знаю и хочу узнать как можно больше.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 07.06.2006 (Ср) 20:43

Код: Выделить всё
Function WindowProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByRef lParam As COPYDATASTRUCT) As Long

Dim lReturn As Long
lReturn = CallWindowProc(OldWndProc, hwnd, Msg, wParam, lParam)
Select Case Msg
    Case WM_COPYDATA
          Debug.Print "Обработано- "; lParam.dwData; " байт"
End Select
WindowProc = lReturn
End Function
Изображение

Glyckmen
Обычный пользователь
Обычный пользователь
 
Сообщения: 72
Зарегистрирован: 30.04.2006 (Вс) 15:32
Откуда: Санкт-Петербург

Сообщение Glyckmen » 07.06.2006 (Ср) 21:15

Все равно вылетает, только теперь даже форма не успевает загрузиться. Это скорее всего происходит из-за того что у меня перехватываются сообщения на форму (при том все сообщения подряд) и при возвращении форме сообщений по:
Код: Выделить всё
lReturn = CallWindowProc(OldWndProc, hwnd, Msg, wParam, lParam)
, то форма при обработке сообщений не понимает lParam As COPYDATASTRUCT, побробую создать что-нибудь ненужное на форме (ну например пустой Label) и перехватывать сообщения уже адресованные ему, тогда наверно можно будет не возвращать обратно сообщение и спокойно его обработать. Завтра попробую и отпишусь.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 07.06.2006 (Ср) 21:25

А как объявлена CallWindowProc?
Изображение

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Сообщение Twister » 08.06.2006 (Чт) 6:56

Код: Выделить всё
Private Sub Command1_Click()
lParam = 1234564
CopyMemory ByVal VarPtr(cd), ByVal lParam, ByVal Len(lParam)
Debug.Print cd.dwData
End Sub
Какое нужно иметь чувство юмора, чтоб написать такое... :lol: CopyMemory нужно вставить именно туда, где она должна быть - в WindowProc.
А я все практикую лечение травами...

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 08.06.2006 (Чт) 6:58

В принципе все предложенные варианты должны были работать. Возможно неправильно объявлена CallWindowProc или что-то не так отправляется из самой DLL.
Весь мир матрица, а мы в нем потоки байтов!

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Сообщение Twister » 08.06.2006 (Чт) 7:03

В принципе все предложенные варианты должны были работать.
Ты про
Код: Выделить всё
CopyMemory cd, ByVal lParam, LenB(cd)
? :wink:
А я все практикую лечение травами...

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 08.06.2006 (Чт) 7:27

Twister писал(а):
В принципе все предложенные варианты должны были работать.
Ты про
Код: Выделить всё
CopyMemory cd, ByVal lParam, LenB(cd)
? :wink:


А почему он не должен работать?
Весь мир матрица, а мы в нем потоки байтов!

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Сообщение Twister » 08.06.2006 (Чт) 7:34

Вопросом на вопрос: а почему должен? :wink:
В копимемори на этом месте лонг. А cd совсем не лонг.
А я все практикую лечение травами...

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 08.06.2006 (Чт) 7:37

В копимемори на этом месте ByRef As Any, и передаётся ссылка на cd.
Есть сомнения?
Изображение

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 08.06.2006 (Чт) 7:39

Хм... если посмотреть привиденный мной код полностью, то мы увидим, что CopyMemory объявлена через Any, а не через Long
!Viper! писал(а):
Код: Выделить всё
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

CopyMemory cd, ByVal lParam, LenB(cd)



При таком объявлении, такой вызов вполне корректен.
Весь мир матрица, а мы в нем потоки байтов!

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Сообщение Twister » 08.06.2006 (Чт) 7:42

Блин... а у меня там лонг. :cry:
Ну при таком раскладе конечно сработает.

PS: 2 !Viper! Сорри, не посмотрел, это все проклятый вчерашний абсент...
А я все практикую лечение травами...

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 08.06.2006 (Чт) 7:47

Вообще хотелось бы увидеть последний вариант кода от автора, а то мы тут уже скоро гадать начнем. Со всеми объявлениями и вызовами.
Весь мир матрица, а мы в нем потоки байтов!

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Сообщение Twister » 08.06.2006 (Чт) 7:49

Последний вариант говоришь? :D
Код: Выделить всё
Private Sub Command1_Click()
lParam = 1234564
CopyMemory ByVal VarPtr(cd), ByVal lParam, ByVal Len(lParam)
Debug.Print cd.dwData
End Sub
А я все практикую лечение травами...

Glyckmen
Обычный пользователь
Обычный пользователь
 
Сообщения: 72
Зарегистрирован: 30.04.2006 (Вс) 15:32
Откуда: Санкт-Петербург

Сообщение Glyckmen » 08.06.2006 (Чт) 13:02

Господа спасибо что откликнулись, сегодня у меня все получилось :lol: :lol:
Раньше было что перехватывались все сообщения адресованные форме и мне надо было их отправлять обратно на форму и поэтому ни один из способов не работал.
А теперь сделал так:
На форме где у меня происходили все эти события, я создал простую кнопку и сделал ее Visible=False т.е. невидимой на форме, а при вызове функции я указал hWnd этой кнопки т.е. теперь функция посылает сообщения для этой кнопки, и теперь я перехватываю все сообщения для этой кнопки не заботясь об их возвращении (т.к. этой кнопкой я не пользуюсь) и по совету от tyomitch я переопределил lParam сразу на тип COPYDATASTRUCT
Код теперь выглядит так:
Код формы
Код: Выделить всё
Private Sub Form_Load()
  gWH = Form2.Command1.hWnd
  OldWndProc = SetWindowLong(gWH, GWL_WNDPROC, AddressOf WindowProc)
  ProgressBar1.Max = FileLen(inputfile)
End Sub

Private Sub Form_Unload(Cancel As Integer)
  SetWindowLong gWH, GWL_WNDPROC, OldWndProc
End Sub
Private Sub XpB1_Click()
'***************Вызываю функцию BZIP2.DLL***************
   CompressBZIP2 inputfile, outpatch + "\" + outputfile + ".bz2", Form2.Command1.hWnd, 3
End Sub

Код модуля:
Код: Выделить всё
Public Const WM_COPYDATA = &H4A
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public OldWndProc As Long
Public Type COPYDATASTRUCT
        dwData As Long
        cbData As Long
        lpData As Long
End Type

Function WindowProc(ByVal hWnd As Long, ByVal msg As Long, ByVal wParam As Long, ByRef lParam As COPYDATASTRUCT) As Long
'Здесь я теперь сразу определяю lParam как COPYDATASTRUCT
   
    Select Case msg
        Case WM_COPYDATA
              Debug.Print "Обработано- "; lParam.dwData; " Байт"
              Form2.ProgressBar1.Value = lParam.dwData
    End Select
End Function

По такому коду все работает.:D

Спасибо tyomitch твоя идея оказалось работоспособной.:wink:

PS: А вот с CopyMemory так ничего и не заработало :(

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Сообщение Twister » 08.06.2006 (Чт) 13:07

PS: А вот с CopyMemory так ничего и не заработало :cry:
Должно было. Попрактикуйся - пригодится...
А я все практикую лечение травами...

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 08.06.2006 (Чт) 13:08

Glyckmen писал(а):PS: А вот с CopyMemory так ничего и не заработало :(


что довольно таки удивительно
Весь мир матрица, а мы в нем потоки байтов!

Glyckmen
Обычный пользователь
Обычный пользователь
 
Сообщения: 72
Зарегистрирован: 30.04.2006 (Вс) 15:32
Откуда: Санкт-Петербург

Сообщение Glyckmen » 08.06.2006 (Чт) 13:55

Twister В этой-же программе (только в другом модуле) я использую CopyMemory но там я копирую один массив в другой, эти массивы одного типа "Byte" и одной размерности (около 20 мегов), и все копируется мгновенно (просто сказка) и проблем нет.

Есть другая проблема. Как мне теперь во время выполнения функции (а она может длиться и час) принудительно закрыть(завершить, прервать) ее если этого хочет пользователь, не убивая саму программу. Подскажите в каком направлении рыть или какой нибудь аналогичный пример.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 08.06.2006 (Чт) 14:06

Glyckmen писал(а):Есть другая проблема. Как мне теперь во время выполнения функции (а она может длиться и час) принудительно закрыть(завершить, прервать) ее если этого хочет пользователь, не убивая саму программу. Подскажите в каком направлении рыть или какой нибудь аналогичный пример.

Лол! http://www.vbstreets.ru/VB/Articles/66058.aspx
:lol:
Изображение

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Сообщение Twister » 08.06.2006 (Чт) 14:06

Процедуру в поток или фибер...
А я все практикую лечение травами...

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Сообщение Twister » 08.06.2006 (Чт) 14:09

tyomitch
Хорошо что я линк не дал - а то вообще два одиинаковых поста получилось бы... :lol:
А я все практикую лечение травами...


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: AhrefsBot, SemrushBot и гости: 132

    TopList