从工作线程调用主线程回调函数

时间:2010-07-28 06:23:59

标签: c++ windows

方案: 我有一个c ++ DLL。 在这个DLL中,我创建了一个工作线程。 在工作线程中,我有一个循环,等待用户通过USB硬件设备输入。 仅当USB设备上的用户输入符合某些条件时,循环才会结束。 另外,我需要实时反馈USB设备的用户使用反馈以在屏幕上显示。 它使用Delphi GUI进行反馈。

当用户使用USB设备时,Windows系统将进行回调功能。此回调函数写在同一个C ++ DLL文件中,并作为USB设备初始化函数中的参数传入。

我在DLL中使用了一个全局变量作为标志来确定此循环何时必须退出。

我也是从Delphi DLL加载这个C ++ DLL。 Delphi DLL - > C ++ DLL 反馈显示来自Delphi DLL。

基本上,我现在面临的问题是函数ptr,funcptr,根本无法调用。屏幕上没有实时反馈。这是Delphi DLL中的一个函数。 这是代码行:

(*(reinterprete_cast<FUNCPTR>(funcPtr)))("this is the feedback msg displayed on Delphi GUI");

有人有解决方案吗?

我是新手并且完全欣赏任何答案。谢谢你的帮助。

    //Global variable
    BOOL flag = TRUE;

    //A function type in Delphi calling app
    typedef void (__stdcall *FUNCPTR)(PCHAR);

    //Functions start here.....
    DWORD WINAPI ThreadProc(LPVOID lpParameter)
    { 
        do {} while (flag);
    }

    function_1st_CalledFromDelphiDLL(FUNCPTR funcPtr)
    {
        Initialize_USBDevice(handleUSBDeviceEvent_callback, funcPtr);
    }

    function_2nd_CalledFromDelphiDLL()
    {
        DWORD threadID;
        HANDLE hWorkerThread;

        hWorkerThread = CreateThread(NULL,0,ThreadProc, 0, 0 , &threadID);

        if (hWorkerThread!=NULL)
        {
            WaitForSingleObject(hWorkerThread, 30000);
        }
    }

    //This is the callback function, called by Windows system when user meddles with the USB device
    handleUSBDeviceEvent_callback(void *funcPtr)
    {
        flag = FALSE; //so loop in ThreadProc can exit
       //The following code cannot be executed at all. Even when i Try MessageBox( NULL,L"msg",NULL,NULL), the message box doesn't popup too. But, I can write something to a filestream here.
        (*(reinterprete_cast<FUNCPTR>(funcPtr)))("this is the feedback msg displayed on Delphi GUI");
    }

1 个答案:

答案 0 :(得分:2)

首先,我不建议使用变量在线程之间进行通信。出于您的目的,请使用活动。

你的DLL:

HANDLE _exitNow = NULL;
HANDLE _queueLock = NULL; // for part 2 below

// call this from your main at start
bool DLL_Initialize()
{
    _exitNow = CreateEvent(...);
    _queueLock = CreateMutex(...);
    ... initialize your device, add the callback ...
}

// call this from your main at exit
void DLL_Shutdown()
{
    SetEvent(_exitNow);
}

// your worker thread
void DLL_Worker()
{
    // use options so WaitFor...() does not block
    int result = WaitForSingleObject(_exitNow, ...);
    if(result indicates _exitNow was fired)
    {
        CloseHandle(_exitNow);
        ... shutdown sequence, unhook your callback, deinit your device ...
        CloseHandle(_queueLock);
    }
}

这将处理init / shutdown / worker位。而现在是困难的部分。

首先,您无法操纵工作线程中的UI位。我不记得确切原因 - 它与Windows消息队列的所有权有关,它由主线程拥有。如果您只需要显示应更新的内容,则应执行以下操作:

  • 声明输出数据的队列。这可能只是一个循环管理的数组。无论如何。
  • 声明一个互斥锁来保护它。如果您的队列已经是线程安全的,则是可选的。
  • 声明获取函数和在访问之前检查互斥锁的put过程。
  • 声明自定义窗口,即使您可以在Windows消息队列中发布。 (检查msdn中的自定义窗口消息)。并在主窗口中声明一个处理程序,它使用你的get()并更新显示。

假设如上所述,其余代码变为......(请注意,我有一段时间没有这样做,所以名称和声明可能略有偏差,但原理是相同的)

您的主要计划:

// double check how to do this exactly. I haven't done this in a long time. 
const CUSTOM_WINDOW_EVENT = WINDOWS_CUSTOM_MESSAGE + [SOMETHING]; 

// check for proper syntax
function Form.CustomHandler: Integer; handles CUSTOM_WINDOW_EVENT; 
var
  S: String;
begin
  S := GetDataFromDLL();
  ... update display based on S ...  
end;

你的DLL:

const CUSTOM_WINDOW_EVENT = WINDOWS_CUSTOM_MESSAGE + [SOMETHING]; 
TQueue queue; // find a suitable type. std::queue<> works fine

// delphi will call this
<String-type> DLL_GetStatus()
{
    ... wait on mutex using WaitForSingleObject() ...
    ... read one entry from queue ...
    ... release mutex ...
    ... return it ...
}

void PutStatus(String statusData)
{
    ... wait on mutex using WaitForSingleObject() ...
    ... write to queue ...
    ... release mutex ...
     ... push the custom message to the windows message queue, use PostMessage() IIRC ...
}

<whatever> handleUSBDeviceEvent_callback(void *funcPtr)
{
    ... read device, compose status data ...
    PutStats(statusData);
}

我从记忆中研究了所有这些,所以我确定会出现问题。希望你能得到原则。