从DLL中调用另一个进程中的方法,该进程由进程加载

时间:2015-01-19 11:20:38

标签: c++ c visual-c++ dll callback

要求: 在“屏幕键盘”中按键时,应调用客户端应用程序中的方法

enter image description here

为了完成上述要求,我们正在创建一个DLL并导出一个回调方法。

extern "C"
{
   void __declspec(dllexport) __stdcall onKeyPress(void);
}

此DLL将由“屏幕键盘”动态加载,并将调用从DLL导出的回调方法。

Where I am stuck:

我必须通过DLL中的导出回调函数调用“客户端应用程序”中的方法,这样只要键盘上有按键,“客户端应用程序”就会收到通知。

我无法在客户端应用程序中调用该方法。

认为屏幕键盘将加载DLL并将调用导出的方法,如图所示 [示例代码]

#pragma comment(lib,"..\\Debug\\SharedDll.lib")
__declspec(dllimport) void __stdcall calledByOnKeyPress(int scanCode);
int main(void)
{
    char ch = getchar();
    calledByOnKeyPress(ch);
    return 0;
}

从DLL,我试图在应用程序中调用这样的方法。

void __declspec(dllexport) __stdcall calledByOnKeyPress(int scanCode)
{
    callBackFunction(scanCode);
}

我没有得到如何继续......

3 个答案:

答案 0 :(得分:2)

当你加载.dll时,它会在不同的进程上有不同的实例(可以这么说)。

例如,如果App1使用myDll.dll而App2也使用myDll.dll,如果您在App1中的myDll.dll内部进行调用,App2将无法看到它。

Dll只是运行时编译代码的提供者。

对于进程内通信,您需要使用进程内方法,例如通过套接字,共享内存等进行通信。

在您的情况下,根据我的理解,键盘处于不同的进程,您需要通过套接字(例如)向客户端App发出键盘更改信号。

答案 1 :(得分:2)

可能的解决方案之一涉及以下内容。

  1. SharedDll应该定义一个可以在多个进程之间共享的公共数据段。
  2. 在客户端应用程序中创建单独的(消息)线程以接收键盘消息。然后通过导出函数将此线程的线程ID设置为SharedDll的公共数据段。
  3. 您的屏幕键盘进程会像往常一样加载SharedDll并调用onKeyPress()函数。

  4. 在SharedDll中的onKeyPress()函数内,它应该检查存储在公共dll数据段中的有效线程ID。如果有一个有效的线程ID,那么只需发布一个线程消息。

  5. 上面的第4步将从"屏幕键盘上传送键盘消息"处理在第二个进程内运行的线程"客户端应用程序"!

    使用Dll common-data-segment是这里的决定性技术。

    在客户端应用程序中

    DWORD WINAPI KeyboardMsgThread( LPVOID lpParam )
    {
        // Start the message thread
    
        MSG stMsg;
        while( GetMessage( &stMsg, 0, KEYBOARD_MSG_MIN, KEYBOARD_MSG_MAX ))
        {
            // Process the keyboard message here!
        }
        return TRUE;
    }
    
    
    bool CreateKeyboardMsgThread()
    {
        DWORD dwThreadID = 0;
        CreateThread( 0, 0, KeyboardMsgThread, 0, 0, &dwThreadID );
        Sleep( 100 );// Let the message queue be created.
        SetKeyboardThread( dwThreadID );//Set the thread id to the common data area.
        return true;
    }
    

    在SharedDll内

    #pragma data_seg(".SHARED")
    DWORD Dll_dwThreadID = 0;
    #pragma data_seg()
    #pragma comment(linker, "/section:.SHARED,RWS")
    extern "C"
    {
       void __declspec(dllexport) __stdcall onKeyPress(void)
       {
           if( 0 != Dll_dwThreadID )
           {
               //When there is a valid thread id, simply post it to the thread. 
               //This thread can be inside any other process.
               PostThreadMessage( Dll_dwThreadID, KEYBOARD_MSG_MIN, 0, 0 );
           }
       }
    
       // Client Application will create the thread and calls this function to
       // set the thread-id to the common-data segment so that it can be 
       // utilized by the instance of SharedDll which resides in the process 
       // space of On Screen Keyboard.
       void __declspec(dllexport) __stdcall SetKeyboardThread(DWORD dwThreadID)
       {
           Dll_dwThreadID = dwThreadID;
       }
    }
    

    在屏幕键盘应用程序内

    bool RecieveKeyboardNotification()
    {
            onKeyPress();
    }
    

    希望这有帮助!

答案 2 :(得分:0)

我认为,客户端应用程序加载了dll,而dll应该在应用程序中调用一个函数。

因此,您的应用必须注册一个应由dll调用的函数。 因此,你需要像(简化):

这样的东西
void registerCallback(CallbackFunctionPointer callbackfunction){
  //the app, or anyone else can call this to register a function which should be called 
  remember = callbackfunction;
}

并且,如果按下该键,则调用:

void something(char ch){
  //call the previously registered callback
  remember(ch);
}

变量"记住"应定义为静态var,并且必须声明,如:

typedef void (*CallbackFunctionPointer)      (char ch);
static CallbackFunctionPointer remember;

希望,这有助于