 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
Lexikos
Joined: 17 Oct 2006 Posts: 7295 Location: Australia
|
Posted: Thu Jan 17, 2008 12:49 pm Post subject: StructParser (for C/C++ structs) |
|
|
Someone recently stated how amazing my understanding of structs is, so I'm posting this to prove them wrong.
This script parses a C/C++ struct definition and outputs AutoHotkey code to set or get each field in the struct.
Known Issues:
- Only types defined in ParseField() are supported.
- Nested structs are not supported, except for RECT and POINT.
- 1-byte field alignment is assumed. This isn't an issue for most structures defined at MSDN, which have explicit padding where necessary.
- Bit fields such as BOOL fFocused:1; are not supported.
- Not really an issue: for convenience, any type beginning with "LP" is assumed to be a pointer type.
If the script encounters a field that it cannot parse, it will prompt the user for the name, size (in bytes) and (optional) NumGet-compatible type of the field.
The generated code assumes the struct's data is stored in an AutoHotkey variable. To operate on a struct by address, the code must be adjusted.
| Code: | ; put value into struct var
NumPut(value, struct, offset, type)
; put value into struct by address (+0 or similar required)
NumPut(value, pointer_to_struct+0, offset, type)
|
Requires: Anchor (in your function library, or add an #include.)
| Code: | #NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%
Gui, +Resize +MinSize250x80
Gui, Margin, 7, 7
Gui, Font,, Courier New
Gui, Add, Edit, R9 W400 vInputText
Gui, Font
Gui, Add, Button, vParseButton gParseStruct Y+2, &Parse
Gui, Add, Button, vCopyButton gParseAndCopy X+0, && &Copy
Gui, Add, Checkbox, vGenGetters Checked X+5 YP+5, &Get
Gui, Add, Checkbox, vGenSetters Checked X+0, &Set
Gui, Add, Checkbox, vGenCtor Checked X+0, &VarSetCapacity
Gui, Add, Edit, vStructName X+0 YP-4, struct
Gui, Font,, Courier New
Gui, Add, Edit, XM Y+4 R12 W400 vOutputText
GuiControlGet, StructName, Pos
GuiControl, Move, StructName, % "W" 414-StructNameX-7
Gui, Show, W414, Struct Parser
DelimNameAndTypeWithNewline := false
return
ParseAndCopy:
gosub ParseStruct
Clipboard := RegExReplace(OutputText, "(?<!`r)`n", "`r`n")
return
ParseStruct:
Gui, Submit, NoHide
OutputText =
OutputGetters =
OutputSetters =
if StructName =
StructName = struct
; Remove comments and directives from consideration.
InputText := RegExReplace(InputText, "`a)//.*|#.*|/\*.*?\*/")
pos := 1
namespace = ; short string to keep track of unions, etc.
indent =
indent_amount = 4
offset = 0
; for union support
union_offsets = ; (list)
union_ends = ; (list)
Loop
{
i := RegExMatch(InputText, "s).*?({|;|})", t, pos)
if ! i
break
; Move cursor to end of this bit.
pos := i+StrLen(t)
; Remove leading whitespace (previous regex excludes trailing space.)
t := RegExReplace(t, "(?:^\s+)")
if (t1 = "{")
{ ; Enter block.
; Mark the beginning of the block.
if GenGetters
OutputGetters .= indent . "; " . t . "`n"
if GenSetters
OutputSetters .= indent . "; " . t . "`n"
; Indent output.
Loop, %indent_amount%
indent .= " "
; Add block info to namespace, if relevant.
if (RegExMatch(t, "^union(?:\s+(\w*))s*{$")) {
last_block = u
StackPush(union_offsets, offset)
StackPush(union_ends, offset)
} else
last_block = .
namespace .= last_block
}
else if (t1 = "}")
{ ; Exit block.
; Un-indent output.
indent := SubStr(indent, 1, -indent_amount)
; Mark the end of the block.
if GenGetters
OutputGetters .= indent . "; }`n"
if GenSetters
OutputSetters .= indent . "; }`n"
if (last_block = "u")
{ ; End union.
offset := StackPop(union_ends, offset)
StackPop(union_offsets)
}
; Remove block info char from namespace.
if (StrLen(namespace))
{
StringTrimRight, namespace, namespace, 1
; Update current immediate block.
last_block := SubStr(namespace, 0) ; 0=last char
}
else
last_block := ""
; Omit declarations following a block (e.g. "struct x { int y } declarations;")
i := RegExMatch(InputText, "s).*?({|;|})", t, pos)
if (t1 = ";")
pos := i+StrLen(t)
}
else if (t != ";")
{
if ! ParseField(t)
return
}
if (t != "{" && last_block = "u")
{ ; Determine end of union by its largest item.
end := StackPop(union_ends)
if (end="" or offset > end)
end := offset
StackPush(union_ends, end)
; Reset offset to beginning of union.
offset := StackPeek(union_offsets, offset)
}
}
if GenCtor
OutputText .= "VarSetCapacity(" StructName ", " offset ", 0)`n`n"
if GenGetters
OutputText .= OutputGetters "`n"
if GenSetters
OutputText .= OutputSetters "`n"
; OutputText .= "`nStdOut( "
; Loop, Parse, NameList, `,
; {
; if (A_Index>1)
; OutputText = %OutputText% ", %A_LoopField%=" %A_LoopField%
; else
; OutputText = %OutputText%"%A_LoopField%=" %A_LoopField%
; }
; OutputText .= " )"
GuiControl,, OutputText, %OutputText%
return
AppendField(name, size, type="", length="") ; length=array length
{
local delim, pos, text, StructName_
if StructName != struct
StructName_ = %StructName%_
if (name && type)
{
if length =
{
text = %StructName_%%name%
if GenGetters
OutputGetters .= indent text " := NumGet(" StructName ", " offset ", """ type """)`n"
if GenSetters
OutputSetters .= indent "NumPut(" text ", " StructName ", " offset ", """ type """)`n"
NameList .= (NameList ? "," : "") . name
}
else
{
if GenGetters
{
OutputGetters .= indent StructName_ name "[%index%] := NumGet(" StructName ", " offset " + index"
if size != 1
OutputGetters .= "*" size
OutputGetters .= ", """ type """)"
. (DelimNameAndTypeWithNewline ? "`n " indent : ", ") . StructName_ name "_length := " length "`n"
}
if GenSetters
{
OutputSetters .= indent "NumPut(" StructName_ name "[%index%], " StructName ", " offset " + index"
if size != 1
OutputSetters .= "*" size
OutputSetters .= ", """ type """)`n"
}
}
}
else
{
text := indent StructName "_" name "_ptr := &" StructName " + " offset
if (type)
text .= (DelimNameAndTypeWithNewline ? "`n " indent : ", ")
. StructName "_" name "_type := """ type """"
if (length)
text .= (DelimNameAndTypeWithNewline ? "`n " indent : ", ")
. StructName "_" name "_length := " length
if GenGetters
OutputGetters .= text "`n"
if GenSetters
OutputSetters .= text "`n"
}
if length
offset += size*length
else
offset += size
}
StackPush(ByRef stack, item)
{
if stack
stack .= ","
stack .= item
}
StackPop(ByRef stack, defval="")
{
if (pos := InStr(stack, ","))
{
item := SubStr(stack, pos+1)
stack := SubStr(stack, 1, pos-1)
return item
}
else if stack
{
item := stack
stack := ""
return item
}
return defval
}
StackPeek(ByRef stack, defval="")
{
if (pos := InStr(stack, ","))
return SubStr(stack, pos+1)
else if stack
return stack
else
return defval
}
; Parses a field string "type identifier[arraylength];"
; Returns:
; name
; size - size, in bytes, of the field.
; type - NumGet/DllCall-compatible type string.
ParseField(t)
{
local m, mtype, msep, mname, mlength, userlength
, typelist, name, size, type
static Types = "Int,UInt,Short,UShort,Char,UChar,Int64,Float,Double"
, IntSize = 4 , IntTypes = "int,INT,LONG"
, UIntSize = 4 , UIntTypes = "unsigned int,unsigned long,UINT,ULONG,DWORD,COLORREF,HANDLE,HBITMAP,HBRUSH,HDC,HICON,HISTANCE,HMENU,HWND,ULONG_PTR,LPARAM,WPARAM"
, ShortSize = 2 , ShortTypes = "short"
, UShortSize = 2 , UShortTypes = "unsigned short,WORD,ATOM,USHORT,WCHAR"
, CharSize = 1 , CharTypes = "char"
, UCharSize = 1 , UCharTypes = "unsigned char,byte,BYTE,UCHAR,TCHAR" ; assume compiled with multi-byte, not unicode...
, Int64Size = 8 , Int64Types = "int64,LONGLONG,ULONGLONG"
, FloatSize = 4 , FloatTypes = "FLOAT"
, DoubleSize = 8 , DoubleTypes = "DOUBLE"
if (RegExMatch(t, "^\s*(?<type>(?:[\w]+[ \t])*[\w]+)(?<sep>[\s\*]+)(?<name>\w+)(?:\[(?<length>\w+)\])?\s*;", m))
{
name := mname
if (mtype = "bool") {
if (mtype=="BOOL") ; BOOL is an alias for int.
AppendField(name, 4, "Int")
else ; bool (C++) is 1 byte.
AppendField(name, 1, "UChar")
return true
}
if (InStr(msep, "*") or SubStr(mtype,1,2)="LP")
{ ; Add 32-bit pointer to something.
AppendField(name, 4, "UInt")
return true
}
if ((mtype = "POINTL" or mtype = "POINT") && mlength="")
{ ; Add individual X and Y fields.
AppendField(name . "_X", 4, "Int")
AppendField(name . "_Y", 4, "Int")
return true
}
if (mtype = "RECT" && mlength="")
{ ; Add individual struct fields.
AppendField(name . "_left", 4, "Int")
AppendField(name . "_top", 4, "Int")
AppendField(name . "_right", 4, "Int")
AppendField(name . "_bottom", 4, "Int")
return true
}
if StartsWith(mtype, "LP") && !EndsWith(mtype, "STR")
{
type := "UInt", size := 4
}
else
{ ; Get DllCall-compatible type if possible.
Loop, Parse, Types, `,
{
typelist := %A_LoopField%Types
if mtype in %typelist%
{
type := A_LoopField
size := %A_LoopField%Size
break
}
}
}
if mlength
if mlength is not integer
{
if ! RegExMatch(mlength, "\W")
if DEF_%mlength%
mlength := DEF_%mlength%
if mlength is not integer
{
mlength_TryAgain:
InputBox, userlength, Constant, Unknown value '%mlength%' used as array length. Please enter the value of '%mlength%'.,,, 150
if userlength =
return
if userlength is not integer
goto mlength_TryAgain
DEF_%mlength% := mlength := userlength
}
}
}
if ! size
{
; Ask the user to enter details for this field.
size = 4
type = UInt ; Most common.
if ! PromptForStuff(t, name, size, type)
return false
}
AppendField(name, size, type, mlength)
return true
}
PromptForStuff(t, ByRef name, ByRef size, ByRef type, message="")
{
static retval, tname, tsize, ttype
if ! message
message = Failed to parse field:`n %t%`n`nPlease enter the necessary details.
Gui, 2:Default
Gui, +Owner1
Gui, +LabelPFS +LastFound
Gui, Add, Text, W300, %message%
Gui, Add, Text, , Name:
Gui, Add, Edit, W300 vtname, %name%
Gui, Add, Text, , Size:
Gui, Add, Edit, W300 vtsize, %size%
Gui, Add, Text, , NumGet-compatible Type:
Gui, Add, Edit, W300 vttype, %type%
Gui, Add, Button, gPFSOK Default, OK
retval = 0
Gui, Show,, Parse Error
Gui, 1:+Disabled
WinWaitClose, % "ahk_id " . WinExist()
name := tname
size := tsize
type := ttype
Gui, 1:Default
Gui, 1:-Disabled
Gui, 1:Show
Gui, 2:Destroy
return retval
PFSEscape:
Gui, 2:Cancel
return
PFSOK:
Gui, 2:Submit
retval = 1
return
}
GuiEscape:
GuiClose:
ExitApp
GuiSize:
; Anchor("InputText" , "w h0.5")
; , Anchor("ParseButton", "y0.5"), Anchor("GenGetters", "y0.5")
; , Anchor("GenGetters", "y0.5"), Anchor("GenSetters", "y0.5")
; , Anchor("GenCtor", "y0.5"), Anchor("StructName", "y0.5 w1")
; , Anchor("OutputText", "w h0.5 y0.5")
; InputText is rarely used for more than a paste target,
; so resize only OutputText vertically.
Anchor("InputText", "w")
, Anchor("StructName", "w")
, Anchor("OutputText", "h w")
return
; Case-sensitive by default because we're parsing C++ code.
EndsWith(A, B, CaseSensitive=true)
{
if (StrLen(A) < StrLen(B))
return false
return CaseSensitive
? (SubStr(A, -(StrLen(B)-1)) == B)
: (SubStr(A, -(StrLen(B)-1)) = B)
}
StartsWith(A, B, CaseSensitive=true)
{
if (StrLen(A) < StrLen(B))
return false
return CaseSensitive
? (SubStr(A, 1, StrLen(B)) == B)
: (SubStr(A, 1, StrLen(B)) = B)
}
Spaces(count)
{
Loop, %count%
str .= " "
return str
}
| Covered by Lexikos' default copyright license.
Usage:
Copy and paste a C/C++ structure definition into the top field, then click Parse. If a parsing error occurs, you will be prompted to enter the correct details. If all goes well, AutoHotkey code will appear in the bottom field. This code may or may not be directly usable in script.
[& Copy] does the same as [Parse], but also copies the result to the clipboard.
The small edit field in the middle defines the name of the struct variable for the generated code. If not "struct", it will be prepended to the name of each field (with "_" as a delimiter.) For the example output below, this field was set to "wp".
Example input:
| Code: | typedef struct _WINDOWPLACEMENT {
UINT length;
UINT flags;
UINT showCmd;
POINT ptMinPosition;
POINT ptMaxPosition;
RECT rcNormalPosition;
} WINDOWPLACEMENT;
| Example output:
| Code: | VarSetCapacity(wp, 44, 0)
; typedef struct _WINDOWPLACEMENT {
wp_length := NumGet(wp, 0, "UInt")
wp_flags := NumGet(wp, 4, "UInt")
wp_showCmd := NumGet(wp, 8, "UInt")
wp_ptMinPosition_X := NumGet(wp, 12, "Int")
wp_ptMinPosition_Y := NumGet(wp, 16, "Int")
wp_ptMaxPosition_X := NumGet(wp, 20, "Int")
wp_ptMaxPosition_Y := NumGet(wp, 24, "Int")
wp_rcNormalPosition_left := NumGet(wp, 28, "Int")
wp_rcNormalPosition_top := NumGet(wp, 32, "Int")
wp_rcNormalPosition_right := NumGet(wp, 36, "Int")
wp_rcNormalPosition_bottom := NumGet(wp, 40, "Int")
; }
; typedef struct _WINDOWPLACEMENT {
NumPut(wp_length, wp, 0, "UInt")
NumPut(wp_flags, wp, 4, "UInt")
NumPut(wp_showCmd, wp, 8, "UInt")
NumPut(wp_ptMinPosition_X, wp, 12, "Int")
NumPut(wp_ptMinPosition_Y, wp, 16, "Int")
NumPut(wp_ptMaxPosition_X, wp, 20, "Int")
NumPut(wp_ptMaxPosition_Y, wp, 24, "Int")
NumPut(wp_rcNormalPosition_left, wp, 28, "Int")
NumPut(wp_rcNormalPosition_top, wp, 32, "Int")
NumPut(wp_rcNormalPosition_right, wp, 36, "Int")
NumPut(wp_rcNormalPosition_bottom, wp, 40, "Int")
; }
|
Final notes:
For the curious, I wrote this script while trying to work with the DEVMODE structure.
I generally only use the code it generates as a reference.
Last edited by Lexikos on Tue Dec 30, 2008 12:38 am; edited 5 times in total |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 4511 Location: Belgrade
|
Posted: Thu Jan 17, 2008 1:43 pm Post subject: |
|
|
ROFLMAO :D
I will definitely use this. When I get high ocasionaly, there is no chance on the world to correctly calcuate struct offsets  |
|
| Back to top |
|
 |
polyethene
Joined: 11 Aug 2004 Posts: 5248 Location: UK
|
Posted: Thu Jan 17, 2008 3:47 pm Post subject: |
|
|
Structs beyond the complexity of a RECT is something I seldom use, but for when such occasions do arise this will definitely be a lot helpful.
I would suggest adding a copy to clipboard feature. If you can, support creating structs would also be an added bonus  _________________ GitHub • Scripts • IronAHK • Contact by email not private message. |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 7295 Location: Australia
|
Posted: Fri Jan 18, 2008 3:33 am Post subject: |
|
|
Update: StructParser now generates more useful code.
| Titan wrote: | | I would suggest adding a copy to clipboard feature. | I've added a [& Copy] button.
| Quote: | If you can, support creating structs would also be an added bonus  | I suppose it is most common to store the struct's data in a variable, so creating a struct is simply calling VarSetCapacity. StructParser now generates
| Code: | VarSetCapacity(struct, size, 0)
| instead of
|
|
| Back to top |
|
 |
Guest
|
Posted: Mon Jan 21, 2008 3:12 pm Post subject: |
|
|
| lexikos wrote: | For the curious, I wrote this script while trying to work with the DEVMODE structure. |
OTOH, what about MENUBARINFO? |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 7295 Location: Australia
|
Posted: Tue Jan 22, 2008 1:07 am Post subject: |
|
|
Ha! The only problem with MENUBARINFO is this mysterious syntax:
| Code: | BOOL fBarFocused:1;
BOOL fFocused:1;
| fBarFocused and fFocused are bit fields. I'm not sure how I could generate code to access them, given that NumGet can get a minimum of one byte. |
|
| Back to top |
|
 |
Guest
|
Posted: Tue Jan 22, 2008 2:29 am Post subject: |
|
|
| lexikos wrote: | | I'm not sure how I could generate code to access them, given that NumGet can get a minimum of one byte. |
Although it could be retrieved using BitWise operators, I don't think it's worth the effort since BitFields are rarely found as you said, like archaic structures in DDE. What I was more concerned about was that the script output an (incorrect) size nevertheless, e.g., 36 which should be 32 for MENUBARINFO. Maybe better leave them to the users when BitFileds are involved. |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 7295 Location: Australia
|
Posted: Tue Jan 22, 2008 4:26 am Post subject: |
|
|
| Anonymous wrote: | What I was more concerned about was that the script output an (incorrect) size nevertheless, e.g., 36 which should be 32 for MENUBARINFO.
| StructParser will not successfully parse a bitfield. Although the size field of the Parse Error dialog defaults to 4 (edit: since this may give a false impression, it now has no default value), the very presence of the dialog indicates that the results may be incorrect. |
|
| Back to top |
|
 |
heresy
Joined: 11 Mar 2008 Posts: 291
|
Posted: Wed May 14, 2008 11:07 pm Post subject: |
|
|
wow Lexikos
why you didn't mention it to me when i was asking you Dllcall thing
this is definitely huge! especially for non-programmers like me
this helper MUST be documented in DllCall page of help file in my opinion
many thanks Lexikos
gratefully _________________ Easy WinAPI - Dive into Windows API World
Benchmark your AutoHotkey skills at PlayAHK.com |
|
| Back to top |
|
 |
Thrawn
Joined: 12 May 2008 Posts: 30 Location: Germany
|
Posted: Thu May 15, 2008 1:05 pm Post subject: |
|
|
Dude! Perfect!
Thx a lot. |
|
| Back to top |
|
 |
Azerty
Joined: 19 Dec 2006 Posts: 72 Location: France
|
Posted: Fri Aug 01, 2008 9:23 am Post subject: |
|
|
Thanks Lexicos
I went past it until now, but never too late
Good work _________________ Assembler-coded MCode.ahk ASCII85.ahk library |
|
| Back to top |
|
 |
Drugwash
Joined: 07 Sep 2008 Posts: 921 Location: Ploiesti, RO
|
Posted: Sun Sep 28, 2008 8:27 pm Post subject: |
|
|
Thank you for this script, Lexicos.
I've skimmed through the code but it's a bit over my head right now and I'd rather not mess with it.
Problem is, I got a few issues with certain structs.
First issue is about struct naming. The structs I've stumbled upon are all named by the trailing string at the end of the declaration (see MUUID below). I wonder, wouldn't it be better to just automatically parse the original name and use it in the output, as long as no struct name has been input in the edit field?
Currently, leaving that field blank will not even throw an error about an unnamed variable.
Then, first struct looks like this (as defined in the C header):
| Code: | typedef struct _MUUID {
unsigned long a;
unsigned short b;
unsigned short c;
unsigned char d[8];
} MUUID; |
The result should be:
ULong
UShort
UShort
UChar
UChar
UChar
UChar
UChar
UChar
UChar
UChar
however the script's output is:
| Code: | ; typedef struct _MUUID {
NumPut(MUUID_a, MUUID, 0, "Int")
NumPut(MUUID_b, MUUID, 4, "Short")
NumPut(MUUID_c, MUUID, 6, "Short")
MUUID_d_ptr := &MUUID + 8, MUUID_d_type := "Char", MUUID_d_length := 8
; } |
As you can see, types don't match (the unsigned declaration is not considered) and the last 8 chars that could've been separate fields are all defined by a single pointer field. This output would be kinda hard to process when nested structs will be implemented. And I hope it will, because the next struct I need to parse does have the first one nested.
The second struct looks like this:
| Code: | typedef struct {
int cbSize;
char *shortName;
DWORD version;
char *description;
char *author;
char *authorEmail;
char *copyright;
char *homepage;
BYTE flags;
int replacesDefaultModule;
MUUID uuid;
} PLUGININFOEX; |
As you see, the previously defined MUUID struct is placed at the end of this struct and currently your script cannot correctly process it.
Finally, related to these structs, I'd need a little bit of help, since I'm not familiar with WinAPI, DllCalls, etc: how do I retrieve a string in AHK from a currently loaded dll, when I only have a pointer to that string (as you see, most values in the PLUGININFOEX struct are pointers to strings)?
Thank you in advance for any help. _________________ AHK tools by Drugwash |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 7295 Location: Australia
|
Posted: Sun Sep 28, 2008 9:49 pm Post subject: |
|
|
| Drugwash wrote: | Currently, leaving that field blank will not even throw an error about an unnamed variable. | Why should it?
| Quote: | The result should be:
ULong | UInt.
| Quote: | | the last 8 chars that could've been separate fields are all defined by a single pointer field. | What if the array has 100000 elements? It is not practical to generate a field for each element. More code is needed to access a given element of the array. For instance:
| Code: | | item := NumGet(MUUID_d_ptr+index, 0, "uchar") |
| Quote: | As you see, the previously defined MUUID struct is placed at the end of this struct and currently your script cannot correctly process it. | Instead, you could replace the uuid field with a definition of the MUUID struct.
| Quote: | | how do I retrieve a string in AHK from a currently loaded dll, when I only have a pointer to that string (as you see, most values in the PLUGININFOEX struct are pointers to strings)? | Use the Str return type. For instance,
| Code: | | str := DllCall("MulDiv","int",ptr,"int",1,"int",1,"str") | MulDiv(x,1,1) returns x unmodified, but AutoHotkey interprets it as a string.
I don't intend to maintain this script. I may rewrite it, but not soon. |
|
| Back to top |
|
 |
Drugwash
Joined: 07 Sep 2008 Posts: 921 Location: Ploiesti, RO
|
Posted: Sun Sep 28, 2008 11:01 pm Post subject: |
|
|
| Lexikos wrote: | | Drugwash wrote: | Currently, leaving that field blank will not even throw an error about an unnamed variable. | Why should it? | Because the resulting struct will be unnamed otherwise and any originally unnamed members will look like _a, _b, etc - not so elegant IMHO.
| Quote: | | Quote: | The result should be:
ULong | UInt. | Semantics. The idea was the missing U.
| Quote: | | Quote: | | the last 8 chars that could've been separate fields are all defined by a single pointer field. | What if the array has 100000 elements? It is not practical to generate a field for each element. More code is needed to access a given element of the array. For instance:
| Code: | | item := NumGet(MUUID_d_ptr+index, 0, "uchar") |
| True. Could this output type be user-configurable, then?
| Quote: | | Quote: | As you see, the previously defined MUUID struct is placed at the end of this struct and currently your script cannot correctly process it. | Instead, you could replace the uuid field with a definition of the MUUID struct. | That structure is taken directly from the C header, unmodified. The idea would be that at some point, this script could parse such header and retrieve any given struct (nested structs included) without (major) user intervention.
| Quote: | | Quote: | | how do I retrieve a string in AHK from a currently loaded dll, when I only have a pointer to that string (as you see, most values in the PLUGININFOEX struct are pointers to strings)? | Use the Str return type. For instance,
| Code: | | str := DllCall("MulDiv","int",ptr,"int",1,"int",1,"str") | MulDiv(x,1,1) returns x unmodified, but AutoHotkey interprets it as a string. | I didn't quite get this one... I found something about lstrcpy but haven't gotten around putting it to work. | Quote: | | I don't intend to maintain this script. I may rewrite it, but not soon. | Too bad, would've been of real help. Maybe I'll fiddle with it locally, time and knowledge allowing.
Thank you for replying.
[EDIT]
Calling MulDiv throws an invalid page fault error.  _________________ AHK tools by Drugwash |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 7295 Location: Australia
|
Posted: Mon Sep 29, 2008 7:46 am Post subject: |
|
|
| Drugwash wrote: | | The idea would be that at some point, this script could parse such header and retrieve any given struct (nested structs included) without (major) user intervention. | StructParser was originally a small tool I hacked up to parse the DEVMODE structure. Rather than waste time adding features to it, I plan to write I proper header-parser. This would parse everything in the header file, allowing a script to get whatever information it needs.
| Drugwash wrote: | | Because the resulting struct will be unnamed otherwise and any originally unnamed members will look like _a, _b, etc - not so elegant IMHO. | If you leave the default name, "struct", no prefix is included in the output variable names (except for arrays, oops). If you specifically delete the name, you get invalid code like NumGet(, 0, "Int").
The name prefix is intended to be the kind of name you'd give a variable, not necessarily the name of the structure. For instance, a POINT structure representing the mouse position could be named mouse_pos, so StructParser would generate mouse_pos_x and mouse_pos_y.
That said, it has occurred to me that deriving the default name from the struct definition would be more intuitive. I do not use the generated variable names, so this was never a priority.
| Quote: | | True. Could this output type be user-configurable, then? | I don't see why not.
| Quote: | | Calling MulDiv throws an invalid page fault error. | Only if you pass it an invalid pointer or pointer to an invalid string (i.e. one that is not null-terminated.).
| Code: | var = hello
ptr := &var
MsgBox % DllCall("MulDiv","int",ptr,"int",1,"int",1,"str") |
|
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|