C++ DLL For VB .NET (Win API Hooking)

For a better explanation of what I'm trying to do, go here: http://www.experts-exchange.com/Programming/Programming_Languages/Dot_Net/VB_DOT_NET/Q_21815892.html -- Anyone who answers this question can also have the points from that question.

Essentially, I need a way to hook WM_USER messages sent to a specific control in an external application.  I've been writing the application in VB .NET but can only find the control's window handle--apparently VB isn't capable of installing this kind of hook.  Unfortunately, I've not written a line of C or C++ code in my life, so I'm a little stuck.

Does anyone know of a free pre-written library that would let me see the lParam of any WM_USER (+ 1004) event sent to a window I have the handle for?  If not, can anyone post a bit of code that could accomplish this?

Thanks,

Chris
LVL 7
inxilAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jkrCommented:
If you have the handle, that's not a big deal. Just use

#define __DLL

#ifndef _DEBUG
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>

#ifdef _DEBUG
#include <crtdbg.h>
#endif

#ifdef __DLL
#define __DYNLINK __declspec( dllexport)
#else
#define __DYNLINK __declspec( dllimport)
#endif

#pragma data_seg( ".shared")
HHOOK   g_hhk   =   NULL;
HWND    g_hWnd  =   NULL;
UINT    g_unMsg =   0;
#pragma data_seg()
#pragma comment(linker,"/section:.shared,rws")

HINSTANCE   g_hThisDll;


LRESULT CALLBACK    HookProc    (   int     nCode,  
                                    WPARAM  wParam,
                                    LPARAM  lParam  
                                );

int APIENTRY    DllMain (   HINSTANCE   hInstance,
                            DWORD       dwReason,
                            LPVOID      lpReserved
                        )
{
    if  (   dwReason    ==  DLL_PROCESS_ATTACH)
        {
            g_hThisDll  =   hInstance;

            return  (   DisableThreadLibraryCalls   (   g_hThisDll));
        }

    return( TRUE);
}

LRESULT CALLBACK HookProc   (   int     nCode,  // hook code
                                WPARAM  wParam, // removal flag
                                LPARAM  lParam  // address of structure with message
                            )
{
    PMSG    pmsg    =   ( PMSG) lParam;

    if  (   0   >   nCode   ||  PM_NOREMOVE ==  wParam)
        {
            return  (   CallNextHookEx  (   g_hhk,
                                            nCode,
                                            wParam,
                                            lParam
                                        )
                    );
        }

    if  (   g_hWnd  ==  pmsg->hWnd && g_unMsg == pmsg->message)
        {
            /* this one is for us */
            char buf[255];
            wsprintf(buf,"Message: %d lParam: %d\n", pmsg->message, pmsg->lParam);
            OutputDebugString   (   buf);

        }

    return  (   CallNextHookEx  (   g_hhk,
                                    nCode,
                                    wParam,
                                    lParam
                                )
            );
}

extern "C"
LONG __DYNLINK MsgSpyInit   ( HWND  hWnd, UINT unMsg)
{

    if  (   g_hhk)  return  (   ERROR_ALREADY_EXISTS);

    g_hhk   =   SetWindowsHookEx    (   WH_GETMESSAGE,
                                        ( HOOKPROC) HookProc,
                                        g_hThisDll,
                                        0
                                    );

    g_hWnd = hWnd;
    g_unMsg = unMsg;

    return  (   0);
}

extern "C"
LONG __DYNLINK MsgSpyTerm   ( void)
{
    UnhookWindowsHookEx (   g_hhk);

    g_hhk   =   NULL;

    return  (   0);
}

and call 'MsgSpyInit()' supplying the window handle and the message you want to monitor.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
inxilAuthor Commented:
Excuse my complete ignorance--I'm not really an application programmer (mostly a PHP Web programmer) and I've never used C++ before.

So I downloaded the free Visual C++ Express Edition 2005, but I don't really know how to use your code.  When I create a new project it offers me the following options: Class Library, CLR Console Application, CLR Empty Project, Makefile Project, Win32 Console Application, Windows Forms Application, and emptyproj.

I've played around with some of 'em, but I can't get it to even pretend to work...  I know I really aught to go out an do a C++ tutorial, but I'm really just trying to create this one library for my VB app and then I'll be done with it for a while--a little bit more of a walkthrough would be much appreciated!

Thanks,

Chris
0
jkrCommented:
That should be a Win32 DLL. You can compile that on the command line like

cl.exe msgspy.cpp /link /dll
0
Cloud Class® Course: Amazon Web Services - Basic

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

inxilAuthor Commented:
fatal error C1083: Cannot open include file: 'windows.h': No such file or directory
0
jkrCommented:
Ah ;o)

You need to execute the 'vcvars32.bat' file from your Visual Studio installation forlder, so it will set the INCLUDE and LIB environment variables correctly before compiling. That should be done in the same console window.
0
inxilAuthor Commented:
C:\Program Files\Microsoft Visual Studio 8\VC\bin>vcvars32.bat

C:\Program Files\Microsoft Visual Studio 8\VC\bin>"C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\vsvars32.bat"
Setting environment for using Microsoft Visual Studio 2005 x86 tools.

C:\Program Files\Microsoft Visual Studio 8\VC\bin>cl.exe "C:\Documents and Settings\MyUserName\My Documents\Visual Studio 2005\Projects\MsgSpy\MsgSpy.cpp" /link /dll
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

MsgSpy.cpp
C:\Documents and Settings\MyUserName\My Documents\Visual Studio 2005\Projects\MsgSpy\MsgSpy.cpp(6) : fatal error C1083: Cannot open include file: 'windows.h': No such file or directory
0
inxilAuthor Commented:
Do I need the Windows Server 2003 R2 Platform SDK?
0
jkrCommented:
No, you should be fine with what you have.

After

C:\Program Files\Microsoft Visual Studio 8\VC\bin>"C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\vsvars32.bat"
Setting environment for using Microsoft Visual Studio 2005 x86 tools.

what does

echo %INCLUDE%

give?

BTW, isn't there a "Win32 DLL Project" option available also in the IDE?
0
inxilAuthor Commented:
No Win32 DLL project option available... and a search of my C drive doesn't turn up a windows.h anywhere...
0
inxilAuthor Commented:
C:\Program Files\Microsoft Visual Studio 8\VC\bin>echo %INCLUDE%
C:\Program Files\Microsoft Visual Studio 8\VC\INCLUDE;C:\Program Files\Microsoft Visual Studio 8\VC\INCLUDE;C:\Program Files\Microsoft Visual Studio 8\VC\INCLUDE;C:\Program Files\Microsoft Visual Studio 8\VC\INCLUDE;C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\include\
0
jkrCommented:
>>and a search of my C drive doesn't turn up a windows.h anywhere...

Now that's bad, since it should 'live' in one of the directories. In that case, you'll have to download teh Platform SDK. This is kinda disappointing, since I would assume that one to ship with the 'Express' versions also.
0
inxilAuthor Commented:
MsgSpy.cpp(48) : error C2039: 'hWnd' : is not a member of 'tagMSG'
        C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\Include\winuser.h(1571) : see declaration of 'tagMSG'
0
jkrCommented:
Ooops, simple typo - that's all lowercase, make that line read

    if  (   g_hWnd  ==  pmsg->hwnd && g_unMsg == pmsg->message)
0
inxilAuthor Commented:
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

MsgSpy.cpp
Microsoft (R) Incremental Linker Version 8.00.50727.42
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:MsgSpy.exe
/dll
MsgSpy.obj
   Creating library MsgSpy.lib and object MsgSpy.exp
MsgSpy.obj : error LNK2019: unresolved external symbol __imp__wsprintfA referenced in function "long __stdcall HookProc(int,unsigned int,long)" (?HookProc@@YGJHIJ@Z)
MsgSpy.obj : error LNK2019: unresolved external symbol __imp__CallNextHookEx@16 referenced in function "long __stdcall HookProc(int,unsigned int,long)" (?HookProc@@YGJHIJ@Z)
MsgSpy.obj : error LNK2019: unresolved external symbol __imp__SetWindowsHookExA@16 referenced in function _MsgSpyInit
MsgSpy.obj : error LNK2019: unresolved external symbol __imp__UnhookWindowsHookEx@4 referenced in function _MsgSpyTerm
MsgSpy.exe : fatal error LNK1120: 4 unresolved externals
0
jkrCommented:
Ah, we're getting somewhere ;o)

Just add

#pragma comment(lib,"user32.lib")

to the code.
0
inxilAuthor Commented:
Okay, so now it created an executable but I'm pretty sure it should have created a library...

MsgSpy.exe
MsgSpy.exp
MsgSpy.lib
MsgSpy.obj
0
jkrCommented:
Huh? That should not even work, there is no entry point for an executable. What was the command line you were using for the build?
0
inxilAuthor Commented:
cl.exe MsgSpy.cpp /link /dll
0
jkrCommented:
I was afraid you would write that ;o)

OK, what do you get when you rename that .exe file to DLL and open if with the DependencyWalker (www.dependencywalker.com)?
0
inxilAuthor Commented:
It loads a big tree of libraries, which I'm guessing is good.  It does say that it can't load MSJAVA.DLL, but I'm also guessing that that's Okay.
0
jkrCommented:
OK, so you have your DLL now. As long as you can see 'MsgSpyInit()' being exported, that's OK.
0
inxilAuthor Commented:
Thanks jkr!  I'm going to need a little more help but I've started it in a new thread because it's pretty much a new question.  If you're up for it, please take a look at:

http://www.experts-exchange.com/Programming/Programming_Languages/Cplusplus/Q_21816860.html

Also, please go to:
http://www.experts-exchange.com/Programming/Programming_Languages/Dot_Net/VB_DOT_NET/Q_21815892.html

And post a link to this thread so I can accept your answer there as well.

Cheers,

Chris
0
jkrCommented:
You're most welcome ;o)

>>And post a link to this thread so I can accept your answer there as well.

I am not absolutely sure whether that would comply with the EE rules, but I tend to say 'no'. Nevertheless, the hint to use C/C++ was helpful, so you could (if you want to) have the points decreased (500 for the pointer and the work done here compared makes that seem a little overpriced) and accept that as an answer.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Editors IDEs

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.