从本机C DLL调用回调到VB6

时间:2014-04-25 19:45:42

标签: c vb6 callback

我正在尝试使用本机C函数来调用VB6应用程序中的回调。在VB中,代码如下所示:

Private Declare Sub StartUp Lib "library.dll" (ByVal cbAddress As Long)

Public Sub MySub
    Call StartUp(AddressOf MyCallback)
End Sub

Public Sub MyCallback(ByVal str As String)
' Use str in UI
End Sub

当我从VB6 IDE运行它时,一切都很好:调用回调,我可以使用str参数没问题。但是,当我将VB6应用程序编译为exe时,应用程序将在调用回调时崩溃。从我在Google搜索中可以看出,这似乎是某种线程问题。有人建议使用Win32 SendMessage以某种方式避免此线程问题。我无法弄清楚如何做到这一点。我会在回调中拨打SendMessage吗?我如何在主线程上收到此消息?另外,我如何将我的字符串传递给SendMessage?

编辑:我刚发现这个: Vb6 application works in the IDE but the executable crashes

然而,我的初步问题仍然存在。

Edit2:我也应该包含在C代码中。这就是定义和调用回调的方式:

typedef void (__stdcall *FUNCPTR)(BSTR);
int wslen = MultiByteToWideChar(CP_ACP, 0, cstr, strlen(cstr), 0, 0);
BSTR bstr = SysAllocStringLen(0, wslen);
MultiByteToWideChar(CP_ACP, 0, cstr, strlen(cstr), bstr, wslen);
((FUNCPTR) _cbAddress)(bstr);
SysFreeString(bstr);

同样,从IDE ...

调用时,这可以正常工作

1 个答案:

答案 0 :(得分:1)

显然,理想的做法是确保回调始终发生在VB应用程序的主线程上。如果做不到这一点,您将被迫使用SendMessage()到应用程序中的窗口,以利用Window自身在Windows之间的编组功能。

之前我写过一个VB应用程序,它从一个用于与遥控器集成的DLL中进行回调。但DLL使用另一个线程与硬件集成。在我的回调中,我使用SendMessage()WM_COPYDATA将数据编组到主VB线程中,这是通过子类化代码获取的。

当然,由于您正在编写C DLL并且只是传回ASCII文本,因此您可以跳过几个阶段而不必编写回调过程或具有子类代码。只需使用SetWindowText() API调用直接将文字写入TextBox即可。确保您在始终加载的表单上使用TextBox = Visible创建此False。然后你只需要使用这段代码:

BOOL WINAPI SetWindowText(
  _In_      HWND hWnd,
  _In_opt_  LPCTSTR lpString
);

HWND m_hWndTextBox

void StartUp(HWND hWndTextBox)
{
    m_hWndTextBox = hWndTextBox;
    // other stuff
}

void Callback(char *cstr) {
    SetWindowText(m_hWndTextBox, cstr);
}

VB代码:

' Form "Form1" with text box "Text1".

Private Declare Sub StartUp Lib "library.dll" (ByVal hWndTextBox As Long)

Public Sub MySub
    Call StartUp(Text1.hWnd)
End Sub

Private Sub Text1_Change()
    DoStuffWithDLLUpdateString Text1.Text
End Sub

你甚至不必将字符串转换为BSTR - VB会为你做这件事。