2012-01-04 4 views
0

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

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

Так скажем, у меня есть

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 или аналогичный, но другой вопрос, это производит ошибка, потому что мой тип данных не может быть введен в Любые, для определения функции:

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 

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

+2

Просто разные потоки в одном и том же процессе (что трудно сделать безопасно в VB6) или в разных процессах? Последнее гораздо более строгое. – Deanna

ответ

3

Объявление последнего параметра 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 и использовать его напрямую, избегая копирования.

+0

Если я это сделаю, последним параметром также должен быть ByRef (определяемые пользователем типы не могут быть переданы byval). Так что скажем, я передаю его с помощью ref ... как я могу получить получение в потоке назначения? В настоящее время я устанавливаю текст текстового поля sendmessage в hwnd текстового поля; пользовательские типы не имеют hwnd, хотя –

+0

@AuthmanApatira См. редактирование. – GSerg

+0

Спасибо за помощь до сих пор Грег. Это похоже на работу: SendMessage отправляет ByVal VarPtr (my_struct). My Textbox получает этот указатель как строку, которую я возвращаю в Long. Я использую функцию RtlMoveMemory, чтобы разыменовать указатель обратно на мой пользовательский тип. Осталось всего 1 проблема: строки в UDT отправляют только первый символ, а не всю строку. Это действительно хорошо для моих целей, так как мой UDT - это просто ints, doubles и bools .. но только из любопытства, прежде чем закрыть этот вопрос, есть ли способ получить полный размер строки? –

1

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

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

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

+0

Несколько потоков в одном процессе. Предположим, я использую varptr (blah) для отправки указателю на мой объект клиенту; как я могу разыменовать указатель (длинный) на пользовательский тип на принимающей стороне? –

+0

RtlMoveMemory2 tmp2, VarPtr (tmp), LenB (tmp2). Это скопирует tmp в tmp2, если tmp и tmp2 находятся в пространстве памяти того же процесса. Если вы пытаетесь пройти межпроцессный процесс, используйте мой ответ. RtlMoveMemory2 - это мой ответ. – Motes

3

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

'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 
+0

Приятная идея, особенно для более объемных передач. – wqw

Смежные вопросы