What happened to the Messenger Plus! forums on msghelp.net?
Shoutbox » MsgHelp Archive » Messenger Plus! for Live Messenger » Scripting » Structure definition class

Structure definition class
Author: Message:
Matti
Elite Member
*****

Avatar
Script Developer and Helper

Posts: 1646
Reputation: 39
31 / Male / Flag
Joined: Apr 2004
O.P. Structure definition class
Structure definition class
Current version: 1.0.001


^o) What?

The structure definition class allows developers to easily define, create, access and modify memory structures to use in many parts of the Win32 API. Instead of calculating the memory positions of the individual members and doing all the needed conversion by hand, this class does the hard work for you and lets you access members by name.

:^) Why?

The power of this class really shows itself with an example. Say you needed a POINT structure to retrieve the current mouse position with GetCursorPos. According to MSDN, a POINT is defined as followed:
C++ code:
typedef struct tagPOINT {
  LONG x;
  LONG y;
} POINT, *PPOINT;

Using just the Plus! scripting engine, we could retrieve the cursor position with:
Javascript code:
var pt = Interop.Allocate(8);
Interop.Call( 'user32', 'GetCursorPos', pt );
var x = pt.ReadDWORD(0);
var y = pt.ReadDWORD(4);

For small structures like this one, this is still pretty manageable. However when you need a structure with 10 or 20 members with different types and sizes, it quickly becomes frustrating to figure out the right positions.

Now have a look at how this same task can be achieved with this class:
Javascript code:
var POINT = new StructType({
    x: DataType.LONG,
    y: DataType.LONG
};
var pt = new POINT;
Interop.Call( 'user32', 'GetCursorPos', pt.dataptr() );
var x = pt.x();
var y = pt.y();

As you can see, this is much easier to read and to work with. If that doesn't convince you, try a more complex example:
Javascript code:
var LVITEM = new StructType({
    mask:           DataType.UINT,
    iItem:          DataType.INT,
    iSubItem:       DataType.INT,
    state:          DataType.UINT,
    stateMask:      DataType.UINT,
    pszText:        DataType.LPTSTR,
    cchTextMax:     DataType.INT,
    iImage:         DataType.INT,
    lParam:         DataType.LONG,
    iIndent:        DataType.INT,
    iGroupId:       DataType.INT,
    cColumns:       DataType.UINT,
    puColumns:      DataType.UINT
});
 
var firstItem = new LVITEM;
firstItem.mask( /* LVIF_TEXT */ 0x1 );
firstItem.pszText( 'First item' );
 
PlusWnd.SendControlMessage( 'MyListView', /* LVM_INSERTITEMW */ (0x1000 + 77), 0, firstItem.dataptr() );

Not only the memory positions are handled by the class, it also does the needed type conversions for you. In this example, the pszText member takes a string, creates a new DataBloc, writes the string to it and then writes the pointer of that DataBloc to the structure.

(H) Features
  • Define once, use forever. By defining a structure type, you create a new class which creates structures. You can create as many class instances as you want, so you don't have to redefine that type ever again.
  • Defining structures is almost like copy pasting from MSDN. You can use the same names for the members and in almost all cases, you can use the same names for the data types as well. If MSDN says that 'mask' is a LONG, then just define it as a DataType.LONG, no need to figure out the corresponding DataBloc method any more.
  • Accessing members couldn't be easier: just use their names. No more fiddling with memory positions, the class always knows where the members are located.
  • Combined getter/setter methods for each member. To write a value to a member, pass it as the first parameter. To read the value of a member, just pass no arguments. Can it be any easier?
    Javascript code:
    // Get
    var x = struct.myMember();
    // Set
    struct.myMember(10);

  • Convert values automatically to the right type. Some DataTypes have a custom setter methods which allow you to pass a value in different types, such a string for an LPSZ, an [x,y] array for a POINT or red/green/blue values for a COLORREF.
  • Use structures in structures. Occasionally, you'll find that a structure contains another structure. For example, NMLISTVIEW has a NMHDR structure for its 'hdr' member. Instead of copying the members of NMHDR to NMLISTVIEW, just create an NMHDR type and use it within NMLISTVIEW:
    Javascript code:
    var NMHDR = new StructType({
        hwndFrom:   DataType.HWND,
        idFrom:     DataType.UINT,
        code:       DataType.UINT
    });
    var NMLISTVIEW = new StructType({
        hdr:        NMHDR,
        iItem:      DataType.INT,
        iSubItem:   DataType.INT,
        uNewState:  DataType.UINT,
        uOldState:  DataType.UINT,
        uChanged:   DataType.UINT,
        ptAction:   DataType.POINT,
        lParam:     DataType.LONG
    });

    You can then access a sub structure member with:
    Javascript code:
    var nmListView = new NMLISTVIEW;
    var hwndFrom = nmListView.hdr().hwndFrom();

    This is possible since StructTypes double as DataTypes, so you can use them just like you'd use a DataType. (prototypical inheritance ftw!)
  • Easily work with datatype arrays. Some structures take an array of values for a single member, for example LOGFONT takes an array of 32 TCHARS for its 'lfFaceName' member. Instead of defining 32 different TCHAR members in a structure type, you can use DataType.Array to create an array-like data type with a fixed length.
    Javascript code:
    var LF_FACESIZE = 32;
    var LOGFONT = new StructType({
        lfHeight:   DataType.LONG,
        // ...
        lfFaceName: DataType.Array(DataType.TCHAR, LF_FACESIZE)
    });
    var font = new LOGFONT;
    // Write a single item to a specific index
    font.lfFaceName().item(0, 'a');
    // Read a single item from a specific index
    var char = font.lfFaceName().item(0);
    // Write an array
    font.lfFaceName().fromArray(['a', 'b', 'c']);
    // Read as an array
    var chars = font.lfFaceName().toArray();
    // (W)CHAR arrays even have extra methods for easier handling
    font.lfFaceName().fromString('abcdef');
    var fontFace = font.lfFaceName().toString();


(co) Download

» Structure definition class (v1.0.001 - 7 November 2010)

8-| Change-log
  • 1.0.001 (7 November 2010)
    • Initial release.
(I) To-do
  • More DataTypes? Post your suggestions below!

Note
This thread was split from SmokingCookie's thread about list-view groups. I threw in the structure class while trying to get grouping support in my ListView class. Because this was the first time the community heard about this class, there was a lot of excitement about it so the thread got split. That's why some of the first replies here may refer to this other thread.

This post was edited on 11-07-2010 at 08:00 PM by Matti.
Plus! Script Developer | Plus! Beta Tester | Creator of Countdown Live | Co-developer of Screenshot Sender 5

Found my post useful? Rate me!
10-17-2010 08:35 PM
Profile E-Mail PM Web Find Quote Report
« Next Oldest Return to Top Next Newest »

Messages In This Thread
Structure definition class - by Matti on 10-17-2010 at 08:35 PM
RE: Structure definition class - by Matti on 10-20-2010 at 04:21 PM
RE: Structure definition class - by Matti on 11-07-2010 at 08:12 PM
RE: List-view groups - by Mnjul on 10-17-2010 at 09:07 PM
RE: List-view groups - by Matti on 10-18-2010 at 11:28 AM
RE: List-view groups - by matty on 10-18-2010 at 12:03 PM
RE: List-view groups - by SmokingCookie on 10-18-2010 at 03:30 PM
RE: List-view groups - by Matti on 10-18-2010 at 08:33 PM
RE: List-view groups - by Eljay on 10-18-2010 at 09:16 PM
RE: List-view groups - by Matti on 10-18-2010 at 09:43 PM
RE: List-view groups - by CookieRevised on 10-18-2010 at 11:11 PM


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