2010-07-28 2 views
2

Сценарий: У меня есть C++ DLL. В этой DLL я создал рабочий поток. В рабочем потоке у меня есть цикл, который ждет ввода пользователя через USB-устройство. Цикл заканчивается только тогда, когда пользовательский ввод на USB-устройстве соответствует некоторым критериям. Кроме того, мне нужно обращать внимание на обратную связь использования устройства USB в режиме реального времени для отображения на экране. Он использует интерфейс Delphi для обратной связи.Вызов функции обратного вызова главной темы из рабочего потока

Когда пользователь использует USB-устройство, функция обратного вызова будет выполнена системой Windows. Эта функция обратного вызова записывается в один файл C++ DLL и передается как параметр в функции инициализации устройства USB.

Я использовал глобальную переменную в DLL как флаг, чтобы определить, когда этот цикл должен выйти.

Я также загружаю эту C++ DLL из DLL Delphi. Delphi DLL -> C++ DLL Экран обратной связи из DLL Delphi.

В основном проблема, с которой я сталкиваюсь сейчас, заключается в том, что функция 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"); 
    } 

ответ

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); 
    } 
} 

Это заботится о инициализации/выключения/рабочих битов. И теперь тяжелая часть.

Во-первых, вы не можете манипулировать битами пользовательского интерфейса из рабочего потока. Я не могу точно помнить, почему это связано с владением очереди сообщений Windows, которая принадлежит первичному потоку. Если все, что вам нужно сделать, это что-то отображаемое, которое должно быть обновлено, вы должны сделать следующее:

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

Я работал над этим из памяти, поэтому я уверен, что что-то не так. Надеюсь, вы все равно получите принципы.

+0

Я добавил код. Пользовательский вход - устройство USB-датчика. – Robogal

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