Thread: Retrieving Data from DLL

  1. #1
    Registered User
    Join Date
    Apr 2007
    Posts
    102

    Retrieving Data from DLL

    Hey everyone, I'm making a program that will be able to watch and record some mouse pixel coordinates when I click the left mouse button anywhere on the screen. However I haven't been able to retrieve the mouse pixel coordinates out of the DLL that contains the function. I'm using windows WH_MOUSE_LL hook for reading the data. Basically I need to figure out how to get the mouseX and mouseY from the DLL into my separate program. Here's my code:

    main.cpp

    Code:
    #include <windows.h>
    #include <iostream>
    
    #include "C:\Users\JohnJr\Desktop\My Programs\Hooks\MouseHook.h"
    #include "C:\Users\JohnJr\Desktop\My Programs\Hooks\HookProcs\main.h"
    /*  Declare Windows procedure  */
    LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
    
    /*  Make the class name into a global variable  */
    char szClassName[ ] = "CodeBlocksWindowsApp";
    
    MouseHook* h = 0;
    
    int WINAPI WinMain (HINSTANCE hThisInstance,
                         HINSTANCE hPrevInstance,
                         LPSTR lpszArgument,
                         int nCmdShow)
    {
        HWND hwnd;               /* This is the handle for our window */
        MSG messages;            /* Here messages to the application are saved */
        WNDCLASSEX wincl;        /* Data structure for the windowclass */
    
        /* The Window structure */
        wincl.hInstance = hThisInstance;
        wincl.lpszClassName = szClassName;
        wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
        wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
        wincl.cbSize = sizeof (WNDCLASSEX);
    
        /* Use default icon and mouse-pointer */
        wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
        wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
        wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
        wincl.lpszMenuName = NULL;                 /* No menu */
        wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
        wincl.cbWndExtra = 0;                      /* structure or the window instance */
        /* Use Windows's default colour as the background of the window */
        wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
    
        /* Register the window class, and if it fails quit the program */
        if (!RegisterClassEx (&wincl))
            return 0;
    
        /* The class is registered, let's create the program*/
        hwnd = CreateWindowEx (
               0,                   /* Extended possibilites for variation */
               szClassName,         /* Classname */
               "Code::Blocks Template Windows App",       /* Title Text */
               WS_OVERLAPPEDWINDOW, /* default window */
               CW_USEDEFAULT,       /* Windows decides the position */
               CW_USEDEFAULT,       /* where the window ends up on the screen */
               544,                 /* The programs width */
               375,                 /* and height in pixels */
               HWND_DESKTOP,        /* The window is a child-window to desktop */
               NULL,                /* No menu */
               hThisInstance,       /* Program Instance handler */
               NULL                 /* No Window Creation data */
               );
    
        /* Make the window visible on the screen */
        ShowWindow (hwnd, nCmdShow);
        h = new MouseHook();
    
        bool exiting = false;
    
        if(!h->SetFunction("C:/Users/JohnJr/Desktop/My Programs/Hooks/HookProcs/bin/Debug/HookProcs.dll"))
            MessageBoxA(hwnd, "Error setting function", "Error", MB_ICONEXCLAMATION);
    
        while(!exiting)								// Loop That Runs Until Ending Program
    	{
            if (PeekMessage(&messages,NULL,0,0,PM_REMOVE))			// Is There A Message Waiting?
    		{
                if (messages.message==WM_QUIT)				// Have We Received A Quit Message?
    			{
    				exiting=TRUE;					// If So done=TRUE
    			}
    			else							// If Not, Deal With Window Messages
    			{
                    TranslateMessage(&messages);				// Translate The Message
    				DispatchMessage(&messages);				// Dispatch The Message
    			}
    		}
    		else								// If There Are No Messages
    		{
                // Execute main program
    
                if(h->isSet())
                    std::cout << mouseX;
    
            }
    
        }
    
        /* The program return-value is 0 - The value that PostQuitMessage() gave */
        return messages.wParam;
    }
    
    
    /*  This function is called by the Windows function DispatchMessage()  */
    
    LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)                  /* handle the messages */
        {
            case WM_DESTROY:
                PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
                break;
    
            case WM_KEYUP:
    
                if(wParam == VK_SPACE)
                    h->Set();
    
                else if(wParam == VK_ESCAPE)
                    h->UnSet();
    
                break;
    
            default:                      /* for messages that we don't deal with */
                return DefWindowProc (hwnd, message, wParam, lParam);
        }
    
        return 0;
    }
    The DLL's main.h file

    Code:
    #ifndef __MAIN_H__
    #define __MAIN_H__
    
    #include <windows.h>
    #include <iostream>
    
    /*  To use this exported function of dll, include this header
     *  in your project.
     */
    
    #ifdef BUILD_DLL
        #define DLL_EXPORT __declspec(dllexport)
    #else
        #define DLL_EXPORT __declspec(dllimport)
    #endif
    
    
    #ifdef __cplusplus
    extern "C"
    {
    #endif
    
    int mouseX = 0;
    int mouseY = 0;
    
    DLL_EXPORT LRESULT CALLBACK MProc(int nCode, WPARAM wParam, LPARAM lParam);
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif // __MAIN_H__
    the main.cpp of DLL

    Code:
    #include "main.h"
    
    // a sample exported function
    DLL_EXPORT LRESULT CALLBACK MProc(int nCode, WPARAM wParam, LPARAM lParam)
    {
        if(nCode < 0)
            return CallNextHookEx(NULL, nCode, wParam, lParam);
    
        //Check wParam here
        if (wParam == WM_LBUTTONUP)
        {
            MOUSEHOOKSTRUCT * hHook = (MOUSEHOOKSTRUCT*)lParam;
            mouseX = hHook->pt.x;
            mouseY = hHook->pt.y;
    
        }
    
        return CallNextHookEx(NULL, nCode, wParam, lParam);
    }
    
    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    {
        switch (fdwReason)
        {
            case DLL_PROCESS_ATTACH:
                // attach to process
                // return FALSE to fail DLL load
                break;
    
            case DLL_PROCESS_DETACH:
                // detach from process
                break;
    
            case DLL_THREAD_ATTACH:
                // attach to thread
                break;
    
            case DLL_THREAD_DETACH:
                // detach from thread
                break;
        }
        return TRUE; // succesful
    }
    In the programs main, I try to access the mouseX from the DLL, however it always displays 0, even though there is no longer a linker error. Can anyone explain why it remains 0? Thanks in advance!
    My Favorite Programming Line:
    Code:
    #define true ((rand() % 2) ? true : false)

  2. #2
    Registered User
    Join Date
    Jan 2008
    Posts
    290
    90&#37; of what you posted is irrelevant for solving your problem. What we need to know is:

    1) Are you properly registering the mouse hook?
    2) Is the mouse hook actually being called?
    3) Are the mouseX and mouseY being updated properly?

    [disregard]
    If all of the above is true then your mouse hook is working properly. Now your problem is, how do you get those mouse coordinates back to your main process? I'm assuming this is a global mouse hook, so your DLL is being loaded into every running process that receives mouse events.

    I believe (and I very well may be mistaken here), that every time your DLL loads into a separate process, it receives its own copy of mouseX and mouseY local to that process. So it wouldn't make any sense for you to declare them as extern and try and access them from your main process (it will only be accessing its local copies). Instead you need a way to record the mouse coordinates in each of the processes that your hook is installed, and then send them back to your main process.

    I would suggest sending your main window a message using SendMessage(). Its a fairly simple way to perform interprocess communication. When your DLL loads, get a handle to your main window using the appropriate Win32 API calls. When a mouse event gets hooked, use SendMessage to send the coordinates using that handle and a custom defined WM_USER message.

    Again, off the top of my head, I don't remember exactly how the memory allocation works when your DLL is loaded into multiple processes. You'd have to look it up.
    [/disregard]

    [edit]
    I apologize. I read up on the WH_MOUSE_LL hook and it doesn't inject into other processes and actually intercepts the mouse message before it is put into a thread message queue.

    Also, the LPARAM to a LowLevelMouseProc should be interpreted as a MSLLHOOKSTRUCT, not a MOUSEHOOKSTRUCT.
    [/edit]
    Last edited by arpsmack; 08-16-2008 at 11:11 AM.

  3. #3
    Registered User
    Join Date
    Apr 2007
    Posts
    102
    Quote Originally Posted by arpsmack View Post
    90% of what you posted is irrelevant for solving your problem. What we need to know is:

    1) Are you properly registering the mouse hook?
    2) Is the mouse hook actually being called?
    3) Are the mouseX and mouseY being updated properly?

    [disregard]
    If all of the above is true then your mouse hook is working properly. Now your problem is, how do you get those mouse coordinates back to your main process? I'm assuming this is a global mouse hook, so your DLL is being loaded into every running process that receives mouse events.

    I believe (and I very well may be mistaken here), that every time your DLL loads into a separate process, it receives its own copy of mouseX and mouseY local to that process. So it wouldn't make any sense for you to declare them as extern and try and access them from your main process (it will only be accessing its local copies). Instead you need a way to record the mouse coordinates in each of the processes that your hook is installed, and then send them back to your main process.

    I would suggest sending your main window a message using SendMessage(). Its a fairly simple way to perform interprocess communication. When your DLL loads, get a handle to your main window using the appropriate Win32 API calls. When a mouse event gets hooked, use SendMessage to send the coordinates using that handle and a custom defined WM_USER message.

    Again, off the top of my head, I don't remember exactly how the memory allocation works when your DLL is loaded into multiple processes. You'd have to look it up.
    [/disregard]

    [edit]
    I apologize. I read up on the WH_MOUSE_LL hook and it doesn't inject into other processes and actually intercepts the mouse message before it is put into a thread message queue.

    Also, the LPARAM to a LowLevelMouseProc should be interpreted as a MSLLHOOKSTRUCT, not a MOUSEHOOKSTRUCT.
    [/edit]
    Sorry about the irrelevancy, I like to include everything that might have something to do with it so I don't miss putting something in and you all can see exactly what I'm doing. The mouse hook is properly registered, and is being called, and it updates the mouseX and mouseY. I have figured that out through some simple debugging. I think you may be on to something with the global DLL containing separate memory addresses. What I have seen, but wasn't sure that I needed was a way to put the data into a shared section in the DLL that all programs can access. I'll try that and see how it goes, thanks for the reply.
    My Favorite Programming Line:
    Code:
    #define true ((rand() % 2) ? true : false)

  4. #4
    Registered User
    Join Date
    Jan 2008
    Posts
    290
    Whoa, take everything I said about the global DLL problem with a grain of salt. I was mistaken. The DLL will should only be loaded into your main process, and all callbacks should be executed in the context of your process (from what I gather in the documentation). The low level mouse hooks intercept mouse events at the system level before they are posted to a thread queue. These events haven't been sent anywhere yet, so your DLL should never be loaded into another process.

    If I recall correctly from when I used to write video game hacks, there are global hooks that will cause your DLL to be loaded into other processes, but that isn't the case here.

    You shouldn't have any problems declaring the variables extern and accessing them from your main process. However, you could also try providing exported functions to retrieve the values as well.

    If I find some time this weekend, maybe I'll try to extract parts of your code and run some of my own tests.

  5. #5
    Registered User
    Join Date
    Apr 2007
    Posts
    102
    Quote Originally Posted by arpsmack View Post
    Whoa, take everything I said about the global DLL problem with a grain of salt. I was mistaken. The DLL will should only be loaded into your main process, and all callbacks should be executed in the context of your process (from what I gather in the documentation). The low level mouse hooks intercept mouse events at the system level before they are posted to a thread queue. These events haven't been sent anywhere yet, so your DLL should never be loaded into another process.

    If I recall correctly from when I used to write video game hacks, there are global hooks that will cause your DLL to be loaded into other processes, but that isn't the case here.

    You shouldn't have any problems declaring the variables extern and accessing them from your main process. However, you could also try providing exported functions to retrieve the values as well.

    If I find some time this weekend, maybe I'll try to extract parts of your code and run some of my own tests.
    Alright, I'll try to mess around with it, thanks for all your help. What your saying makes sense though, once again thanks for the help I should be able to get it working .
    My Favorite Programming Line:
    Code:
    #define true ((rand() % 2) ? true : false)

  6. #6
    Registered User
    Join Date
    Apr 2007
    Posts
    102
    Hey thanks for everyone's help! I solved the problem by adding some accessor functions in the DLL. Looks a bit complicated but I use some function pointers to make it look nicer in the main file. Anyway, here's the code that solved it for me.

    dll main.h

    Code:
    #ifndef __MAIN_H__
    #define __MAIN_H__
    
    #include <windows.h>
    #include <iostream>
    
    /*  To use this exported function of dll, include this header
     *  in your project.
     */
    
    #ifdef BUILD_DLL
        #define DLL_EXPORT __declspec(dllexport)
    #else
        #define DLL_EXPORT __declspec(dllimport)
    #endif
    
    
    #ifdef __cplusplus
    extern "C"
    {
    #endif
    
    int mouseX;
    int mouseY;
    
    DLL_EXPORT LRESULT CALLBACK MProc(int nCode, WPARAM wParam, LPARAM lParam);
    DLL_EXPORT int getMouseX();
    DLL_EXPORT int getMouseY();
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif // __MAIN_H__
    main.cpp of dll

    Code:
    #include "main.h"
    
    // a sample exported function
    DLL_EXPORT LRESULT CALLBACK MProc(int nCode, WPARAM wParam, LPARAM lParam)
    {
        if(nCode < 0)
            return CallNextHookEx(NULL, nCode, wParam, lParam);
    
        //Check wParam here
        if (wParam == WM_LBUTTONUP)
        {
            MSLLHOOKSTRUCT * hHook = (MSLLHOOKSTRUCT*)lParam;
            mouseX = hHook->pt.x;
            mouseY = hHook->pt.y;
    
        }
    
        return CallNextHookEx(NULL, nCode, wParam, lParam);
    }
    
    DLL_EXPORT int getMouseX()
    {   return mouseX;  }
    
    DLL_EXPORT int getMouseY()
    {   return mouseY;  }
    
    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    {
        switch (fdwReason)
        {
            case DLL_PROCESS_ATTACH:
                // attach to process
                // return FALSE to fail DLL load
                break;
    
            case DLL_PROCESS_DETACH:
                // detach from process
                break;
    
            case DLL_THREAD_ATTACH:
                // attach to thread
                break;
    
            case DLL_THREAD_DETACH:
                // detach from thread
                break;
        }
        return TRUE; // succesful
    }
    Then in order to receive the mouseX and mouseY, I just use the GetProcAddress() function and then call the address function returned. Anyways, thanks again all!
    My Favorite Programming Line:
    Code:
    #define true ((rand() % 2) ? true : false)

  7. #7
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    You shouldn't put definitions (declarations that allocate space) in header files. Now that you have accessors, just move the definitions for mouseX and mouseY into "main.cpp of dll".

    It is possible to export global variables from a DLL: http://msdn.microsoft.com/en-us/libr...y6(VS.80).aspx
    You would put "extern DLL_EXPORT int mouseX;" (declaration) in the header, and "DLL_EXPORT int mouseX;" (definition) in main.cpp of the dll.

    Also, your posted message loop is a bit inefficient - "spinning" as fast as the OS and CPU will run it - even if there's no work that needs to be done. If you're going to poll for data, consider placing a "Sleep(0)" at the bottom of the loop to relinquish the remainder of your time slice so the OS can do other work. You should see your CPU utilization go from the 90's to 0 when things are idle. Another option is not to poll for data, but have the data put in the message queue to be pulled off with a normal GetMessage() loop.

    gg

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Note that Sleep(0) is not going to reduce the CPU usage significantly, it will let other applications "in", but it will still use up 100% of one CPU. Since mouse movements are pretty much user speed anyways [so tens of millisecond timing should be sufficient], you can probably set a timer or use for example MsgWaitForMultipleObjectsEx. You may have to create a dummy handle to wait for, but you have a timeout variable on that function which allows you to define how long to wait for an event - since all you need the "if nothing happened" for is to output the mouse coordinates, I expect that setting a timeout of 100ms would be fine.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> You should see your CPU utilization go from the 90's to 0 when things are idle.
    That's incorrect as matsp explained. You would still be "spinning" - in this case, relinquishing your time slice as fast as the OS/CPU will run it. Which would be an improvement, but no "hard spinning" at all would be best.
    Interval polling could be achieved by simply call Sleep(N) at the bottom of the loop (where N > 0).

    gg

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Codeplug View Post
    Interval polling could be achieved by simply call Sleep(N) at the bottom of the loop (where N > 0).
    But that would also slow down when there is a lot of data to be processed [the mouse is moving furiously] - which is perhaps not a great idea.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #11
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Right - I forgot that a message loop is necessary for the mouse-hook callback to even occur. So Sleep is just a bad idea altogether - which is usually the case

    gg

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Codeplug View Post
    Right - I forgot that a message loop is necessary for the mouse-hook callback to even occur. So Sleep is just a bad idea altogether - which is usually the case

    gg
    Yes, I think that's a good summary of "Sleep" - most of the time it's used, it really ought to be "Wait for something, and if it takes longer than X, return anyways". Or use multiple threads, but that's another kettle of fish.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. xor linked list
    By adramalech in forum C Programming
    Replies: 23
    Last Post: 10-14-2008, 10:13 AM
  2. Replies: 3
    Last Post: 04-18-2008, 10:06 AM
  3. question about a working linked list
    By cold_dog in forum C++ Programming
    Replies: 23
    Last Post: 09-13-2006, 01:00 AM
  4. Binary Tree, couple questions
    By scoobasean in forum C Programming
    Replies: 3
    Last Post: 03-12-2005, 09:09 PM
  5. HUGE fps jump
    By DavidP in forum Game Programming
    Replies: 23
    Last Post: 07-01-2004, 10:36 AM