Structure definition class - Printable Version -Shoutbox (https://shoutbox.menthix.net) +-- Forum: MsgHelp Archive (/forumdisplay.php?fid=58) +--- Forum: Messenger Plus! for Live Messenger (/forumdisplay.php?fid=4) +---- Forum: Scripting (/forumdisplay.php?fid=39) +----- Thread: Structure definition class (/showthread.php?tid=95631) Structure definition class by Matti on 10-17-2010 at 08:35 PM
Structure definition class Current version: 1.0.001 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: cpp code:Using just the Plus! scripting engine, we could retrieve the cursor position with: js code: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: js code: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: js code: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. Features
Download » Structure definition class (v1.0.001 - 7 November 2010) Change-log
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. RE: List-view groups by Mnjul on 10-17-2010 at 09:07 PM
quote:Wow Matti - that's something amazing! Get it released soon Can you first tell us what DataType's you support? RE: List-view groups by Matti on 10-18-2010 at 11:28 AM
At the moment, I implemented some basic types (BOOL, WORD, INT, CHAR, LPWSTR) and some common synonyms (UINT, DWORD, LONG). I also added a POINT type which basically writes an array [x, y] to two INTs. RE: List-view groups by matty on 10-18-2010 at 12:03 PM
You should add this by default RE: List-view groups by SmokingCookie on 10-18-2010 at 03:30 PM
Wow, looks like I've missed something in the past 36 hours RE: List-view groups by Matti on 10-18-2010 at 08:33 PM
quote:Did you see how long that list is? I'll be more than happy if I could implement the most commonly used types, and it still won't be enough. quote:That's exactly how I did it. The following comes straight from my implementation: js code:The DWORD implementation maps to the INT functions but also removes the sign from the numbers, so -2 becomes 0xFFFF FFFE. On a totally unrelated note then... While I was playing with these signed/unsigned types, I saw that the code member from NMHDR was defined as a UINT, but could also take signed values (e.g. LVN_COLUMNCLICK = -108) so to get around this, I defined code as an INT instead. Anyone has a valid explanation for this behavior? Source: NMHDR on MSDN RE: List-view groups by Eljay on 10-18-2010 at 09:16 PM
It's quite funny how similar your struct system is to one I started making js code: But I "built" the DataBloc during construction rather than with an extra function, so it might be easier to do variable-size members your way. It's nice to know you made almost exactly the same thing anyway, it means I don't need to finish mine now RE: List-view groups by Matti on 10-18-2010 at 09:43 PM
quote:Actually, that build() method simply returns the DataBloc created during construction. When I started working on it, I first laid out the structure and I was still unsure about how I was going to implement it. I kept the build() method so the actual DataBloc cannot be accidentally replaced or removed from the class instance. (Well, you can still destroy the DataBloc with firstItem.build().Size = 0 but I don't think any sane developer would do that). As for the arrays of a data type - great idea, thanks for your suggestion! I think you'll understand that working with fields with fixed sizes is much easier to work with than variable sized fields. Still, it may be possible to let the size be defined when the structure type is assigned to a structure member. You could add a constructor to the data type which takes a parameter (e.g. the amount of TCHARs) and sets its size accordingly. A LOGFONT could then look like this: js code:In general, any DataType could take an array length as parameter and morph into an array type, such as INT[10] or LONG[5]. In the TCHAR constructor, this general behavior could then be extended to also allow a 32-character string to be accepted for the getter and to be outputted by the setter method by making use of inheritance. I'm just thinking out loud here, the exact syntax may vary from what I really make but that's one way to do it. RE: List-view groups by CookieRevised on 10-18-2010 at 11:11 PM The signed/unsigned behaviour and handling was the first thing I was wondering about when I saw you made a class for this, Matti. I was wondering if you took that into account... (since the WriteDWORD function can accept signed values too, yet you make it possible to define stuff like UINT, etc)... but I didn't checked your code yet to see for myself if you took that into account (lazy )... Anyways, since you brought it up... quote:A signed value can always be represented as an unsigned value and vice versa. So if you assign -108 to an UINT (=4 bytes in memory), you actually assign the unsigned value: 0xFFFFFF94 or 4294967188 in memory. And -108 is just easier to remember and to recognize in code than 4294967188, that's all. Actually -108 (LVN_COLUMNCLICK ) comes from the calculation LVN_FIRST-8, and LVN_FIRST is defined as 0xFFFFFF9C (or -100 when you interpret is as a signed INT). Thus, code should actually be defined as UINT though, not as an INT! So, instead of that 'workaround' by defining it as a wrong type, your function should convert the given signed value to an unsigned value, which is actually automatically already done by WriteDWORD anyways. That is: it simply writes the given number as-is to memory, which is already enough... (after of course AND'ing it with 0xFFFFFFFF to avoid overflow errors). But to read the UINT value again, you must do some calculation yourself though. ReadDWORD() will otherwise return -108 (in the above example). But since it is defined as UINT it should return 4294967188 instead. So, what you should do is check the return value and if <0 you need to add 0x100000000 to the returned value. In short (taking INT/UINT as example): - To write a value you don't need to do anything (accept AND'ing with 0xFFFFFFFF of course). It doesn't matter if the number is pos or neg or if the type is signed or not... - But to properly return an unsigned value, you do need to check if the returned value isn't negative, if so, you add 0xFFFFFFFF+1 to it) -- PS: Another thing you could come across which would be very related to this is that quite a lot of functions in Windows actually compare your assigned value with an OR function to a mask which represents the meaningfull bits. So, it could well be that a -108 value (to take the same number as above) is simply interpreted as 4 in case the mask with meaningfull bits is 0xF. So, in that case -108, -236, 292, 1104936484, -4294966732, etc all have the same function since the least significant digit is always 0x4. In the other way around: there are also some types used in Windows which are defined as a signed type, but in fact only unsigned (positive) values are defined. That is: only some positive values have a meaning. This is in most cases by design. And in those cases, in later Windows versions, you'll see that some other values are added and sometimes they are indeed negative values. So, it is not because the type is signed and only positive values are defined now, that in a later Windows version some new (negative) values aren't added anymore. I hope I make some sense here, it's already late and I didn't slept much last nights either... RE: Structure definition class by Matti on 10-20-2010 at 04:21 PM
Thanks for the very thorough explanation, Cookie! I already had such conversions implemented in my getters, I just needed to do the signed to unsigned conversion on LVN_COLUMNCLICK as well to make my comparison work. For ease of use, I exposed these methods in Number.toUnsigned(), Number.toSigned() and Number.toUINT(). Then again, it's a bit counter-intuitive to have DataBloc.ReadWORD() and ReadDWORD() take signed numbers while WORD and DWORD are both unsigned... RE: Structure definition class by Matti on 11-07-2010 at 08:12 PM
It's here! The first version of the class is now available. Go get it from the download link in the first post. |