VB6 SendMessage для отправки пользовательского типа данных - PullRequest
0 голосов
/ 04 января 2012

В настоящее время я успешно использую функцию SendMessage API Win32 для отправки текста между двумя потоками с помощью параметра WM_SETTEXT.

Что я хотел бы сделать, это отправить пользовательский тип данных вместо примитивных типов данных.

Итак, допустим, у меня есть

Type myType
    a as Integer
    b(5) as Boolean
    d(15) as Double
End Type
Dim tmp as myType

Я хотел бы иметь возможность:

Call SendMessage(dstHWnd, WM_SETTEXT, 0, tmp)

Я предполагаю, что мне придется использовать WM_COPYDATA или аналогичный, но другойпроблема в том, что это приводит к ошибке, потому что мой тип данных не может быть преобразован в Any для каждого определения функции:

Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As Any) As Long

Возможно ли уговорить это преобразование?Или есть альтернативный метод передового опыта (быстрый и оптимальный)?

Ответы [ 3 ]

3 голосов
/ 04 января 2012

Как насчет использования файла с отображением в памяти?

'Write to MyMMF

Private Function writeMyType(newMyType As myType)

    hMMF = OpenFileMapping(FILE_MAP_ALL_ACCESS, False, "MyMMF")

    If hMMF = 0 Then
        hMMF = CreateFileMapping(-1, 0, PAGE_READWRITE, 0, LenB(newMyType), "MyMMF")
    End If

    If Not hMMF = 0 Then
        pMemfile = MapViewOfFile(hMMF, FILE_MAP_ALL_ACCESS, 0, 0, 0)
        RtlMoveMemory1 pMemfile, ByVal newMyType, LenB(newMyType)
    End If

    CloseHandle hMMF

End Function

'Read from MyMMF
Private Function readMyType(ByRef inMyType As myType)

    hMMF = OpenFileMapping(FILE_MAP_ALL_ACCESS, False, "MyMMF")

    If hMMF = 0 Then
        MsgBox "No data in MyMMF"
        Exit Function
    Else
        pMemfile = MapViewOfFile(hMMF, FILE_MAP_ALL_ACCESS, 0, 0, 0)
        RtlMoveMemory2 ByVal inMyType, pMemfile, LenB(inMyType)
    End If

    CloseHandle hMMF

End Function


'Declares and Constants
Public Type myType
    a As Integer
    b(5) As Boolean
    d(15) as Double
End Type


Public Declare Function OpenFileMapping Lib "kernel32" Alias "OpenFileMappingA" (ByVal dwDesiredAccess As Integer, ByVal bInheritHandle As Integer, ByVal lpName As String) As Long
Public Declare Function CreateFileMapping Lib "kernel32" Alias "CreateFileMappingA" (ByVal hFile As Long, ByVal lpAttributes As Long, ByVal flProtect As Integer, ByVal dwMaximumSizeHigh As Integer, ByVal dwMaximumSizeLow As Integer, ByVal lpName As String) As Long
Public Declare Function MapViewOfFile Lib "kernel32" (ByVal hFileMappingObject As Long, ByVal dwDesiredAccess As Long, ByVal dwFileOffsetHigh As Long, ByVal dwFileOffsetLow As Long, ByVal dwNumberOfBytesToMap As Long) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

Public Declare Sub RtlMoveMemory1 Lib "kernel32.dll" Alias "RtlMoveMemory" ( _
ByVal Destination As Long, _
ByRef Source As Any, _
ByVal Length As Long)

Public Declare Sub RtlMoveMemory2 Lib "kernel32.dll" Alias "RtlMoveMemory" ( _
ByRef Destination As Any, _
ByVal Source As Long, _
ByVal Length As Long)

Public Const FILE_MAP_ALL_ACCESS = &H1F
Public Const PAGE_READWRITE = &H4
3 голосов
/ 04 января 2012

Объявите последний параметр SendMessage как byref lParam as myType.

Однако вы злоупотребляете системой обмена сообщениями. Это нормально, если вы знаете, что делаете, и уверены, что никакая системная логика обработки по умолчанию никогда не будет применена к этому сообщению.


Чтобы уточнить, на стороне получателя вы делаете следующее, чтобы получить данные.
Сначала вы объявляете процедуру обработки сообщений с последним параметром ByVal lParam As Long. Также есть функция:

Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Затем, когда вы получите сообщение:

if uMsg = WM_SETTEXT then
  dim t as myType
  copymemory t, byval lParam, len(t)

  'Using t here
end if

Чтобы уточнить немного.

Поскольку все потоки находятся внутри одного процесса, вы можете просто поделиться указателями и сделать это с помощью WM_COPYDATA. Вам понадобится только первый член структуры COPYDATASTRUCT.

На конце отправки вы устанавливаете COPYDATASTRUCT.dwData = VarPrt(your_struct).

На принимающей стороне вы делаете ту же самую вещь CopyMemory, показанную выше.

Обратите внимание, что если ваша подпрограмма обработки сообщений будет получать только это единственное сообщение (и никаких других сообщений), то вы можете просто объявить его последний параметр как ByRef lParam As myType и использовать его напрямую, избегая копирования.

1 голос
/ 04 января 2012

Если это два потока (каждый со своим окном в VB6? Хмм), то вам просто нужно отправить указатель на переменную VarPtr(blah) и убедиться, что вы скопировали в оконной процедуре перед возвратом.

Если, однако, потоки находятся в двух отдельных процессах, у вас гораздо меньше вариантов.

Вы можете использовать сообщение WM_COPYDATA, которое выполняет маршалинг для вас, или настроить некоторую общую / глобальную память ипередать указатель / смещения через обычный SendMessage() Обычные методы синхронизации потоков применяются к последним методам.

...