What happened to the Messenger Plus! forums on msghelp.net?
Shoutbox » MsgHelp Archive » Messenger Plus! for Live Messenger » Scripting » WM_NOTIFY Help - (Noobs stay away! haha)

WM_NOTIFY Help - (Noobs stay away! haha)
Author: Message:
matty
Scripting Guru
*****


Posts: 8336
Reputation: 109
39 / Male / Flag
Joined: Dec 2002
Status: Away
O.P. WM_NOTIFY Help - (Noobs stay away! haha)
Well I have been working on a little project here and it makes use of the Tree View Control. Now since there isn't any built in support for it you have to subclass and receive messages.

Firstly I was using WM_PARENTNOTIFY and the returned value of wParam was WM_LBUTTONDOWN. Now what I need is to be able to use a double click not just a single click. So I did some research and came across website: http://www.codeproject.com/treectrl/treeview.asp.

Now a specific section talks about catching WM_NOTIFY and using the NMHDR structure to get which command :
quote:
NM_CLICK   ; user has clicked the left mouse button within the control
NM_DBLCLK  ; user has Double clicked the left mouse button within the control
NM_RCLICK  ; user has clicked the right mouse button within the control
NM_RDBLCLK ; user has Double clicked the left mouse button within the control

Now this is all fine and dandy however I can understand that I can use SendMessageW with WM_NOTIFY and the defined structure will be filled with the information I need however... This message is supposed to be returned in the OnWindowIdEvent_MessageNotification function. So my dilemma is the website example says that lParam is the NMHDR structure however there would be no way to access the members of the structure.

Any ideas?

As well here is the current function in my script.

code:
function On_editorEvent_MessageNotification(pPlusWnd,     /*        Window Object                */
                                            nMessage,     /*        Window Message Received      */
                                            wParam,       /*        wParam field message         */
                                            lParam)       /*        lParam field message         */
                                            {
    switch (nMessage){
        case WM_PARENTNOTIFY:
            _sent_notify = true;
            Interop.Call('user32', 'SendMessageW', _window.Handle,
                                                   WM_NOTIFY,
                                                   pPlusWnd.GetControlHandle('tvFiles'),
                                                   NMHDR.DataPtr);
            break;
        case WM_NOTIFY:
            _get_item(pPlusWnd);
            if (_sent_notify == true){
                Interop.Call('kernel32', 'RtlMoveMemory', NMHDR, lParam, 12);
                Debug.Trace(NMHDR.ReadDWORD(0));
                _sent_notify = false;
            }
            break;
    }
}

This post was edited on 03-08-2007 at 10:48 PM by matty.
03-08-2007 10:24 PM
Profile E-Mail PM Find Quote Report
effection
Full Member
***

Destroy The Runner

Posts: 135
Reputation: 4
– / Male / Flag
Joined: Sep 2006
RE: WM_NOTIFY Help - (Noobs stay away! haha)
code:
typedef struct tagNMHDR {
    HWND hwndFrom;
    UINT_PTR idFrom;
    UINT code;
} NMHDR;

now im not sure what size the HWND structure is (i think it is an integer) but UINT_PTR should be a 32bit value and so should UINT, so could you not just read off the DWORDs from the structure?
code:
var hwndFrom= nmhdr.ReadDWORD(0);
var idFrom = nmhdr.ReadDWORD(4);
var code = nmhdr.ReadDWORD(8 );

sorry if ive missed something

This post was edited on 03-08-2007 at 10:36 PM by effection.
03-08-2007 10:34 PM
Profile E-Mail PM Find Quote Report
deAd
Scripting Contest Winner
*****

Avatar

Posts: 1060
Reputation: 28
– / Male / Flag
Joined: Jan 2006
RE: WM_NOTIFY Help - (Noobs stay away! haha)
This is easy actually, I asked the same question a while back:

code:
var pNmhdr = Interop.Allocate(12); // if this is the wrong size sorry
Interop.Call('Kernel32.dll', 'RtlMoveMemory', pNmhdr.DataPtr, lParam, pNmhdr.Size);
// do stuff with pNmhdr

If you want to modify the structure, just call RtlMoveMemory again with the opposite parameters after you're all done modifying it:

code:
Interop.Call('Kernel32.dll', 'RtlMoveMemory', lParam, pNmhdr.DataPtr, pNmhdr.Size);

PS: How are you subclassing the control? Dll? or are you just processing the notifications it sends to the parent window?

This post was edited on 03-08-2007 at 10:48 PM by deAd.
03-08-2007 10:45 PM
Profile PM Find Quote Report
matty
Scripting Guru
*****


Posts: 8336
Reputation: 109
39 / Male / Flag
Joined: Dec 2002
Status: Away
O.P. RE: WM_NOTIFY Help - (Noobs stay away! haha)

quote:
Originally posted by deAd
code:
var pNmhdr = Interop.Allocate(12); // if this is the wrong size sorry
Interop.Call('Kernel32.dll', 'RtlMoveMemory', pNmhdr.DataPtr, lParam, pNmhdr.Size);
// do stuff with pNmhdr


The members of the structure are still 0... I don't see why this isn't working :S

quote:
Originally posted by deAd
PS: How are you subclassing the control? Dll? or are you just processing the notifications it sends to the parent window?
Processing messages to the parent.

This post was edited on 03-08-2007 at 10:54 PM by matty.
03-08-2007 10:50 PM
Profile E-Mail PM Find Quote Report
deAd
Scripting Contest Winner
*****

Avatar

Posts: 1060
Reputation: 28
– / Male / Flag
Joined: Jan 2006
RE: RE: WM_NOTIFY Help - (Noobs stay away! haha)
quote:
Originally posted by Matty
quote:
Originally posted by deAd
PS: How are you subclassing the control? Dll? or are you just processing the notifications it sends to the parent window?
Processing messages to the parent.

Ok, cool :) Did you get it to work?

This post was edited on 03-08-2007 at 10:53 PM by deAd.
03-08-2007 10:53 PM
Profile PM Find Quote Report
CookieRevised
Elite Member
*****

Avatar

Posts: 15519
Reputation: 173
– / Male / Flag
Joined: Jul 2003
Status: Away
RE: WM_NOTIFY Help - (Noobs stay away! haha)
Matty? How did you do it then in SendTo? Doesn't that script use the NMHDR structure or somthing very similar too....?

:D:p



quote:
Originally posted by Matty
quote:
Originally posted by deAd
code:
var pNmhdr = Interop.Allocate(12); // if this is the wrong size sorry
Interop.Call('Kernel32.dll', 'RtlMoveMemory', pNmhdr.DataPtr, lParam, pNmhdr.Size);
// do stuff with pNmhdr

The members of the structure are still 0... I don't see why this isn't working :S
Because you've sent the notification message yourself:
code:
case WM_PARENTNOTIFY:
            _sent_notify = true;
            Interop.Call('user32', 'SendMessageW', _window.Handle,
                                                   WM_NOTIFY,
                                                   pPlusWnd.GetControlHandle('tvFiles'),
                                                   NMHDR.DataPtr);
but you don't fill the structure with the proper values.





----------------------

quote:
Originally posted by Matty
So my dilemma is the website example says that lParam is the NMHDR structure however there would be no way to access the members of the structure.
I could be wrong, but I think you're confusing some things.

Anyways, some stuff about the NMHDR structure when it is send from a control by Windows itself:

lParam points to an _extended_ NMHDR structure. This means, in the OnWndAllContactsEvent_MessageNotification, you need to copy the entire structure in memory to a datablock. This is done with the RtlMoveMemory API, as you already know.

But before you do this, you first need to check several things, so you don't copy unallocated memory (as not every extended structure used by the specific notification messages is the same size). But the basic NMHDR structure is always 12 bytes long of course.

And thus depending on the code member of the structure, the structure will actually be x bytes bigger. The code member is that notification code. (thus of which each uses their own extended NMHDR structures. thus which all begin with the basic NMHDR structure again).

So, from "the top of my head" (almost, as I use this very same code "somewhere" already :p):
code:
function OnWndAllContactsEvent_MessageNotification(pPlusWnd, nMessage, wParam, lParam) {
    // Allocate enough memory immediatly for the extended structure we're going to use
    var _NMHDR = Interop.Allocate(72);

    // Copy only the basic needed members (at first)
    // (<= come to think of it, this needs to be fixed in SendTo ;))
    Interop.Call('Kernel32', 'RtlMoveMemory', _NMHDR.DataPtr, lParam, 12);

    // Check the code member.
    if (_NMHDR.ReadDWORD( 8) === /* LVN_BEGINLABELEDIT */ -175) {
        // If it is the correct one, we can copy the rest of the needed bytes safely
        Interop.Call('Kernel32', 'RtlMoveMemory', _NMHDR.DataPtr + 12, lParam + 12, 60);
        Debug.Trace('0    HWND hwndFrom; ' + _NMHDR.ReadDWORD(0));
        Debug.Trace('4    UINT idFrom; ' + _NMHDR.ReadDWORD(4));
        Debug.Trace('8    UINT code; ' + _NMHDR.ReadDWORD( 8));
        Debug.Trace('12    UINT mask; ' + _NMHDR.ReadDWORD(12));
        Debug.Trace('16    int iItem; ' + _NMHDR.ReadDWORD(16));
        Debug.Trace('20    int iSubItem; ' + _NMHDR.ReadDWORD(20));
        Debug.Trace('24    UINT state; ' + _NMHDR.ReadDWORD(24));
        Debug.Trace('28    UINT stateMask; ' + _NMHDR.ReadDWORD(28));
        Debug.Trace('32    LPTSTR pszText; ' + _NMHDR.ReadDWORD(32));
        Debug.Trace('36    int cchTextMax; ' + _NMHDR.ReadDWORD(36));
        Debug.Trace('40    int iImage;  ' + _NMHDR.ReadDWORD(40));
        Debug.Trace('44    LPARAM lParam; ' + _NMHDR.ReadDWORD(44));
        Debug.Trace('48    int iIndent; ' + _NMHDR.ReadDWORD(48));
        Debug.Trace('52    int iGroupId; ' + _NMHDR.ReadDWORD(52));
        Debug.Trace('56    UINT cColumns; ' + _NMHDR.ReadDWORD(56));
        Debug.Trace('60    PUINT puColumns; ' + _NMHDR.ReadDWORD(60));
        Debug.Trace('64    int* piColFmt; ' + _NMHDR.ReadDWORD(64));
        Debug.Trace('68    int iGroup; ' + _NMHDR.ReadDWORD(68));
}


or in your case (which doesn't actually use an extended NMHDR structure though):
code:
case WM_NOTIFY:
            _get_item(pPlusWnd);
            if (_sent_notify == true){
                Interop.Call('kernel32', 'RtlMoveMemory', NMHDR, lParam, 12);
                Debug.Trace(NMHDR.ReadDWORD(0));
                Debug.Trace(NMHDR.ReadDWORD( 8)); // this is your NM_CLICK, NM_DBLCLK, etc notification code
But of course, the members of the structure you read here are filled in by you (or rather, not filled in) so they just return what you've put there: nothing.


-----------

Part 2:

So what do you fill in in that NMHDR structure in the WM_PARENTNOTIFY case? That depends on the values of lparam and wparam. eg: if the low-order word of wParam is WM_LBUTTONDOWN, you should fill he structure with the appropiate handle of the control, the id, and NM_CLICK as code member.

But as far as double clicking goes, this needs to be detected by your own custom code. This means you need to catch two WM_LBUTTONDOWN's in a row in a certain time, and then you could fill in the NMHDR structure with NM_DBLCLK. In other words, if that event occurs, you would have recieved in the WM_NOTIFY case of your code 1 NM_CLICK and milliseconds later (depending on how long you set your timer to detect a doubleclick) one NM_DBLCLK. see WM_LBUTTONDBLCLK.


This brings up the fact that sending your own WM_NOTIFY message is actually useless, as you could just as well handled the double clicking (whatever the effect is you want) directly in the WM_PARENTNOTIFY case.



This said, and this might be a dumb comment, but why don't you use the WM_NOTIFY messages send from the control itself? They will contain all those specific notification messages already. Or aren't they send to the parent window for a TreeView? (I know some stuff for a listview isn't send to the parent either, so I wouldn't be surpised of it actually)...

This post was edited on 03-09-2007 at 10:44 AM by CookieRevised.
.-= A 'frrrrrrrituurrr' for Wacky =-.
03-09-2007 12:55 AM
Profile PM Find Quote Report
Patchou
Messenger Plus! Creator
*****

Avatar

Posts: 8607
Reputation: 201
43 / Male / Flag
Joined: Apr 2002
RE: WM_NOTIFY Help - (Noobs stay away! haha)
hum.. there'S a lot of stuff here (btw Cookie, did you forget about WM_LBUTTONDBLCLK? :p).

so, my first questio nwould be: what do you want to do exactly? because if you simply want to catch notifications sent from the treeview control, all you need to do is to catch WM_NOTIFY messages, cast lParam to a NMHDR structure and check if "code" is equal to NM_CLICK, NM_DBLCLK, etc...
[Image: signature2.gif]
03-09-2007 06:29 AM
Profile PM Web Find Quote Report
CookieRevised
Elite Member
*****

Avatar

Posts: 15519
Reputation: 173
– / Male / Flag
Joined: Jul 2003
Status: Away
RE: RE: WM_NOTIFY Help - (Noobs stay away! haha)
quote:
Originally posted by Patchou
(btw Cookie, did you forget about WM_LBUTTONDBLCLK? :p).
yes... :p


quote:
Originally posted by Patchou
so, my first questio nwould be: what do you want to do exactly? because if you simply want to catch notifications sent from the treeview control, all you need to do is to catch WM_NOTIFY messages, cast lParam to a NMHDR structure and check if "code" is equal to NM_CLICK, NM_DBLCLK, etc...
quote:
Originally posted by CookieRevised
This said, and this might be a dumb comment, but why don't you use the WM_NOTIFY messages send from the control itself? They will contain all those specific notification messages already.

This post was edited on 03-09-2007 at 10:46 AM by CookieRevised.
.-= A 'frrrrrrrituurrr' for Wacky =-.
03-09-2007 10:45 AM
Profile PM Find Quote Report
« Next Oldest Return to Top Next Newest »


Threaded Mode | Linear Mode
View a Printable Version
Send this Thread to a Friend
Subscribe | Add to Favorites
Rate This Thread:

Forum Jump:

Forum Rules:
You cannot post new threads
You cannot post replies
You cannot post attachments
You can edit your posts
HTML is Off
myCode is On
Smilies are On
[img] Code is On