Help using postmessage and WM_USER

HI all,

I've hooked into an external program and am intercepting and processing certain messages. When I detect a WM_WINPOSCHANGED message i want to post a WM_USER message to the bottom of the queue.

i do this using the callback method;

LRESULT CALLBACK AppEventsHook (int nCode, WPARAM wParam, LPARAM lParam)
{
      if(nCode == HC_ACTION)
      {
            LPCWPSTRUCT pCwp = (LPCWPSTRUCT) lParam;            
            switch(pCwp->message)
            { ....

and i post the message as so

::PostThreadMessage(pCwp->hwnd,WM_USER+1,12345,NULL);

i have also tried

::PostThreadMessage(NULL,WM_USER+1,12345,NULL);

at the moment all i try and do is catch the WM_USER message (i catch the WM_WINPOSCHANGED just fine)  and output to a log file to prove that it is working, however it doesnt seems to be posting the WM_USER message properly.

case WM_USER+1:
{
      if(pCwp->wParam == 12345)
      {
            msg.Format("DETECTED MY MESSAGE");                        CLogFile::logmsg(msg);
      }
}

can anyone tell me what i'm doing wrong here?
flynnyAsked:
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x
 
jkrConnect With a Mentor Commented:
Well, see the docs on the type of hook you are using: http://msdn2.microsoft.com/en-us/library/ms644975.aspx ("CallWndProc"): "The system calls this function whenever the thread calls the SendMessage function."

You'd be better off with a "GetMsgProc" (IOW: WH_GETMESSAGE hook, see http://msdn2.microsoft.com/en-us/library/ms644981.aspx) for that purpose.
0
 
Deepu AbrahamR & D Engineering ManagerCommented:
Did you try PostMessage()?
0
 
flynnyAuthor Commented:
sorry. i apologise

i question PostThreadMessage should have been PostMessage (i was playiung around with different method before i posted.) i'll edit the question.

anyway, yes i did try this and it doesn't seem to be processing the message.
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
flynnyAuthor Commented:
also, could i be sending the PostMessage to the wrong HWND?
i assumed posting to pCwp->hwnd would be the right way??

is there anyway i can get hold of the window or thread the callback funtion belongs to?
0
 
flynnyAuthor Commented:
to note i have tried the following without any luck

::PostThreadMessage(::GetWindowThreadProcessId(pCwp->hwnd,NULL),WM_USER+1,12345,NULL);
0
 
jkrCommented:
If more than one process is involved here, 'WM_USER' messages will not be unique. You should rather use

UINT uMyMsg = RegisterWindowMessage("WM_MyUniquePrivateMessage");
0
 
flynnyAuthor Commented:
thanks for the reply jkr.

OK i tried that and it still doesnt seem to be working (i have to remove the WM_PRIVATE_MSG test outside the switch statement as it says its not a const? (error C2051: case expression not constant))

ok so i have

const static UINT WM_PRIVATE_MSG = RegisterWindowMessage("WM_PRIVATE_MSG");

LRESULT CALLBACK AppEventsHook (int nCode, WPARAM wParam, LPARAM lParam)
{
      try
      {
      if(nCode == HC_ACTION)
      {
            LPCWPSTRUCT pCwp = (LPCWPSTRUCT) lParam;

            if(pCwp->message == WM_PRIVATE_MSG)
            {
                  msg.Format("DETECTED WM_USER MESSAGE");
                  CLogFile::logmsg(msg);
            }

where i have tried

::PostMessage(pCwp->hwnd,WM_PRIVATE_MSG,NULL,NULL);
::PostMessage(NULL,WM_PRIVATE_MSG,NULL,NULL);

also if i call getlasterror it return 183 each time. (looking at the docs an error is 0, so it looks like it thinks its posting ok)

any ideas?
0
 
jkrCommented:
You can't use that within a 'switch' unfortunately, but anyway....

BTW, are you sure that you want to post that to the window you are hooking?
0
 
flynnyAuthor Commented:
yes i think so unless you have any other ideas.

As the window hasn't added all the components at this time i simply wanted to wait until it had. I can then perfrom my EmunChildProc to run through all its child windows and hopefully find the window witht he individual text.

My thoughts were (correct me if i'm wrong) that if i could detect the event and then post a message to the bottom of the queue by the time all the other had been processed it would have added all the components so i can perform my add on this user message.

the other option was WaitForInputIdle() but unfortunately this didnt work either. Plus i wasnt sure whether or not i could call this inside a callback proc.

thanks againfor the quick response.
0
 
flynnyAuthor Commented:
hi jkr just for reference, i've tried the WaitForInputIdle and its erroring (returns -1) getlasterror code is 6.
0
 
jkrCommented:
What about using a minimalistic windows app to test the messaging, e.g.


#include <windows.h>
 
#pragma comment(lib,"user32.lib")
 
static char g_szClassName[] = "MyWindowClass";
static HINSTANCE g_hInst = NULL;
 
const static UINT WM_PRIVATE_MSG = RegisterWindowMessage("WM_PRIVATE_MSG");
 
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
 
  if (Message == WM_PRIVATE_MSG) MessageBox(0, "Received message!", "Got it!", MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
  switch(Message)
  {
     case WM_CLOSE:
        DestroyWindow(hwnd);
     break;
     case WM_DESTROY:
        PostQuitMessage(0);
     break;
     default:
        return DefWindowProc(hwnd, Message, wParam, lParam);
  }
  return 0;
}
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  LPSTR lpCmdLine, int nCmdShow)
{
  WNDCLASSEX WndClass;
  HWND hwnd;
  MSG Msg;
 
  g_hInst = hInstance;
 
  WndClass.cbSize        = sizeof(WNDCLASSEX);
  WndClass.style         = NULL;
  WndClass.lpfnWndProc   = WndProc;
  WndClass.cbClsExtra    = 0;
  WndClass.cbWndExtra    = 0;
  WndClass.hInstance     = g_hInst;
  WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
  WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  WndClass.lpszMenuName  = NULL;
  WndClass.lpszClassName = g_szClassName;
  WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
 
  if(!RegisterClassEx(&WndClass))
  {
     MessageBox(0, "Window Registration Failed!", "Error!",
        MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
     return 0;
  }
 
  hwnd = CreateWindowEx(
     WS_EX_CLIENTEDGE,
     g_szClassName,
     "The title of my window",
     WS_OVERLAPPEDWINDOW & ~WS_BORDER,
     CW_USEDEFAULT, CW_USEDEFAULT, 320, 240,
     NULL, NULL, g_hInst, NULL);
 
  if(hwnd == NULL)
  {
     MessageBox(0, "Window Creation Failed!", "Error!",
        MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
     return 0;
  }
 
  ShowWindow(hwnd, nCmdShow);
  UpdateWindow(hwnd);
 
  while(GetMessage(&Msg, NULL, 0, 0))
  {
     TranslateMessage(&Msg);
     DispatchMessage(&Msg);
  }
  return Msg.wParam;
}
 
// in the hook:
 
HWND hwnd = FindWindow("MyWindowClass","TestTarget");
::PostMessage(hwnd,WM_PRIVATE_MSG,NULL,NULL);

Open in new window

0
 
flynnyAuthor Commented:
Hi jkr, i tried that. Just so i understand how the code was working. the Translate and Dispatch msgs should put the message back into my callback msg queue should it not?. (sorry if i'm being dumb)

i'm not picking up anything in the log file though still.
0
 
flynnyAuthor Commented:
sorry ignore that last post, i'm with it now. ;)

but no its not picking up the message being posted. so it look like my callback is the problem.
0
 
jkrCommented:
Well, that's a biolerplate Windows app, it is basically the message pump for a small window. And it logs nothing, it only should display a message box when the custom message is receivedvia
HWND hwnd = FindWindow("MyWindowClass","TestTarget");
::PostMessage(hwnd,WM_PRIVATE_MSG,NULL,NULL);

Open in new window

0
 
flynnyAuthor Commented:
hi jkr, the app is recieving the message now ok.

(the problem was i was sending the classname in FindWindow("MyClassName","Target");)

setting to

FindWindow(NULL, "This is the title");

worked and i recieve the message box. So could posting the message to the wrong window?

basically all i do in the WM_WINPOSCHANGED method i the following

HWND foundWND = FindCurrentWindow(hookWindow);

if(foundWND>0)
{
HWND hwndzz = FindWindow(NULL,"The title of my window");
::PostMessage(hwndzz,WM_PRIVATE_MSG,NULL,NULL);
//::PostMessage(foundWND,WM_PRIVATE_MSG,NULL,NULL);
//have also tried
//::PostMessage(NULL,WM_PRIVATE_MSG,NULL,NULL);
//::PostMessage(pCwp->hwnd,WM_PRIVATE_MSG,NULL,NULL);

all with no luck? could it be the way i create the hook?
0
 
flynnyAuthor Commented:
hi its me thanks for the link and the explanation. Ok, so from looking at the documentation and to clarify.

so looking at the 'GetMsgProc', this will be called every time the get message is processed. So i assume this will be called everytime a message is popped off the stack? This should handle the same message too should it not? as i've changed my creation to

SetWindowsHookEx(/*WH_CALLWNDPROC*/WH_GETMESSAGE, (HOOKPROC)AppEventsHook, hinstDLL, GetWindowThreadProcessId(GetAppWnd(), NULL) );

where
hinstDLL is
static HINSTANCE hinstDLL = LoadLibrary((LPCTSTR) ".\\LaunchDLL.dll");

and getAppWnd() simply returns the handle from the FindWindow call.

also, might it be worth changing my callback proc to

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
from
LRESULT CALLBACK WndProc(UINT Message, WPARAM wParam, LPARAM lParam)
as per your example?



0
 
flynnyAuthor Commented:
hi, just to add i tried making the switch of the callback functions and it made no difference, i'm still getting the same output.

thanks again,
Matt.
0
 
jkrCommented:
What code do you  have inside your hook now?
0
 
flynnyAuthor Commented:
at the moment, i have the following.

i creeate the hook as follows.

appHook = SetWindowsHookEx(/*WH_CALLWNDPROC*/ WH_GETMESSAGE, (HOOKPROC)AppEventsHook, hinstDLL, GetWindowThreadProcessId(GetAppWnd(), NULL));

where GetAppWnd() siply returns the application HWND. (found using the main window title.)

My Callback is then as follows ( i have also tried using a similar overload as you provided in your example but to no avail).

const static UINT WM_PRIVATE_MSG = RegisterWindowMessage("WM_PRIVATE_MSG");

LRESULT CALLBACK AppEventsHook (int nCode, WPARAM wParam, LPARAM lParam)
{
      try
      {
      if(nCode == HC_ACTION)
      {
            LPCWPSTRUCT pCwp = (LPCWPSTRUCT) lParam;

            if(pCwp->message == WM_PRIVATE_MSG)
            {
                  
                        MessageBox(0, "Received message!", "Got it!", MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
                  msg.Format("DETECTED WM_USER MESSAGE");
                  CLogFile::logmsg(msg);
            }
            
            switch(pCwp->message)
            {
            case WM_WINDOWPOSCHANGED:
            {

foundWND = FindCurrentWindow(hookWindow);
//hook window is name of the window in question i want to add the buttons to (i.e. waituntil it has finished creating and populating all its child windows and then test to see if i add the button.

//find current window simply checks to se where or not the windwo has already been hooked into (so buttons are not added every time a WM_WINPOSCHANGED event on that window is called.

if(foundWND>0)
{
::PostMessage(pCwp->hwnd,WM_PRIVATE_MSG,NULL,NULL);
//ahve also tried
::PostMessage(foundWND,WM_PRIVATE_MSG,NULL,NULL);
//and
::PostThreadMessage(GetCurrentProcessId(),WM_PRIVATE_MSG,NULL,NULL);

thanks again for your help jkr, its much appreciated.

0
 
jkrCommented:
Um, in case of a WH_GETMESSAGE hook, that should be
MSG* pMsg = (PMSG)lParam;
 
      if(nCode == HC_ACTION)
      {
 
            if(pMsg->message == WM_PRIVATE_MSG)
            {
                  
                        MessageBox(0, "Received message!", "Got it!", MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
                  msg.Format("DETECTED WM_USER MESSAGE");
                  CLogFile::logmsg(msg);
            }
            
            switch(pMsg->message)
            {
            case WM_WINDOWPOSCHANGED:
            {
// etc.

Open in new window

0
 
flynnyAuthor Commented:
Hi jkr,

thanks for that, a step forward, if i do this kind of message then it doesn't seem to be picking up the WM_WINPOSCHANGED message (i assume it should detect this?).

However, it does pick up other messages, which i tested the code below.

Looking through these messages it was posting numerous messages including a WM_USER. so to test it i simply added a select case for the WM_USER message and posted a WM_PRIVATE_MSG, which worked!

is there any reason that the callback wouldnt pick up the WM_WINDOWPOSCHANGED?




MSG* pMsg = (PMSG)lParam;
 
      if(nCode == HC_ACTION)
      {
 
            if(pMsg->message == WM_PRIVATE_MSG)
            {
                  
                        MessageBox(0, "Received message!", "Got it!", MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
                  msg.Format("DETECTED WM_USER MESSAGE");
                  CLogFile::logmsg(msg);
            }
            
            switch(pMsg->message)
            {
            case WM_WINDOWPOSCHANGED:
            {
break;
}
default:
{
msg.Format("OTHERMSG:%x:",pCwp->message);
CLogFile::logmsg(msg);
}

Open in new window

0
 
jkrCommented:
Hm, the above is fragmented and still uses 'pCwp' in the 'default:' branch. Do you get 'WM_WINDOWPOSCHANGING'? Also, try using

      if(nCode > 0) // *not* '== HC_ACTION'

Open in new window

0
 
flynnyAuthor Commented:
Hi jkr,

i've got the program detecting the message now. i create a WH_CALLWNDPROC and when the window witht he relevant title is detected i hook into it with a WH_GETMESSAGE proc, posting my message onto the queue.

I then detect and check the windows, however i can now at least see all the windows as they have all been added however the text always returns null from them. I assume i'm still not waiting long enough?

So my idea was if the idenftifer field didnt ext keep reposting the message until it does. However when i repost in the WH_GETMESSAGE method its doesn't seem to be posting the message in a similar way to before.
0
 
flynnyAuthor Commented:
sorry i knocked enter an posted without proofing that post.

so

if(!found)
::PostMessage(pCwp->hwnd,0,NULL,NULL);

in the WH_GETMESSAGE proc. As this is catching the messages for the found window i assume pCwp->hwnd woul be correct
SetWindowHook(SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)AppGetEventsHook, hinstDLL, GetWindowThreadProcessId(foundWND, NULL)));::WaitForInputIdle(GetCurrentProcess(),INFINITE);
::PostMessage(foundWND,WM_PRIVATE_MSG,NULL,NULL);
						

Open in new window

0
 
jkrCommented:
You won't receive a 'LPCWPSTRUCT' any longer, thus the pointer will not to valid data. That won't work.
0
 
flynnyAuthor Commented:
sorry i missed the nCode>0 message, must have been typing whilst you posted!. If i replace the ==NC_ACTION to >0 then it doesn't even pick up my WM_PRIVATE_MSG

Also apologies about pasting the code i tried to format it in the code snippet window to ake it more readable for you and missed a }.

i no longer create the 'LPCWPSTRUCT' i create a 'MSG*' (sorry kept the name of the variable just changed the structure in the end).

finally, regards the WM_WINDOWPOSCHANGING its doesnt seem to be picking this up either.

At the moment i'm testing this on windows 2003 server? could this be a problem? at the moment my xp machine is down. I'll try and get this up and running again and see if running on this os do you think this could make a difference?


 
0
 
flynnyAuthor Commented:
hi jkr,

i've finally managed to get it to work with a little bit of fudging. does this method sound ok to you (it works but i would just like to get your opinion on it)

Ok, I hook into my main program using WH_CALLWNDPROC and monitor its messages.

If i detect a WM_WINDOWPOSCHANGED i check to see if it is the window i want to hook into.

if it potentially is (ie. the title matches and the hwnd (which i store) has not already been hooked into), i add a WH_GETMESSAGE hook to this child window an dpost my private message to it. I also set a bool in global memory postedMessage to true, to prevent any further posts being sent to the window.

i pick up the private message and i try and find the identrifier if not i close my hook (unhookwindowshookex) , and set the bool to false.

as further WM_WINDOWPOSCHANGED messages are caught it will repost the WM_PRIVATE _MSG and there is such a call after all the windows have been populated, success!

can you see any pitfalls with this approach as it isn't ideal.
0
 
jkrCommented:
Sounds OK if it works for you, but it is hard to detect any pitfalls without seein gthe code. Yet  personally would have preferred a WH_GETMESSAGE, but...
0
 
flynnyAuthor Commented:
I agree, the problem i seem to have is that it doesn't let a postmessage be made from inside the proc method if it is posted to itself?? if i post to the other window the message (or test program) the message goes across ok.

anyway i'll keep it at that for now it seems to be running ok and held up with a few stress tests.

Thanks for all you help jkr, you've been brilliant.
0
 
flynnyAuthor Commented:
great advice, well explained and directed me quickly towards a solution thanks.
0
All Courses

From novice to tech pro — start learning today.