【问题标题】:Calling a method in another process from DLL which is loaded by a process从进程加载的 DLL 调用另一个进程中的方法
【发布时间】:2015-01-19 11:20:37
【问题描述】:

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

为了完成上述要求,我们正在创建一个 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);
}

我不知道如何继续......

【问题讨论】:

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


    【解决方案1】:

    其中一个可能的解决方案涉及以下内容。

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

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

    上面的第 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】:

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

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

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

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

      在您的情况下,据我了解,键盘位于不同的进程中,您需要通过套接字(例如)向客户端应用程序发出键盘更改的信号。

      【讨论】:

        【解决方案3】:

        我假设,客户端应用程序加载 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);
        }
        

        变量“remember”应该定义为静态变量,并且必须声明,例如:

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

        希望,这会有所帮助

        【讨论】:

        • 我在发帖前试过这个。这是行不通的。原因可能是调用代码在不同的进程(屏幕键盘+ Dll)和被调用的代码在不同的进程(客户端应用程序)。
        • 对不起,我没有真正理解你的问题。您想在 2 个应用程序之间进行通信。如果您不想使用 MNS 的 MichaelCMS 解决方案,您可以尝试使用信号量。我推荐插座。
        猜你喜欢
        • 2021-11-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多