Any mpc-hc/_struct users can take a look at this api?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
hachi
Posts: 15
Joined: 16 Jan 2017, 19:29

Any mpc-hc/_struct users can take a look at this api?

21 Oct 2017, 14:11

My goal with this app is to send a copydata struct for custom OSD messages through class _struct.

The relevant data types in MpcApi.h looks like this,

Code: Select all

struct MPC_OSDDATA {
    int nMsgPos;       // screen position constant (see OSD_MESSAGEPOS constants)
    int nDurationMS;   // duration in milliseconds
    TCHAR strMsg[128]; // message to display in OSD
};
//// MPC_OSDDATA.nMsgPos constants (for host side programming):
/*typedef enum {
    OSD_NOMESSAGE,
    OSD_TOPLEFT,
    OSD_TOPRIGHT
} OSD_MESSAGEPOS;*/
I'm also using this python api example for reference. My effort to construct a valid message in ahk,

Code: Select all

#include <_struct>
hhwnd := a_scripthwnd + 0
mpch := "", CMD_OSDSHOWMESSAGE := 0xA0005000

run mpc-hc64.exe /new /slave %hhwnd%,,, mpid	; file must be loaded for OSD to show
winwait ahk_pid %mpid%
mpch := winexist("ahk_pid" . mpid)
return

copydata(hwnd, dwData, byref lpData) {
	VarSetCapacity(CopyData, 3*A_PtrSize, 0)
	size := (StrLen(lpData) + 1) * (A_IsUnicode ? 2 : 1)
	NumPut(size, CopyData, A_PtrSize)
	NumPut(dwData, CopyData, 0, "Ptr")
	NumPut(&lpData, CopyData, 2*A_PtrSize)

	SendMessage, 0x4a,, &CopyData,, ahk_id %hwnd%
	return ErrorLevel
}

struct(nMsgPos, nDurationMS, strMsg) {
	obj := new _struct("int nMsgPos, int nDurationMS, tchar strMsg[128]")
	obj.nMsgPos := nMsgPos, obj.nDurationMS := nDurationMS, obj.strMsg := strMsg
	return obj[""]
}

f1::copydata(mpch, CMD_OSDSHOWMESSAGE, struct(1, 1000, "test"))
mpc receives the message and activates the display, but none of the elements are being read properly. Instead of a 1s test string in the top left corner, it shows 4 random digits I can't really tell the meaning of, in the top right that does not obey this duration either. Any ideas?
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Any mpc-hc/_struct users can take a look at this api?

21 Oct 2017, 14:21

I wrote this AutoHotkey example:

winapi - media player classic - jump to point in video/audio programmatically - Stack Overflow
https://stackoverflow.com/questions/413 ... mmatically

Which may be useful as a template.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
hachi
Posts: 15
Joined: 16 Jan 2017, 19:29

Re: Any mpc-hc/_struct users can take a look at this api?

21 Oct 2017, 15:02

thank you, both yours and the autoit script looks like they're doing the same here. the difference being this MPC_OSDDATA structure needed for the display, my alignment is off and I have no idea why, maybe I'm using this class wrong. the mpc docs are also kind of confusing on this, do we actually need the struct or just a pipe delimited string? I have tried both ways, and they both yield an osd message... just not one that respects any of these params or decodes the string properly.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Any mpc-hc/_struct users can take a look at this api?

21 Oct 2017, 15:22

I would prepare the struct like this:

Code: Select all

vSize := 8 + (128 << !!A_IsUnicode)
VarSetCapacity(MPC_OSDDATA, vSize, 0)
NumPut(vPosType, &MPC_OSDDATA, 0, "Int")
NumPut(vDuration, &MPC_OSDDATA, 4, "Int")
StrPut(vText, &MPC_OSDDATA+8, 128)
Last edited by jeeswg on 21 Oct 2017, 16:12, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Any mpc-hc/_struct users can take a look at this api?

21 Oct 2017, 15:41

NumPut(size, CopyData, A_PtrSize) -> NumPut(size, CopyData, A_PtrSize, "uint") on 64 bit.

Cheers
Edit: @ jeeswg, VarSetCapacity(vOutput, MPC_OSDDATA, vSize) -> VarSetCapacity(MPC_OSDDATA,vSize) ?
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Any mpc-hc/_struct users can take a look at this api?

21 Oct 2017, 16:23

@Helgef: fixed.

From:
list of structs with parameters (sizes and types) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=7&t=30497

Code: Select all

;;COPYDATASTRUCT=24:12

		typedef struct tagCOPYDATASTRUCT {
0:0, "UPtr"	  ULONG_PTR dwData;
8:4, "UInt"	  DWORD     cbData;
16:8, "Ptr"	  PVOID     lpData;
		} COPYDATASTRUCT, *PCOPYDATASTRUCT;
24:12
That function that I was using to Send, looks like it isn't x64 compatible. I will fix the code at Stack Overflow at some point ... I intend to do a Media Player Classic tutorial.

When using old scripts that don't work, it's often best to test them in AHK x32, for which they were originally designed.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
hachi
Posts: 15
Joined: 16 Jan 2017, 19:29

Re: Any mpc-hc/_struct users can take a look at this api?

21 Oct 2017, 17:18

jeeswg wrote:I would prepare the struct like this:
that was my first approach, the position param is accepted, though not duration or string this way, the offsets are still wrong somehow
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Any mpc-hc/_struct users can take a look at this api?

22 Oct 2017, 23:19

I tried your script but I don't see anything.
- What version of Media Player Classic is required to run it? What version do you use?
- Does a separate window pop up? Do you have a screenshot with your partial success?
- What OS do you use?
- What version of AHK do you use? x64/x32. Cheers.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
hachi
Posts: 15
Joined: 16 Jan 2017, 19:29

Re: Any mpc-hc/_struct users can take a look at this api?

23 Oct 2017, 22:54

it is the latest stable x64, 1.7.13 on win7. make sure a file is loaded, the OSD overlay doesn't show without some type of active renderer
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Any mpc-hc/_struct users can take a look at this api?

24 Oct 2017, 00:12

This line might be a problem:
size := (StrLen(lpData) + 1) * (A_IsUnicode ? 2 : 1)
What is the value of size?

I still can't get the script to work, if I could, perhaps I could work out something.
- The script you posted works as is, to show some kind of rectangle in the top-right corner, over part of the video?
- What do you mean by 'active renderer', do you have some examples?
- Is there something inherent in Media Player Classic that uses the OSD to know what it should look like?
- Btw what is your overall goal? In case there are workarounds, but I'll still try and fix it.

[EDIT:] So you state that you have had partial success? You can at least get the first parameter to work?
- Rewrite the script without using the _Struct library, and see if you can get that same level of partial success without the library. Then post that script.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
hachi
Posts: 15
Joined: 16 Jan 2017, 19:29

Re: Any mpc-hc/_struct users can take a look at this api?

24 Oct 2017, 08:07

jeeswg wrote:- Is there something inherent in Media Player Classic that uses the OSD to know what it should look like?
every interaction you would expect feedback from. it sounds like you have this disabled, there's a toggle in the player options panel.
What is the value of size?
this is the cbdata value as per msdn. you have a pretty much identical assignment in your stackoverflow post.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Any mpc-hc/_struct users can take a look at this api?

24 Oct 2017, 09:17

I took another look, please try this,

Code: Select all

hhwnd := a_scripthwnd +0
mpch := "", CMD_OSDSHOWMESSAGE := 0xA0005000
ctr:=0
run mpc-hc64.exe /new /slave %hhwnd%,,, mpid	; file must be loaded for OSD to show
winwait ahk_pid %mpid%
mpch := winexist("ahk_pid" . mpid)
return

copydata(hwnd, dwData, size, byref lpData) {
	VarSetCapacity(CopyData, 3*A_PtrSize, 0)
	NumPut(dwData, CopyData, 0, "Ptr")
	NumPut(size, CopyData, A_PtrSize, "uint")
	NumPut(&lpData, CopyData, 2*A_PtrSize)

	SendMessage, 0x4a,, &CopyData,, ahk_id %hwnd%
	return ErrorLevel
}

MPC_OSDDATA(pos, dur, txt, byref lpData){
	size :=(strlen(txt)+1)*(A_IsUnicode?2:1)+8
	VarSetCapacity(lpData, size, 0)
	NumPut(pos, lpData, 0, "Int")
	NumPut(dur, lpData, 4, "Int")
	StrPut(txt, &lpData+8)
	return size
}

f1::
	pos := 1
	duration := 1000
	text:= "Hello: " (++ctr) "."
	size := MPC_OSDDATA(pos, duration, text, lpData)
	copydata(mpch, CMD_OSDSHOWMESSAGE, size, lpData)
return
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Any mpc-hc/_struct users can take a look at this api?

24 Oct 2017, 12:51

OK, there are options here to turn it on:
View, Options...,
Player, Other, Show OSD (requires restart)

I've basically changed &lpData to lpData, and changed how size is calculated.

This is a minimal fix to get it working:

Code: Select all

#include <_struct>
hhwnd := a_scripthwnd + 0
mpch := "", CMD_OSDSHOWMESSAGE := 0xA0005000

run mpc-hc64.exe /new /slave %hhwnd%,,, mpid	; file must be loaded for OSD to show
winwait ahk_pid %mpid%
mpch := winexist("ahk_pid" . mpid)
return

copydata(hwnd, dwData, lpData) {
	VarSetCapacity(CopyData, 3*A_PtrSize, 0)
	size := 8 + 128 * (A_IsUnicode ? 2 : 1)
	NumPut(dwData, CopyData, 0, "UPtr")
	NumPut(size, CopyData, A_PtrSize, "UInt")
	NumPut(lpData, CopyData, 2*A_PtrSize, "Ptr")

	SendMessage, 0x4a,, &CopyData,, ahk_id %hwnd%
	return ErrorLevel
}

struct(nMsgPos, nDurationMS, strMsg) {
	obj := new _struct("int nMsgPos, int nDurationMS, tchar strMsg[128]")
	obj.nMsgPos := nMsgPos, obj.nDurationMS := nDurationMS, obj.strMsg := strMsg
	return obj[""]
}

f1::copydata(mpch, CMD_OSDSHOWMESSAGE, struct(1, 1000, "test"))
I had never used OSD before, it's quite nice, you get a little dark grey box with white text in the top-left corner, that notifies you when you play/pause or change the volume etc. The problem is that the Pause message stays for a while.

==================================================

I actually wrote something myself, to notify me when I change the volume using the Progress command. I don't personally want notifications for anything else.

Code: Select all

~Up:: ;media player classic - display - notify when change volume
~Down:: ;media player classic - display - notify when change volume
if WinExist("ahk_class #32768")
	return
ControlGetFocus, vCtlClassNN, A
if (vCtlClassNN = "SysListView322")
	return
if (A_TimeIdle > 200)
	return
Loop, 3
{
	SendMessage, 0x400, 0, 0, msctls_trackbar321, A ;TBM_GETPOS := 0x400
	vNum := ErrorLevel
	if (vNum = "FAIL") || (vNum = "ERROR")
		break
	else if (A_Index = 1)
		Progress, zh0 b fs18 w56, % vNum
	else if !(A_Index = 1) && !(vNum = vNum2)
		Progress, zh0 b fs18 w56, % vNum
	Sleep, 100
	vNum2 := vNum
}
Progress, Off
return
Btw Helgef, are you a fan of Media Player Classic?
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Any mpc-hc/_struct users can take a look at this api?

24 Oct 2017, 13:12

Btw Helgef, are you a fan of Media Player Classic?
Hello jeeswg :wave: Yes.
This is a minimal fix to get it working:
That will not work jeeswg. The most relevant mistake is in the function struct(), fixing the size is also important ofc. Changing &lpData to lpData shouldn't be done based on guessing. You can do it, but why did you? Both of you would benefit from working out the issue here.
I attach _struct (and sizeof) if someone wants to tinker with it,

Code: Select all


;: Title: _Struct by HotKeyIt
;

; Function: _Struct
; Description:
;      _Struct is based on AHK_L objects and supports both, ANSI and UNICODE version. To use it you will require <a href=http://www.autohotkey.com/forum/viewtopic.php?t=43049>Lexikos AutoHotkey_L.exe</a> or other versions based on it.<br><br>new _Struct is used to create new structure. A structure must be defined as a global variable or an item of global class (e.g. "MyClass.Struct").<br>_Struct can handle structure in structure as well as Arrays of structures and Vectors.<br>Visit <a href=http://www.autohotkey.com/forum/viewtopic.php?t=43049>_Struct on AutoHotkey</a> forum, any feedback is welcome.
; Syntax: MyStruct:= new _Struct(Structure_Definition,Address,initialization)
; Parameters:
;	   General Design - Class _Struct will create Object(s) that will manage fields of structure(s), for example<br>left,top,right,bottom<br>RC := new _Struct("RECT")<br>will create a RECT structure with fields left,top,right,bottom of type UInt. To pass the structure its pointer to a function, DllCall or SendMessage use RC[""].<br><br>To access fields you can use usual Object syntax: RC.left, RC.right ...<br>To set a field of the structure use RC.top := 100.
;	   Field types - Following AutoHotkey and Windows Data Types are supported:<br><br>AutoHotkey Data Types:<br>Int, Uint, Int64, UInt64, Char, UChar, Short, UShort, Fload and Double.<br><br>Windows Data Types:<br>ATOM,BOOL,BOOLEAN,BYTE,CHAR,COLORREF,DWORD,DWORDLONG,DWORD_PTR,<br>DWORD32,DWORD64,FLOAT,HACCEL,HALF_PTR,HANDLE,HBITMAP,HBRUSH,HCOLORSPACE,HCONV,HCONVLIST,HCURSOR,HDC,<br>HDDEDATA,HDESK,HDROP,HDWP,HENHMETAFILE,HFILE,HFONT,HGDIOBJ,HGLOBAL,HHOOK,HICON,HINSTANCE,HKEY,HKL,<br>HLOCAL,HMENU,HMETAFILE,HMODULE,HMONITOR,HPALETTE,HPEN,HRESULT,HRGN,HRSRC,HSZ,HWINSTA,HWND,INT,<br>INT_PTR,INT32,INT64,LANGID,LCID,LCTYPE,LGRPID,LONG,LONGLONG,LONG_PTR,LONG32,LONG64,LPARAM,LPBOOL,<br>LPBYTE,LPCOLORREF,LPCSTR,LPCTSTR,LPCVOID,LPCWSTR,LPDWORD,LPHANDLE,LPINT,LPLONG,LPSTR,LPTSTR,LPVOID,<br>LPWORD,LPWSTR,LRESULT,PBOOL,PBOOLEAN,PBYTE,PCHAR,PCSTR,PCTSTR,PCWSTR,PDWORD,PDWORDLONG,PDWORD_PTR,<br>PDWORD32,PDWORD64,PFLOAT,PHALF_PTR,PHANDLE,PHKEY,PINT,PINT_PTR,PINT32,PINT64,PLCID,PLONG,PLONGLONG,<br>PLONG_PTR,PLONG32,PLONG64,POINTER_32,POINTER_64,POINTER_SIGNED,POINTER_UNSIGNED,PSHORT,PSIZE_T,<br>PSSIZE_T,PSTR,PTBYTE,PTCHAR,PTSTR,PUCHAR,PUHALF_PTR,PUINT,PUINT_PTR,PUINT32,PUINT64,PULONG,PULONGLONG,<br>PULONG_PTR,PULONG32,PULONG64,PUSHORT,PVOID,PWCHAR,PWORD,PWSTR,SC_HANDLE,SC_LOCK,SERVICE_STATUS_HANDLE,<br>SHORT,SIZE_T,SSIZE_T,TBYTE,TCHAR,UCHAR,UHALF_PTR,UINT,UINT_PTR,UINT32,UINT64,ULONG,ULONGLONG,<br>ULONG_PTR,ULONG32,ULONG64,USHORT,USN,WCHAR,WORD,WPARAM
;	   <b>Structure Definition</b> - <b>Description</b>
;	   User defined - To create a user defined structure you will need to pass a string of predefined types and field names.<br>Default type is UInt, so for example for a RECT structure type can be omited: <b>"left,top,right,left"</b>, which is the same as <b>"Uint left,Uint top,Uint right,Uint bottom"</b><br><br>You can also use structures very similar to C#/C++ syntax, see example.
;	   Global - Global variables can be used to save structures, easily pass name of that variable as first parameter, e.g. new _Struct("MyStruct") where MyStruct must be a global variable with structure definition. Also new _Struct(MyStruct) can be used if variable is accessible.
;	   Array - To create an array of structures include a digit in the end of your string enclosed in squared brackets.<br>For example "RECT[2]" would create an array of 2 structures.<br>This feature can also be used for user defined arrays, for example "Int age,TCHAR name[10]".
;	   Union - Using {} you can create union, for example: <br>_AHKVar:="{Int64 ContentsInt64,Double ContentsDouble,object},...
;	   Struct - Using struct{} you can create structures in union or in structures.
;	   Pointer - To create a pointer you can use *, for example: CHR:="char *str" will hold a pointer to a character. Same way you can have a structure in structure so you can call it recursive, for example Label.NextLabel.NextLabel.NextLabel.JumpToLine
;	   <b>Parameters</b> - <b>Description</b>
;	   MyStruct - This is a variable that will hold the object representing the strucuture which is returned by new _Struct(...).
;	   Structure_Definition - C/C++ syntax or one-line definition e.g. "Int x,Int y".
;	   pointer - Pass a pointer as second parameter to occupy existing strucure.
;	   Initialization - Pass an object to initialize structure, e.g. {left:100,top:20}. If pointer is not used initialization can be specified in second parameter.
;	   <b>Methods</b> - <b>Description</b>
;	   Strct.Type(itm) - Returns type of item or structure
;	   Strct.AhkType(itm) - Returns AHK type of item or structure to be used with NumGet and NumPut as well as DllCall
;	   Strct.Size() - Returns size of structure, same as sizeof(MyStruct)
;	   Strct.SizeT(itm) - Returns size of an item
;	   Strct.Offset(itm) - Returns offset for items
;	   Strct.Encoding(itm) - Returns encoding for items, to be used with StrGet and StrPut
;	   Strct.Alloc(itm,size[,ptrsize]) - Allocates memory in bytes, ptrsize is used to create pointers
;	   Strct.Capacity(itm) - Returns memory capacity for items.
;	   Strct.IsPointer(itm) - Returns whether the item is a pointer (defined using *).
; Return Value:
;     A class object representing your structure
; Remarks:
;		<b>NOTE!!! accessing a field that does not exist will cause recrusive calls and will crash your script, these errors are not catched for performance reasons.<br>TCHAR, UCHAR and CHAR return actual character rather than the value, use Asc() function to find out the value/code.
; Related:
; Example:
;		file:Struct_Example.ahk
;

Class _Struct {
	; Data Sizes
  static PTR:=A_PtrSize,UPTR:=A_PtrSize,SHORT:=2,USHORT:=2,INT:=4,UINT:=4,__int64:=8,INT64:=8,UINT64:=8,DOUBLE:=8,FLOAT:=4,CHAR:=1,UCHAR:=1,VOID:=A_PtrSize
    ,TBYTE:=A_IsUnicode?2:1,TCHAR:=A_IsUnicode?2:1,HALF_PTR:=A_PtrSize=8?4:2,UHALF_PTR:=A_PtrSize=8?4:2,INT32:=4,LONG:=4,LONG32:=4,LONGLONG:=8
    ,LONG64:=8,USN:=8,HFILE:=4,HRESULT:=4,INT_PTR:=A_PtrSize,LONG_PTR:=A_PtrSize,POINTER_64:=A_PtrSize,POINTER_SIGNED:=A_PtrSize
    ,BOOL:=4,SSIZE_T:=A_PtrSize,WPARAM:=A_PtrSize,BOOLEAN:=1,BYTE:=1,COLORREF:=4,DWORD:=4,DWORD32:=4,LCID:=4,LCTYPE:=4,LGRPID:=4,LRESULT:=4,PBOOL:=4
    ,PBOOLEAN:=A_PtrSize,PBYTE:=A_PtrSize,PCHAR:=A_PtrSize,PCSTR:=A_PtrSize,PCTSTR:=A_PtrSize,PCWSTR:=A_PtrSize,PDWORD:=A_PtrSize,PDWORDLONG:=A_PtrSize
    ,PDWORD_PTR:=A_PtrSize,PDWORD32:=A_PtrSize,PDWORD64:=A_PtrSize,PFLOAT:=A_PtrSize,PHALF_PTR:=A_PtrSize
    ,UINT32:=4,ULONG:=4,ULONG32:=4,DWORDLONG:=8,DWORD64:=8,ULONGLONG:=8,ULONG64:=8,DWORD_PTR:=A_PtrSize,HACCEL:=A_PtrSize,HANDLE:=A_PtrSize
    ,HBITMAP:=A_PtrSize,HBRUSH:=A_PtrSize,HCOLORSPACE:=A_PtrSize,HCONV:=A_PtrSize,HCONVLIST:=A_PtrSize,HCURSOR:=A_PtrSize,HDC:=A_PtrSize
    ,HDDEDATA:=A_PtrSize,HDESK:=A_PtrSize,HDROP:=A_PtrSize,HDWP:=A_PtrSize,HENHMETAFILE:=A_PtrSize,HFONT:=A_PtrSize
  static HGDIOBJ:=A_PtrSize,HGLOBAL:=A_PtrSize,HHOOK:=A_PtrSize,HICON:=A_PtrSize,HINSTANCE:=A_PtrSize,HKEY:=A_PtrSize,HKL:=A_PtrSize
    ,HLOCAL:=A_PtrSize,HMENU:=A_PtrSize,HMETAFILE:=A_PtrSize,HMODULE:=A_PtrSize,HMONITOR:=A_PtrSize,HPALETTE:=A_PtrSize,HPEN:=A_PtrSize
    ,HRGN:=A_PtrSize,HRSRC:=A_PtrSize,HSZ:=A_PtrSize,HWINSTA:=A_PtrSize,HWND:=A_PtrSize,LPARAM:=A_PtrSize,LPBOOL:=A_PtrSize,LPBYTE:=A_PtrSize
    ,LPCOLORREF:=A_PtrSize,LPCSTR:=A_PtrSize,LPCTSTR:=A_PtrSize,LPCVOID:=A_PtrSize,LPCWSTR:=A_PtrSize,LPDWORD:=A_PtrSize,LPHANDLE:=A_PtrSize
    ,LPINT:=A_PtrSize,LPLONG:=A_PtrSize,LPSTR:=A_PtrSize,LPTSTR:=A_PtrSize,LPVOID:=A_PtrSize,LPWORD:=A_PtrSize,LPWSTR:=A_PtrSize,PHANDLE:=A_PtrSize
    ,PHKEY:=A_PtrSize,PINT:=A_PtrSize,PINT_PTR:=A_PtrSize,PINT32:=A_PtrSize,PINT64:=A_PtrSize,PLCID:=A_PtrSize,PLONG:=A_PtrSize,PLONGLONG:=A_PtrSize
    ,PLONG_PTR:=A_PtrSize,PLONG32:=A_PtrSize,PLONG64:=A_PtrSize,POINTER_32:=A_PtrSize,POINTER_UNSIGNED:=A_PtrSize,PSHORT:=A_PtrSize,PSIZE_T:=A_PtrSize
    ,PSSIZE_T:=A_PtrSize,PSTR:=A_PtrSize,PTBYTE:=A_PtrSize,PTCHAR:=A_PtrSize,PTSTR:=A_PtrSize,PUCHAR:=A_PtrSize,PUHALF_PTR:=A_PtrSize,PUINT:=A_PtrSize
    ,PUINT_PTR:=A_PtrSize,PUINT32:=A_PtrSize,PUINT64:=A_PtrSize,PULONG:=A_PtrSize,PULONGLONG:=A_PtrSize,PULONG_PTR:=A_PtrSize,PULONG32:=A_PtrSize
    ,PULONG64:=A_PtrSize,PUSHORT:=A_PtrSize,PVOID:=A_PtrSize,PWCHAR:=A_PtrSize,PWORD:=A_PtrSize,PWSTR:=A_PtrSize,SC_HANDLE:=A_PtrSize
    ,SC_LOCK:=A_PtrSize,SERVICE_STATUS_HANDLE:=A_PtrSize,SIZE_T:=A_PtrSize,UINT_PTR:=A_PtrSize,ULONG_PTR:=A_PtrSize,ATOM:=2,LANGID:=2,WCHAR:=2,WORD:=2,USAGE:=2
	; Data Types
  static _PTR:="PTR",_UPTR:="UPTR",_SHORT:="Short",_USHORT:="UShort",_INT:="Int",_UINT:="UInt"
    ,_INT64:="Int64",_UINT64:="UInt64",_DOUBLE:="Double",_FLOAT:="Float",_CHAR:="Char",_UCHAR:="UChar"
    ,_VOID:="PTR",_TBYTE:=A_IsUnicode?"USHORT":"UCHAR",_TCHAR:=A_IsUnicode?"USHORT":"UCHAR",_HALF_PTR:=A_PtrSize=8?"INT":"SHORT"
    ,_UHALF_PTR:=A_PtrSize=8?"UINT":"USHORT",_BOOL:="Int",_INT32:="Int",_LONG:="Int",_LONG32:="Int",_LONGLONG:="Int64",_LONG64:="Int64"
    ,_USN:="Int64",_HFILE:="UInt",_HRESULT:="UInt",_INT_PTR:="PTR",_LONG_PTR:="PTR",_POINTER_64:="PTR",_POINTER_SIGNED:="PTR",_SSIZE_T:="PTR"
    ,_WPARAM:="PTR",_BOOLEAN:="UCHAR",_BYTE:="UCHAR",_COLORREF:="UInt",_DWORD:="UInt",_DWORD32:="UInt",_LCID:="UInt",_LCTYPE:="UInt"
    ,_LGRPID:="UInt",_LRESULT:="UInt",_PBOOL:="UPTR",_PBOOLEAN:="UPTR",_PBYTE:="UPTR",_PCHAR:="UPTR",_PCSTR:="UPTR",_PCTSTR:="UPTR"
    ,_PCWSTR:="UPTR",_PDWORD:="UPTR",_PDWORDLONG:="UPTR",_PDWORD_PTR:="UPTR",_PDWORD32:="UPTR",_PDWORD64:="UPTR",_PFLOAT:="UPTR",___int64:="Int64"
    ,_PHALF_PTR:="UPTR",_UINT32:="UInt",_ULONG:="UInt",_ULONG32:="UInt",_DWORDLONG:="UInt64",_DWORD64:="UInt64",_ULONGLONG:="UInt64"
    ,_ULONG64:="UInt64",_DWORD_PTR:="UPTR",_HACCEL:="UPTR",_HANDLE:="UPTR",_HBITMAP:="UPTR",_HBRUSH:="UPTR",_HCOLORSPACE:="UPTR"
    ,_HCONV:="UPTR",_HCONVLIST:="UPTR",_HCURSOR:="UPTR",_HDC:="UPTR",_HDDEDATA:="UPTR",_HDESK:="UPTR",_HDROP:="UPTR",_HDWP:="UPTR"
  static _HENHMETAFILE:="UPTR",_HFONT:="UPTR",_HGDIOBJ:="UPTR",_HGLOBAL:="UPTR",_HHOOK:="UPTR",_HICON:="UPTR",_HINSTANCE:="UPTR",_HKEY:="UPTR"
    ,_HKL:="UPTR",_HLOCAL:="UPTR",_HMENU:="UPTR",_HMETAFILE:="UPTR",_HMODULE:="UPTR",_HMONITOR:="UPTR",_HPALETTE:="UPTR",_HPEN:="UPTR"
    ,_HRGN:="UPTR",_HRSRC:="UPTR",_HSZ:="UPTR",_HWINSTA:="UPTR",_HWND:="UPTR",_LPARAM:="UPTR",_LPBOOL:="UPTR",_LPBYTE:="UPTR",_LPCOLORREF:="UPTR"
    ,_LPCSTR:="UPTR",_LPCTSTR:="UPTR",_LPCVOID:="UPTR",_LPCWSTR:="UPTR",_LPDWORD:="UPTR",_LPHANDLE:="UPTR",_LPINT:="UPTR",_LPLONG:="UPTR"
    ,_LPSTR:="UPTR",_LPTSTR:="UPTR",_LPVOID:="UPTR",_LPWORD:="UPTR",_LPWSTR:="UPTR",_PHANDLE:="UPTR",_PHKEY:="UPTR",_PINT:="UPTR"
    ,_PINT_PTR:="UPTR",_PINT32:="UPTR",_PINT64:="UPTR",_PLCID:="UPTR",_PLONG:="UPTR",_PLONGLONG:="UPTR",_PLONG_PTR:="UPTR",_PLONG32:="UPTR"
    ,_PLONG64:="UPTR",_POINTER_32:="UPTR",_POINTER_UNSIGNED:="UPTR",_PSHORT:="UPTR",_PSIZE_T:="UPTR",_PSSIZE_T:="UPTR",_PSTR:="UPTR"
    ,_PTBYTE:="UPTR",_PTCHAR:="UPTR",_PTSTR:="UPTR",_PUCHAR:="UPTR",_PUHALF_PTR:="UPTR",_PUINT:="UPTR",_PUINT_PTR:="UPTR",_PUINT32:="UPTR"
    ,_PUINT64:="UPTR",_PULONG:="UPTR",_PULONGLONG:="UPTR",_PULONG_PTR:="UPTR",_PULONG32:="UPTR",_PULONG64:="UPTR",_PUSHORT:="UPTR"
    ,_PVOID:="UPTR",_PWCHAR:="UPTR",_PWORD:="UPTR",_PWSTR:="UPTR",_SC_HANDLE:="UPTR",_SC_LOCK:="UPTR",_SERVICE_STATUS_HANDLE:="UPTR"
  static _SIZE_T:="UPTR",_UINT_PTR:="UPTR",_ULONG_PTR:="UPTR",_ATOM:="Ushort",_LANGID:="Ushort",_WCHAR:="Ushort",_WORD:="UShort",_USAGE:="UShort"
    
  ; Following is used internally only to simplify setting field helpers
  ; the corresponding key can be set to invalid type (for string integer and vice versa) to set default if necessary, e.g. ___InitField(N,"")
  ___InitField(_this,N,offset=" ",encoding=0,AHKType=0,isptr=" ",type=0,arrsize=0,memory=0){ ; N = Name of field
    static _prefixes_:={offset:"`b",isptr:"`r",AHKType:"`n",type:"`t",encoding:"`f",memory:"`v",arrsize:" "}
          ,_testtype_:={offset:"integer",isptr:"integer",AHKType:"string",type:"string",encoding:"string",arrsize:"integer"}
          ,_default_:={offset:0,isptr:0,AHKType:"UInt",type:"UINT",encoding:"CP0",memory:"",arrsize:1}
    for _key_,_value_ in _prefixes_
    {
      _typevalid_:=0
      If (_testtype_[_key_]="Integer"){
        If %_key_% is integer
          useDefault:=1,_typevalid_:=1
        else if !_this.HasKey(_value_ N)
          useDefault:=1
      } else {
        If %_key_% is not integer
          useDefault:=1,_typevalid_:=1
        else if !_this.HasKey(_value_ N)
          useDefault:=1
      }
      If (useDefault) ; item does not exist or user supplied a valid type
        If (_key_="encoding")
          _this[_value_ N]:=_typevalid_?(InStr(",LPTSTR,LPCTSTR,TCHAR,","," %_key_% ",")?(A_IsUnicode?"UTF-16":"CP0")
                                        :InStr(",LPWSTR,LPCWSTR,WCHAR,","," %_key_% ",")?"UTF-16":"CP0")
                                      :_default_[_key_]
        else {
          _this[_value_ N]:=_typevalid_?%_key_%:_default_[_key_]
         }
    }
  }
  
  ; Struct Contstructor
  ; Memory, offset and definitions are saved in following character + given key/name
  ;   `a = Allocated Memory
  ;   `b = Byte Offset (related to struct address)
  ;   `f = Format (encoding for string data types)
  ;   `n = New data type (AHK data type)
  ;   `r = Is Pointer (requred for __GET and __SET)
  ;   `t = Type (data type, also when it is name of a Structure it is used to resolve structure pointers dynamically
  ;   `v = Memory used to save string and pointer memory
  __NEW(_TYPE_,_pointer_=0,_init_=0){
    static _base_:={__GET:_Struct.___GET,__SET:_Struct.___SET,__SETPTR:_Struct.___SETPTR,__Clone:_Struct.___Clone,__NEW:_Struct.___NEW
          ,IsPointer:_Struct.IsPointer,Offset:_Struct.Offset,Type:_Struct.Type,AHKType:_Struct.AHKType,Encoding:_Struct.Encoding
          ,Capacity:_Struct.Capacity,Alloc:_Struct.Alloc,Size:_Struct.Size,SizeT:_Struct.SizeT,Print:_Struct.Print,ToObj:_Struct.ToObj}
		local _,_ArrType_,_ArrName_:="",_ArrSize_,_align_total_,_defobj_,_IsPtr_,_key_,_LF_,_LF_BKP_,_match_,_offset_:=""
			,_struct_,_StructSize_,_total_union_size_,_union_,_union_size_,_value_,_mod_,_max_size_,_in_struct_,_struct_align_
		
		If (RegExMatch(_TYPE_,"^[\w\d\._]+$") && !_Struct.HasKey(_TYPE_)){ ; structures name was supplied, resolve to global var and run again
      If InStr(_TYPE_,"."){ ;check for object that holds structure definition
        Loop,Parse,_TYPE_,.
          If A_Index=1
            _defobj_:=%A_LoopField%
          else _defobj_:=_defobj_[A_LoopField]
        _TYPE_:=_defobj_
      } else _TYPE_:=%_TYPE_%,_defobj_:=""
    } else _defobj_:=""
    ; If a pointer is supplied, save it in key [""] else reserve and zero-fill memory + set pointer in key [""]
    If (_pointer_ && !IsObject(_pointer_))
      this[""] := _pointer_,this["`a"]:=0,this["`a`a"]:=sizeof(_TYPE_)
    else
      this._SetCapacity("`a",_StructSize_:=sizeof(_TYPE_)) ; Set Capacity in key ["`a"]
      ,this[""]:=this._GetAddress("`a") ; Save pointer in key [""]
      ,DllCall("RtlZeroMemory","UPTR",this[""],"UInt",this["`a`a"]:=_StructSize_) ; zero-fill memory
    ; C/C++ style structure definition, convert it
    If InStr(_TYPE_,"`n") {
      _struct_:=[] ; keep track of structures (union is just removed because {} = union, struct{} = struct
      _union_:=0   ; init to 0, used to keep track of union depth
      Loop,Parse,_TYPE_,`n,`r`t%A_Space%%A_Tab% ; Parse each line
      {
        _LF_:=""
        Loop,Parse,A_LoopField,`,`;,`t%A_Space%%A_Tab% ; Parse each item
        {
          If RegExMatch(A_LoopField,"^\s*//") ;break on comments and continue main loop
              break
          If (A_LoopField){ ; skip empty lines
              If (!_LF_ && _ArrType_:=RegExMatch(A_LoopField,"[\w\d_#@]\s+[\w\d_#@]")) ; new line, find out data type and save key in _LF_ Data type will be added later
                _LF_:=RegExReplace(A_LoopField,"[\w\d_#@]\K\s+.*$")
              If Instr(A_LoopField,"{"){ ; Union, also check if it is a structure
                _union_++,_struct_.Insert(_union_,RegExMatch(A_LoopField,"i)^\s*struct\s*\{"))
              } else If InStr(A_LoopField,"}") ; end of union/struct
                _offset_.="}"
              else { ; not starting or ending struct or union so add definitions and apply Data Type.
                If _union_ ; add { or struct{
                    Loop % _union_
                      _ArrName_.=(_struct_[A_Index]?"struct":"") "{"
                _offset_.=(_offset_ ? "," : "") _ArrName_ ((_ArrType_ && A_Index!=1)?(_LF_ " "):"") RegExReplace(A_LoopField,"\s+"," ")
                ,_ArrName_:="",_union_:=0
              }
          }
        }
      }
      _TYPE_:=_offset_
    }

    _offset_:=0                 
    ,_union_:=[]                 ; keep track of union level, required to reset offset after union is parsed
    ,_struct_:=[]                ; for each union level keep track if it is a structure (because here offset needs to increase
    ,_union_size_:=[]            ; keep track of highest member within the union or structure, used to calculate new offset after union
    ,_struct_align_:=[]          ; keep track of alignment before structure
    ,_total_union_size_:=0       ; used in combination with above, each loop the total offset is updated if current data size is higher
    ,_align_total_:=0			; used to calculate alignment for total size of structure
	,_in_struct_:=1
    
    ,this["`t"]:=0,this["`r"]:=0 ; will identify a Structure Pointer without members

    ; Parse given structure definition and create struct members
    ; User structures will be resolved by recrusive calls (!!! a structure must be a global variable)
    Loop,Parse,_TYPE_,`,`; ;,%A_Space%%A_Tab%`n`r
    {
      _in_struct_+=StrLen(A_LoopField)+1
      If ("" = _LF_ := trim(A_LoopField,A_Space A_Tab "`n`r"))
        continue
      _LF_BKP_:=_LF_ ;to check for ending brackets = union,struct
      _IsPtr_:=0
      ; Check for STARTING union and set union helpers
       While (_match_:=RegExMatch(_LF_,"i)^(struct|union)?\s*\{\K"))
      ; correct offset for union/structure, sizeof_maxsize returns max size of union or structure
        _max_size_:=sizeof_maxsize(SubStr(_TYPE_,_in_struct_-StrLen(A_LoopField)-1+(StrLen(_LF_BKP_)-StrLen(_LF_))))
        ,_union_.Insert(_offset_+=(_mod_:=Mod(_offset_,_max_size_))?Mod(_max_size_-_mod_,_max_size_):0)
        ,_union_size_.Insert(0)
        ,_struct_align_.Insert(_align_total_>_max_size_?_align_total_:_max_size_)
        ,_struct_.Insert(RegExMatch(_LF_,"i)^struct\s*\{")?(1,_align_total_:=0):0)
        ,_LF_:=SubStr(_LF_,_match_)

      StringReplace,_LF_,_LF_,},,A ;remove all closing brackets (these will be checked later)
      
      ; Check if item is a pointer and remove * for further processing, separate key will store that information
      While % (InStr(_LF_,"*")){
        StringReplace,_LF_,_LF_,*
        _IsPtr_:=A_Index
      }
      ; Split off data type, name and size (only data type is mandatory)
      RegExMatch(_LF_,"^(?<ArrType_>[\w\d\._]+)?\s*(?<ArrName_>[\w\d_]+)?\s*\[?(?<ArrSize_>\d+)?\]?\s*\}*\s*$",_)
      If (!_ArrName_ && !_ArrSize_){
        If RegExMatch(_TYPE_,"^\**" _ArrType_ "\**$"){
          _Struct.___InitField(this,"",0,_ArrType_,_IsPtr_?"PTR":_Struct.HasKey("_" _ArrType_)?_Struct["_" _ArrType_]:"PTR",_IsPtr_,_ArrType_)
          this.base:=_base_
          If (IsObject(_init_)||IsObject(_pointer_)){ ; Initialization of structures members, e.g. _Struct(_RECT,{left:10,right:20})
            for _key_,_value_ in IsObject(_init_)?_init_:_pointer_
            {
              If !this["`r"]{ ; It is not a pointer, assign value
                If InStr(",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR,","," this["`t" _key_] ",")
                  this.Alloc(_key_,StrLen(_value_)*(InStr(".LPWSTR,LPCWSTR,","," this["`t"] ",")||(InStr(",LPTSTR,LPCTSTR,","," this["`t" _key_] ",")&&A_IsUnicode)?2:1))
                if InStr(",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR,CHAR,TCHAR,WCHAR,","," this["`t" _key_] ",")
                  this[_key_]:=_value_
                else 
                  this[_key_] := _value_
              }else if (_value_<>"") ; It is not empty
                If _value_ is integer ; It is a new pointer
                  this[_key_][""]:=_value_
            }
          }
          Return this ;:= new _Struct(%_ArrType_%,_pointer_)   ;only Data type was supplied, object/structure has got no members/keys
        } else
          _ArrName_:=_ArrType_,_ArrType_:="UInt"
      }
      If InStr(_ArrType_,"."){ ;check for object that holds structure definition
        Loop,Parse,_ArrType_,.
          If A_Index=1
            _defobj_:=%A_LoopField%
          else _defobj_:=_defobj_[A_LoopField]
      }
      if (!_IsPtr_ && !_Struct.HasKey(_ArrType_)){  ; _ArrType_ not found resolve to global variable (must contain struct definition)
        if (sizeof(_defobj_?_defobj_:%_ArrType_%,0,_align_total_) && mod:=Mod(_offset_,_align_total_))
          _offset_+=Mod(_align_total_-_mod_,_align_total_)
        _Struct.___InitField(this,_ArrName_,_offset_,_ArrType_,0,0,_ArrType_,_ArrSize_)
        ; update current union size
        If (_uix_:=_union_.MaxIndex()) && (_max_size_:=_offset_ + sizeof(_defobj_?_defobj_:%_ArrType_%) - _union_[_uix_])>_union_size_[_uix_]
          _union_size_[_uix_]:=_max_size_
        _max_size:=0
        ; if not a union or a union + structure then offset must be moved (when structure offset will be reset below
        If (!_uix_||_struct_[_struct_.MaxIndex()])
          _offset_+=this[" " _ArrName_]*sizeof(_defobj_?_defobj_:%_ArrType_%) ; move offset
        ;Continue
      } else {
        If ((_IsPtr_ || _Struct.HasKey(_ArrType_)))
          _offset_+=(_mod_:=Mod(_offset_,_max_size_:=_IsPtr_?A_PtrSize:_Struct[_ArrType_]))=0?0:(_IsPtr_?A_PtrSize:_Struct[_ArrType_])-_mod_
          ,_align_total_:=_max_size_>_align_total_?_max_size_:_align_total_
          ,_Struct.___InitField(this,_ArrName_,_offset_,_ArrType_,_IsPtr_?"PTR":_Struct.HasKey(_ArrType_)?_Struct["_" _ArrType_]:_ArrType_,_IsPtr_,_ArrType_,_ArrSize_)
        ; update current union size
        If (_uix_:=_union_.MaxIndex()) && (_max_size_:=_offset_ + _Struct[this["`n" _ArrName_]] - _union_[_uix_])>_union_size_[_uix_]
          _union_size_[_uix_]:=_max_size_
        _max_size_:=0
        ; if not a union or a union + structure then offset must be moved (when structure offset will be reset below
        If (!_uix_||_struct_[_uix_])
          _offset_+=_IsPtr_?A_PtrSize:(_Struct.HasKey(_ArrType_)?_Struct[_ArrType_]:%_ArrType_%)*this[" " _ArrName_]
      }
      ; Check for ENDING union and reset offset and union helpers
      While (SubStr(_LF_BKP_,0)="}"){
        If (!_uix_:=_union_.MaxIndex()){
          MsgBox,0, Incorrect structure, missing opening braket {`nProgram will exit now `n%_TYPE_%
          ExitApp
        } ; Increase total size of union/structure if necessary
        ; reset offset and align because we left a union or structure
        if (_uix_>1 && _struct_[_uix_-1]){
          if (_mod_:=Mod(_offset_,_struct_align_[_uix_]))
          _offset_+=Mod(_struct_align_[_uix_]-_mod_,_struct_align_[_uix_])
        } else _offset_:=_union_[_uix_]
        if (_struct_[_uix_]&&_struct_align_[_uix_]>_align_total_)
          _align_total_ := _struct_align_[_uix_]
        ; Increase total size of union/structure if necessary
        _total_union_size_ := _union_size_[_uix_]>_total_union_size_?_union_size_[_uix_]:_total_union_size_
        ,_union_._Remove(),_struct_._Remove(),_union_size_._Remove(),_struct_align_.Remove(),_LF_BKP_:=SubStr(_LF_BKP_,1,StrLen(_LF_BKP_)-1) ; remove latest items
        If (_uix_=1){ ; leaving top union, add offset
          if (_mod_:=Mod(_total_union_size_,_align_total_))
			_total_union_size_ += Mod(_align_total_-_mod_,_align_total_)
          _offset_+=_total_union_size_,_total_union_size_:=0
        }
      }
    }
	this.base:=_base_ ; apply new base which uses below functions and uses ___GET for __GET and ___SET for __SET
    If (IsObject(_init_)||IsObject(_pointer_)){ ; Initialization of structures members, e.g. _Struct(_RECT,{left:10,right:20})
      for _key_,_value_ in IsObject(_init_)?_init_:_pointer_
      {
        If !this["`r" _key_]{ ; It is not a pointer, assign value
          If InStr(",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR,","," this["`t" _key_] ",")
            this.Alloc(_key_,StrLen(_value_)*(InStr(".LPWSTR,LPCWSTR,","," this["`t"] ",")||(InStr(",LPTSTR,LPCTSTR,","," this["`t" _key_] ",")&&A_IsUnicode)?2:1))
          if InStr(",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR,CHAR,TCHAR,WCHAR,","," this["`t" _key_] ",")
            this[_key_]:=_value_
          else 
            this[_key_] := _value_
        }else if (_value_<>"") ; It is not empty
          if _value_ is integer ; It is a new pointer
            this[_key_][""]:=_value_
      }
    }
    Return this
  }
  ToObj(struct:=""){
		obj:=[]
		for k,v in struct?struct:struct:=this
			if (Asc(k)=10)
				If IsObject(_VALUE_:=struct[_TYPE_:=SubStr(k,2)])
					obj[_TYPE_]:=this.ToObj(_VALUE_)
				else obj[_TYPE_]:=_VALUE_
		return obj
	}
  SizeT(_key_=""){
    return sizeof(this["`t" _key_])
  }
  Size(){
    return sizeof(this)
  }
  IsPointer(_key_=""){
    return this["`r" _key_] 
  }
  Type(_key_=""){
    return this["`t" _key_] 
  }
  AHKType(_key_=""){
    return this["`n" _key_] 
  }
  Offset(_key_=""){
    return this["`b" _key_] 
  }
  Encoding(_key_=""){
    return this["`b" _key_] 
  }
  Capacity(_key_=""){
    return this._GetCapacity("`v" _key_)
  }
  Alloc(_key_="",size="",ptrsize=0){
    If _key_ is integer
      ptrsize:=size,size:=_key_,_key_:=""
   If size is integer
      SizeIsInt:=1
    If ptrsize {
      If (this._SetCapacity("`v" _key_,!SizeIsInt?A_PtrSize+ptrsize:size + (size//A_PtrSize)*ptrsize)="")
        MsgBox % "Memory for pointer ." _key_ ". of size " (SizeIsInt?size:A_PtrSize) " could not be set!"
      else {
        DllCall("RtlZeroMemory","UPTR",this._GetAddress("`v" _key_),"UInt",this._GetCapacity("`v" _key_))
			  If (this[" " _key_]>1){
					ptr:=this[""] + this["`b" _key_]
					If (this["`r" _key_] || InStr(",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR,","," this["`t" _key_] ","))
						NumPut(ptrs:=this._GetAddress("`v" _key_),ptr+0,"PTR")
					else if _key_
						this[_key_,""]:=ptrs:=this._GetAddress("`v" _key_)
					else this[""]:=ptr:=this._GetAddress("`v" _key_),ptrs:=this._GetAddress("`v" _key_)+(SizeIsInt?size:A_PtrSize)
				} else {
	        If (this["`r" _key_] || InStr(",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR,","," this["`t" _key_] ","))
	          NumPut(ptr:=this._GetAddress("`v" _key_),this[""] + this["`b" _key_],"PTR")
	        else this[""]:=ptr:=this._GetAddress("`v" _key_)
	        ptrs:=ptr+(size?size:A_PtrSize)
				}
        Loop % SizeIsInt?(size//A_PtrSize):1
          NumPut(ptrs+(A_Index-1)*ptrsize,ptr+(A_Index-1)*A_PtrSize,"PTR")
      }
    } else {
      If (this._SetCapacity("`v" _key_,SizeIsInt?size:A_PtrSize)=""){
        MsgBox % "Memory for pointer ." _key_ ". of size " (SizeIsInt?size:A_PtrSize) " could not be set!"
      } else
          NumPut(ptr:=this._GetAddress("`v" _key_),this[""] + this["`b" _key_],"PTR"),DllCall("RtlZeroMemory","UPTR",ptr,"UInt",SizeIsInt?size:A_PtrSize)
    }
    return ptr
  }
  ___NEW(init*){
    this:=this.base
    newobj := this.__Clone(1) ;clone structure and keep pointer (1), it will be changed below
    If (init.MaxIndex() && !IsObject(init.1))
      newobj[""] := init.1
    else If (init.MaxIndex()>1 && !IsObject(init.2))
      newobj[""] := init.2
    else
      newobj._SetCapacity("`a",_StructSize_:=sizeof(this)) ; Set Capacity in key ["`a"]
      ,newobj[""]:=newobj._GetAddress("`a") ; Save pointer in key [""]
      ,DllCall("RtlZeroMemory","UPTR",newobj[""],"UInt",_StructSize_) ; zero-fill memory
    If (IsObject(init.1)||IsObject(init.2))
      for _key_,_value_ in IsObject(init.1)?init.1:init.2
          newobj[_key_] := _value_
    return newobj
  }
  
  ; Clone structure and move pointer for new structure
  ___Clone(offset){
    static _base_:={__GET:_Struct.___GET,__SET:_Struct.___SET,__SETPTR:_Struct.___SETPTR,__Clone:_Struct.___Clone,__NEW:_Struct.___NEW
          ,IsPointer:_Struct.IsPointer,Offset:_Struct.Offset,Type:_Struct.Type,AHKType:_Struct.AHKType,Encoding:_Struct.Encoding
          ,Capacity:_Struct.Capacity,Alloc:_Struct.Alloc,Size:_Struct.Size,SizeT:_Struct.SizeT,Print:_Struct.Print,ToObj:_Struct.ToObj}
    If offset=1
      return this
    newobj:={} ; new structure object
    for _key_,_value_ in this ; copy all values/objects
      If (_key_!="`a")
        newobj[_key_]:=_value_ ; add key to new object and assign value
    newobj._SetCapacity("`a",_StructSize_:=sizeof(this)) ; Set Capacity in key ["`a"]
    ,newobj[""]:=newobj._GetAddress("`a") ; Save pointer in key [""]
    ,DllCall("RtlZeroMemory","UPTR",newobj[""],"UInt",_StructSize_) ; zero-fill memory
    If this["`r"]{ ; its a pointer so we need too move internal memory
      NumPut(NumGet(this[""],"PTR")+A_PtrSize*(offset-1),newobj[""],"Ptr")
      newobj.base:=_base_ ;assign base of _Struct
    } else ; do not use internal memory, simply assign new pointer to new structure
      newobj.base:=_base_,newobj[]:=this[""]+sizeof(this)*(offset-1)
    return newobj ; return new object
  }
  ___GET(_key_="",p*){
    If (_key_="")           ; Key was not given so structure[] has been called, return pointer to structure
      Return this[""]
		else if !(idx:=p.MaxIndex())
			_field_:=_key_,opt:="~"
		else {
		  ObjInsert(p,1,_key_)
			opt:=ObjRemove(p),_field_:=_key_:=ObjRemove(p)
			for key_,value_ in p
				this:=this[value_]
		}
    If this["`t"] ; structure without keys/members
      _key_:="" ; set _key_ empty so items below will resolve to our structure
    If (opt!="~"){
      If (opt=""){
        If _field_ is integer
          return (this["`r"]?NumGet(this[""],"PTR"):this[""])+sizeof(this["`t"])*(_field_-1)
        else return this["`r" _key_]?NumGet(this[""]+this["`b" _key_],"PTR"):this[""]+this["`b" _key_] ;+sizeof(this["`t" _key_])*(_field_-1)
      } else If opt is integer
      { ;offset to a item e.g. struct.a[100] ("Uint a[100]")
		; MsgBox % "ja " 
        If (_Struct.HasKey("_" this["`t" _key_]) && this[" " _key_]>1) {
				  If (InStr( ",CHAR,UCHAR,TCHAR,WCHAR," , "," this["`t" _key_] "," )){  ; StrGet 1 character only
					Return StrGet(this[""]+this["`b" _key_]+(opt-1)*sizeof(this["`t" _key_]),1,this["`f" _key_])
				  } else if InStr( ",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR," , "," this["`t" _key_] "," ){ ; StrGet string
					Return StrGet(NumGet(this[""]+this["`b" _key_]+(opt-1)*A_PtrSize,"PTR"),this["`f" _key_])
				  } else {
					Return NumGet(this[""]+this["`b" _key_]+(opt-1)*sizeof(this["`t" _key_]),this["`n" _key_])
				  }
				} else Return new _Struct(this["`t" _key_],this[""]+this["`b" _key_]+(opt-1)*sizeof(this["`t" _key_]))
      } else
        return this[_key_][opt]
    } else If _field_ is integer
    { ; array access (must be listed first because otherwise this["`r" _key_] cannot be resolved
      If (_key_){ ; Offset for item
        return this.__Clone(_field_)
      } else if this["`r"] {
        Pointer:=""
        Loop % (this["`r"]-1) ; dip into one step and return a new structure
          pointer.="*"
        If pointer
          Return new _Struct(pointer this["`t"],NumGet(this[""],"PTR")+A_PtrSize*(_field_-1))
        else Return new _Struct(pointer this["`t"],NumGet(this[""],"PTR")+sizeof(this["`t"])*(_field_-1)).1
      } else if _Struct.HasKey("_" this["`t"]) {
        ; If this[" "]
          ; Return new _Struct(this["`t"],this[""])
        ; else 
				If (InStr( ",CHAR,UCHAR,TCHAR,WCHAR," , "," this["`t"] "," )){  ; StrGet 1 character only
          Return StrGet(this[""]+sizeof(this["`t"])*(_field_-1),1,this["`f"])
        } else if InStr(",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR," , "," this["`t"] "," ){ ; StrGet string
					Return StrGet(NumGet(this[""]+A_PtrSize*(_field_-1),"PTR"),this["`f"])
        } else { ; resolve pointer
            Return NumGet(this[""]+sizeof(this["`t"])*(_field_-1),this["`n"])
        }
      } else {
			
				; return this.__Clone(_field_)
				; listVars
				; MsgBox % this[""] "+" sizeof(this["`t"])*(_field_-1) "-" this["`t"]
        Return new _Struct(this["`t"],this[""]+sizeof(this["`t"])*(_field_-1))
      }
    } else If this["`r" _key_] { ;pointer
      Pointer:=""
      Loop % (this["`r" _key_]-1) ; dip into one step and return a new structure
          pointer.="*"
      If (_key_=""){
        return this[1][_field_]
      } else {
        Return new _Struct(pointer this["`t" _key_],NumGet(this[""]+this["`b" _key_],"PTR"))
      }
    } else if _Struct.HasKey("_" this["`t" _key_]) { ; default data type, not pointer
      If (this[" " _key_]>1)
        Return new _Struct(this["`t" _key_],this[""] + this["`b" _key_])
      else If (InStr( ",CHAR,UCHAR,TCHAR,WCHAR," , "," this["`t" _key_] "," )){  ; StrGet 1 character only
        Return StrGet(this[""]+this["`b" _key_],1,this["`f" _key_])
      } else if InStr( ",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR," , "," this["`t" _key_] "," ){ ; StrGet string
        Return StrGet(NumGet(this[""]+this["`b" _key_],"PTR"),this["`f" _key_])
      } else {
        Return NumGet(this[""]+this["`b" _key_],this["`n" _key_])
      }
    } else { ; the field is a non pointer structure
      Return new _Struct(this["`t" _key_],this[""]+this["`b" _key_])
    }
  }
  ___SET(_key_,p*){ ;="",_value_=-0x8000000000000000 ,opt="~"){
    If !(idx:=p.MaxIndex()) ; Set new Pointer, here a value was assigned e.g. struct[]:=&var
      return this[""] :=_key_,this._SetCapacity("`a",0) ; free internal memory, it will not be used anymore
    else if (idx=1)
			_value_:=p.1,opt:="~"
		else if (idx>1){
      ObjInsert(p,1,_key_)
			If (p[idx]="")
				opt:=ObjRemove(p),_value_:=ObjRemove(p),_key_:=ObjRemove(p)
      else _value_:=ObjRemove(p),_key_:=ObjRemove(p),opt:="~"
			for key_,value_ in p
				this:=this[value_]
    }
    If this["`t"] ; structure without members
      _field_:=_key_,_key_:="" ; set _key_ empty so it will resolve to our structure
    else _field_:=_key_
    If this["`r" _key_] { ; Pointer
			If opt is integer
        return NumPut(opt,this[""] + this["`b" _key_],"PTR")
      else if this.HasKey("`t" _key_) {
        Pointer:=""
        Loop % (this["`r" _key_]-1) ; dip into one step and return a new structure
          pointer.="*"
        If _key_
          Return (new _Struct(pointer this["`t" _key_],NumGet(this[""] + this["`b" _key_],"PTR"))).1:=_value_
        else Return (new _Struct(pointer this["`t"],NumGet(this[""],"PTR")))[_field_]:=_value_
      } else If _field_ is Integer
       if (_key_="") ; replace this for the operation
        _this:=this,this:=this.__Clone(_Field_)
      If InStr( ",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR," , "," this["`t" _key_] "," )
        StrPut(_value_,NumGet(NumGet(this[""]+this["`b" _key_],"PTR"),"PTR"),this["`f" _key_]) ; StrPut char to addr+A_PtrSize
      else if InStr( ",TCHAR,CHAR,UCHAR,WCHAR," , "," this["`t" _key_] "," ){ ; same as above but for 1 Character only
        StrPut(_value_,NumGet(this[""]+this["`b" _key_],"PTR"),this["`f" _key_]) ; StrPut char to addr
      } else
        NumPut(_value_,NumGet(this[""]+this["`b" _key_],"PTR"),this["`n" _key_])
      If _field_ is integer ; restore this after operation
        this:=_this
    } else if (RegExMatch(_field_,"^\d+$") && _key_="") {
      if InStr( ",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR," , "," this["`t"] "," ){ 
        StrPut(_value_,NumGet(this[""]+A_PtrSize*(_field_-1),"PTR"),this["`f"]) ; StrPut string to addr
      } else if InStr( ",TCHAR,CHAR,UCHAR,WCHAR," , "," this["`t" _key_] "," ){
        StrPut(_value_,this[""] + sizeof(this["`t"])*(_field_-1),this["`f"])
      } else
        NumPut(_value_,this[""] + sizeof(this["`t"])*(_field_-1),this["`n"]) ; NumPut new value to key
    } else if opt is integer
    {
      return NumPut(opt,this[""] + this["`b" _key_],"PTR")
    } else if InStr( ",LPSTR,LPCSTR,LPTSTR,LPCTSTR,LPWSTR,LPCWSTR," , "," this["`t" _key_] "," ){ 
      StrPut(_value_,NumGet(this[""] + this["`b" _key_],"PTR"),this["`f" _key_]) ; StrPut string to addr
    } else if InStr( ",TCHAR,CHAR,UCHAR,WCHAR," , "," this["`t" _key_] "," ){
      StrPut(_value_,this[""] + this["`b" _key_],this["`f" _key_]) ; StrPut character key
    } else
      NumPut(_value_,this[""]+this["`b" _key_],this["`n" _key_]) ; NumPut new value to key
    Return _value_
  }
}
;: Title: sizeof function by HotKeyIt
;

; Function: sizeof
; Description:
;      sizeof() is based on AHK_L Objects and supports both, ANSI and UNICODE version, so to use it you will require <a href=http://www.autohotkey.com/forum/viewtopic.php?t=43049>Lexikos AutoHotkey_L.exe</a> or other versions based on it that supports objects.<br><br>nsizeof is used to calculate the size of structures or data types. <br>Visit <a href=http://www.autohotkey.com/forum/viewtopic.php?t=43049>sizeof at AutoHotkey</a> forum, any feedback is welcome.
; Syntax: size:= sizeof(Structure_Definition or Structure_Object)
; Parameters:
;	   Field types - All AutoHotkey and Windows Data Types are supported<br>AutoHotkey Data Types<br> Int, Uint, Int64, UInt64, Char, UChar, Short, UShort, Fload and Double.<br>Windows Data Types<br> - note, TCHAR UCHAR and CHAR return actual character rather than the value, use Asc() function to find out the value/code<br>Windows Data types: Asc(char)<br>ATOM,BOOL,BOOLEAN,BYTE,CHAR,COLORREF,DWORD,DWORDLONG,DWORD_PTR,<br>DWORD32,DWORD64,FLOAT,HACCEL,HALF_PTR,HANDLE,HBITMAP,HBRUSH,HCOLORSPACE,HCONV,HCONVLIST,HCURSOR,HDC,<br>HDDEDATA,HDESK,HDROP,HDWP,HENHMETAFILE,HFILE,HFONT,HGDIOBJ,HGLOBAL,HHOOK,HICON,HINSTANCE,HKEY,HKL,<br>HLOCAL,HMENU,HMETAFILE,HMODULE,HMONITOR,HPALETTE,HPEN,HRESULT,HRGN,HRSRC,HSZ,HWINSTA,HWND,INT,<br>INT_PTR,INT32,INT64,LANGID,LCID,LCTYPE,LGRPID,LONG,LONGLONG,LONG_PTR,LONG32,LONG64,LPARAM,LPBOOL,<br>LPBYTE,LPCOLORREF,LPCSTR,LPCTSTR,LPCVOID,LPCWSTR,LPDWORD,LPHANDLE,LPINT,LPLONG,LPSTR,LPTSTR,LPVOID,<br>LPWORD,LPWSTR,LRESULT,PBOOL,PBOOLEAN,PBYTE,PCHAR,PCSTR,PCTSTR,PCWSTR,PDWORD,PDWORDLONG,PDWORD_PTR,<br>PDWORD32,PDWORD64,PFLOAT,PHALF_PTR,PHANDLE,PHKEY,PINT,PINT_PTR,PINT32,PINT64,PLCID,PLONG,PLONGLONG,<br>PLONG_PTR,PLONG32,PLONG64,POINTER_32,POINTER_64,POINTER_SIGNED,POINTER_UNSIGNED,PSHORT,PSIZE_T,<br>PSSIZE_T,PSTR,PTBYTE,PTCHAR,PTSTR,PUCHAR,PUHALF_PTR,PUINT,PUINT_PTR,PUINT32,PUINT64,PULONG,PULONGLONG,<br>PULONG_PTR,PULONG32,PULONG64,PUSHORT,PVOID,PWCHAR,PWORD,PWSTR,SC_HANDLE,SC_LOCK,SERVICE_STATUS_HANDLE,<br>SHORT,SIZE_T,SSIZE_T,TBYTE,TCHAR,UCHAR,UHALF_PTR,UINT,UINT_PTR,UINT32,UINT64,ULONG,ULONGLONG,<br>ULONG_PTR,ULONG32,ULONG64,USHORT,USN,WCHAR,WORD,WPARAM
;	   <b>Parameters</b> - <b>Description</b>
;	   size - The size of structure or data type
;	   Structure_Definition - C/C++ syntax or usual definition (must not be multiline) e.g. "Int x,Int y", C/C++ definitions must be multiline.
; Return Value:
;     sizeof returns size of structures or data types
; Remarks:
;		None.
; Related:
; Example:
;		file:

sizeof(_TYPE_,parent_offset=0,ByRef _align_total_=0){
  ;Windows and AHK Data Types, used to find out the corresponding size
  static _types__:="
  (LTrim Join
    ,ATOM:2,LANGID:2,WCHAR:2,WORD:2,PTR:" A_PtrSize ",UPTR:" A_PtrSize ",SHORT:2,USHORT:2,INT:4,UINT:4,INT64:8,UINT64:8,DOUBLE:8,FLOAT:4,CHAR:1,UCHAR:1,__int64:8
    ,TBYTE:" (A_IsUnicode?2:1) ",TCHAR:" (A_IsUnicode?2:1) ",HALF_PTR:" (A_PtrSize=8?4:2) ",UHALF_PTR:" (A_PtrSize=8?4:2) ",INT32:4,LONG:4,LONG32:4,LONGLONG:8
    ,LONG64:8,USN:8,HFILE:4,HRESULT:4,INT_PTR:" A_PtrSize ",LONG_PTR:" A_PtrSize ",POINTER_64:" A_PtrSize ",POINTER_SIGNED:" A_PtrSize "
    ,BOOL:4,SSIZE_T:" A_PtrSize ",WPARAM:" A_PtrSize ",BOOLEAN:1,BYTE:1,COLORREF:4,DWORD:4,DWORD32:4,LCID:4,LCTYPE:4,LGRPID:4,LRESULT:4,PBOOL:" A_PtrSize "
    ,PBOOLEAN:" A_PtrSize ",PBYTE:" A_PtrSize ",PCHAR:" A_PtrSize ",PCSTR:" A_PtrSize ",PCTSTR:" A_PtrSize ",PCWSTR:" A_PtrSize ",PDWORD:" A_PtrSize "
    ,PDWORDLONG:" A_PtrSize ",PDWORD_PTR:" A_PtrSize ",PDWORD32:" A_PtrSize ",PDWORD64:" A_PtrSize ",PFLOAT:" A_PtrSize ",PHALF_PTR:" A_PtrSize "
    ,UINT32:4,ULONG:4,ULONG32:4,DWORDLONG:8,DWORD64:8,ULONGLONG:8,ULONG64:8,DWORD_PTR:" A_PtrSize ",HACCEL:" A_PtrSize ",HANDLE:" A_PtrSize "
     ,HBITMAP:" A_PtrSize ",HBRUSH:" A_PtrSize ",HCOLORSPACE:" A_PtrSize ",HCONV:" A_PtrSize ",HCONVLIST:" A_PtrSize ",HCURSOR:" A_PtrSize ",HDC:" A_PtrSize "
     ,HDDEDATA:" A_PtrSize ",HDESK:" A_PtrSize ",HDROP:" A_PtrSize ",HDWP:" A_PtrSize ",HENHMETAFILE:" A_PtrSize ",HFONT:" A_PtrSize ",USAGE:" 2 "
   )"
  static _types_:=_types__ "
  (LTrim Join
     ,HGDIOBJ:" A_PtrSize ",HGLOBAL:" A_PtrSize ",HHOOK:" A_PtrSize ",HICON:" A_PtrSize ",HINSTANCE:" A_PtrSize ",HKEY:" A_PtrSize ",HKL:" A_PtrSize "
     ,HLOCAL:" A_PtrSize ",HMENU:" A_PtrSize ",HMETAFILE:" A_PtrSize ",HMODULE:" A_PtrSize ",HMONITOR:" A_PtrSize ",HPALETTE:" A_PtrSize ",HPEN:" A_PtrSize "
     ,HRGN:" A_PtrSize ",HRSRC:" A_PtrSize ",HSZ:" A_PtrSize ",HWINSTA:" A_PtrSize ",HWND:" A_PtrSize ",LPARAM:" A_PtrSize ",LPBOOL:" A_PtrSize ",LPBYTE:" A_PtrSize "
     ,LPCOLORREF:" A_PtrSize ",LPCSTR:" A_PtrSize ",LPCTSTR:" A_PtrSize ",LPCVOID:" A_PtrSize ",LPCWSTR:" A_PtrSize ",LPDWORD:" A_PtrSize ",LPHANDLE:" A_PtrSize "
     ,LPINT:" A_PtrSize ",LPLONG:" A_PtrSize ",LPSTR:" A_PtrSize ",LPTSTR:" A_PtrSize ",LPVOID:" A_PtrSize ",LPWORD:" A_PtrSize ",LPWSTR:" A_PtrSize "
     ,PHANDLE:" A_PtrSize ",PHKEY:" A_PtrSize ",PINT:" A_PtrSize ",PINT_PTR:" A_PtrSize ",PINT32:" A_PtrSize ",PINT64:" A_PtrSize ",PLCID:" A_PtrSize "
     ,PLONG:" A_PtrSize ",PLONGLONG:" A_PtrSize ",PLONG_PTR:" A_PtrSize ",PLONG32:" A_PtrSize ",PLONG64:" A_PtrSize ",POINTER_32:" A_PtrSize "
     ,POINTER_UNSIGNED:" A_PtrSize ",PSHORT:" A_PtrSize ",PSIZE_T:" A_PtrSize ",PSSIZE_T:" A_PtrSize ",PSTR:" A_PtrSize ",PTBYTE:" A_PtrSize "
     ,PTCHAR:" A_PtrSize ",PTSTR:" A_PtrSize ",PUCHAR:" A_PtrSize ",PUHALF_PTR:" A_PtrSize ",PUINT:" A_PtrSize ",PUINT_PTR:" A_PtrSize "
     ,PUINT32:" A_PtrSize ",PUINT64:" A_PtrSize ",PULONG:" A_PtrSize ",PULONGLONG:" A_PtrSize ",PULONG_PTR:" A_PtrSize ",PULONG32:" A_PtrSize "
     ,PULONG64:" A_PtrSize ",PUSHORT:" A_PtrSize ",PVOID:" A_PtrSize ",PWCHAR:" A_PtrSize ",PWORD:" A_PtrSize ",PWSTR:" A_PtrSize ",SC_HANDLE:" A_PtrSize "
     ,SC_LOCK:" A_PtrSize ",SERVICE_STATUS_HANDLE:" A_PtrSize ",SIZE_T:" A_PtrSize ",UINT_PTR:" A_PtrSize ",ULONG_PTR:" A_PtrSize ",VOID:" A_PtrSize "
     )"
  local _,_ArrName_:="",_ArrType_,_ArrSize_,_defobj_,_idx_,_LF_,_LF_BKP_,_match_,_offset_,_padding_,_struct_
				,_total_union_size_,_uix_,_union_,_union_size_,_in_struct_,_mod_,_max_size_,_struct_align_
	_offset_:=parent_offset           ; Init size/offset to 0 or parent_offset

  If IsObject(_TYPE_){    ; If structure object - check for offset in structure and return pointer + last offset + its data size
    return _TYPE_["`a`a"]
  }
  
  If RegExMatch(_TYPE_,"^[\w\d\._]+$"){ ; structures name was supplied, resolve to global var and run again
      If InStr(_types_,"," _TYPE_ ":")
        Return SubStr(_types_,InStr(_types_,"," _TYPE_ ":") + 2 + StrLen(_TYPE_),1)
      else If InStr(_TYPE_,"."){ ;check for object that holds structure definition
        Loop,Parse,_TYPE_,.
          If A_Index=1
            _defobj_:=%A_LoopField%
          else _defobj_:=_defobj_[A_LoopField]
        Return sizeof(_defobj_,parent_offset)
      } else Return sizeof(%_TYPE_%,parent_offset)
  } else _defobj_:=""    
  If InStr(_TYPE_,"`n") {   ; C/C++ style definition, convert
    _offset_:=""            ; This will hold new structure
    ,_struct_:=[]            ; This will keep track if union is structure
    ,_union_:=0              ; This will keep track of union depth
    Loop,Parse,_TYPE_,`n,`r`t%A_Space%%A_Tab%
    {
      _LF_:=""
      Loop,Parse,A_LoopField,`,`;,`t%A_Space%%A_Tab%
      {
        If RegExMatch(A_LoopField,"^\s*//") ;break on comments and continue main loop
            break
        If (A_LoopField){ ; skip empty lines
            If (!_LF_ && _ArrType_:=RegExMatch(A_LoopField,"[\w\d_#@]\s+[\w\d_#@]")) ; new line, find out data type and save key in _LF_ Data type will be added later
              _LF_:=RegExReplace(A_LoopField,"[\w\d_#@]\K\s+.*$")
            If Instr(A_LoopField,"{"){ ; Union, also check if it is a structure
              _union_++,_struct_.Insert(_union_,RegExMatch(A_LoopField,"i)^\s*struct\s*\{"))
            } else If InStr(A_LoopField,"}") ; end of union/struct
              _offset_.="}"
            else { ; not starting or ending struct or union so add definitions and apply Data Type.
              If _union_ ; add { or struct{
                  Loop % _union_
                    _ArrName_.=(_struct_[A_Index]?"struct":"") "{"
              _offset_.=(_offset_ ? "," : "") _ArrName_ ((_ArrType_ && A_Index!=1)?(_LF_ " "):"") RegExReplace(A_LoopField,"\s+"," ")
              ,_ArrName_:="",_union_:=0
            }
        }
      }
    }
    _TYPE_:=_offset_
    ,_offset_:=parent_offset           ; Init size/offset to 0 or parent_offset
  }
  
  ; Following keep track of union size/offset
  _union_:=[]               ; keep track of union level, required to reset offset after union is parsed
  ,_struct_:=[]              ; for each union level keep track if it is a structure (because here offset needs to increase
  ,_union_size_:=[]          ; keep track of highest member within the union or structure, used to calculate new offset after union
  ,_struct_align_:=[]        ; keep track of alignment before structure
  ,_total_union_size_:=0     ; used in combination with above, each loop the total offset is updated if current data size is higher
  ;,_align_total_:=0          ; used to calculate alignment for total size of structure
  ,_in_struct_:=1
  ; Parse given structure definition and calculate size
  ; Structures will be resolved by recrusive calls (a structure must be global)
  Loop,Parse,_TYPE_,`,`; ;,%A_Space%%A_Tab%`n`r
  {
    _in_struct_+=StrLen(A_LoopField)+1
    If ("" = _LF_ := trim(A_LoopField,A_Space A_Tab "`n`r"))
      continue
    _LF_BKP_:=_LF_ ;to check for ending brackets = union,struct
    ; Check for STARTING union and set union helpers
    While (_match_:=RegExMatch(_LF_,"i)^(struct|union)?\s*\{\K"))
      ; correct offset for union/structure, sizeof_maxsize returns max size of union or structure
        _max_size_:=sizeof_maxsize(SubStr(_TYPE_,_in_struct_-StrLen(A_LoopField)-1+(StrLen(_LF_BKP_)-StrLen(_LF_))))
        ,_union_.Insert(_offset_+=(_mod_:=Mod(_offset_,_max_size_))?Mod(_max_size_-_mod_,_max_size_):0)
        ,_union_size_.Insert(0)
        ,_struct_align_.Insert(_align_total_>_max_size_?_align_total_:_max_size_)
        ,_struct_.Insert(RegExMatch(_LF_,"i)^struct\s*\{")?(1,_align_total_:=0):0)
        ,_LF_:=SubStr(_LF_,_match_)
    StringReplace,_LF_,_LF_,},,A
    
    If InStr(_LF_,"*"){ ; It's a pointer, size will be always A_PtrSize
      _offset_ += (_mod_:=Mod(_offset_ + A_PtrSize,A_PtrSize)?A_PtrSize-_mod_:0) + A_PtrSize
      ,_align_total_:=_align_total_<A_PtrSize?A_PtrSize:_align_total_
    } else {
      ; Split array type and optionally the size of array, e.g. "TCHAR chr[5]"
      RegExMatch(_LF_,"^(?<ArrType_>[\w\d\._#@]+)?\s*(?<ArrName_>[\w\d\._#@]+)?\s*\[?(?<ArrSize_>\d+)?\]?\s*$",_)
      If (!_ArrName_ && !_ArrSize_ && !InStr( _types_  ,"," _ArrType_ ":"))
        _ArrName_:=_ArrType_,_ArrType_:="UInt"
      If InStr(_ArrType_,"."){ ;check for object that holds structure definition
        Loop,Parse,_ArrType_,.
          If A_Index=1
            _defobj_:=%A_LoopField%
          else _defobj_:=_defobj_[A_LoopField]
        ; _ArrType_:=_defobj_                                                                     ;                   ??????????????????????????????????????
      }
      If (_idx_:=InStr( _types_  ,"," _ArrType_ ":")) ; AHK or Windows data type
        _padding_:=SubStr( _types_  , _idx_+StrLen(_ArrType_)+2 , 1 ),_align_total_:=_align_total_<_padding_?_padding_:_align_total_
      else _padding_:= sizeof(_defobj_?_defobj_:%_ArrType_%,0,_align_total_),_max_size_:=sizeof_maxsize(_defobj_?_defobj_:%_ArrType_%)
      if (_max_size_){
        if (_mod_:=Mod(_offset_,_max_size_))
          _offset_ += Mod(_max_size_-_mod_,_max_size_)
      } else if _mod_:=Mod(_offset_,_padding_)
        _offset_ += Mod(_padding_-_mod_,_padding_)
      _offset_ += (_padding_ * (_ArrSize_?_ArrSize_:1))
      _max_size_:=0
    }
    ; It's a union or struct, check if new member is higher then previous members
    If (_uix_:=_union_.MaxIndex()) && (_max_size_:=_offset_ - _union_[_uix_])>_union_size_[_uix_]
      _union_size_[_uix_]:=_max_size_
    _max_size_:=0
    ; It's a union and not struct
    If (_uix_ && !_struct_[_uix_])
      _offset_:=_union_[_uix_]

    ; Check for ENDING union and reset offset and union helpers
    While (SubStr(_LF_BKP_,0)="}"){
      If !(_uix_:=_union_.MaxIndex()){
        MsgBox,0, Incorrect structure, missing opening braket {`nProgram will exit now `n%_TYPE_%
        ExitApp
      }
      ; reset offset and align because we left a union or structure
      if (_uix_>1 && _struct_[_uix_-1]){
        If (_mod_:=Mod(_offset_,_struct_align_[_uix_]))
          _offset_+=Mod(_struct_align_[_uix_]-_mod_,_struct_align_[_uix_])
      } else _offset_:=_union_[_uix_]
      ; a member of union/struct is smaller than previous align, restore
      if (_struct_[_uix_] &&_struct_align_[_uix_]>_align_total_)
        _align_total_ := _struct_align_[_uix_]
      ; Increase total size of union/structure if necessary
      _total_union_size_ := _union_size_[_uix_]>_total_union_size_?_union_size_[_uix_]:_total_union_size_
      ,_union_.Remove() ,_struct_.Remove() ,_union_size_.Remove(),_struct_align_.Remove() ; remove latest items
      ,_LF_BKP_:=SubStr(_LF_BKP_,1,StrLen(_LF_BKP_)-1)
      If (_uix_=1){ ; leaving top union, add offset
        if (_mod_:=Mod(_total_union_size_,_align_total_))
          _total_union_size_ += Mod(_align_total_-_mod_,_align_total_)
        _offset_+=_total_union_size_,_total_union_size_:=0
      }
    }
  }
  _offset_+= Mod(_align_total_ - Mod(_offset_,_align_total_),_align_total_)
  Return _offset_
}
sizeof_maxsize(s){
  static _types__:="
  (LTrim Join
    ,ATOM:2,LANGID:2,WCHAR:2,WORD:2,PTR:" A_PtrSize ",UPTR:" A_PtrSize ",SHORT:2,USHORT:2,INT:4,UINT:4,INT64:8,UINT64:8,DOUBLE:8,FLOAT:4,CHAR:1,UCHAR:1,__int64:8
    ,TBYTE:" (A_IsUnicode?2:1) ",TCHAR:" (A_IsUnicode?2:1) ",HALF_PTR:" (A_PtrSize=8?4:2) ",UHALF_PTR:" (A_PtrSize=8?4:2) ",INT32:4,LONG:4,LONG32:4,LONGLONG:8
    ,LONG64:8,USN:8,HFILE:4,HRESULT:4,INT_PTR:" A_PtrSize ",LONG_PTR:" A_PtrSize ",POINTER_64:" A_PtrSize ",POINTER_SIGNED:" A_PtrSize "
    ,BOOL:4,SSIZE_T:" A_PtrSize ",WPARAM:" A_PtrSize ",BOOLEAN:1,BYTE:1,COLORREF:4,DWORD:4,DWORD32:4,LCID:4,LCTYPE:4,LGRPID:4,LRESULT:4,PBOOL:" A_PtrSize "
    ,PBOOLEAN:" A_PtrSize ",PBYTE:" A_PtrSize ",PCHAR:" A_PtrSize ",PCSTR:" A_PtrSize ",PCTSTR:" A_PtrSize ",PCWSTR:" A_PtrSize ",PDWORD:" A_PtrSize "
    ,PDWORDLONG:" A_PtrSize ",PDWORD_PTR:" A_PtrSize ",PDWORD32:" A_PtrSize ",PDWORD64:" A_PtrSize ",PFLOAT:" A_PtrSize ",PHALF_PTR:" A_PtrSize "
    ,UINT32:4,ULONG:4,ULONG32:4,DWORDLONG:8,DWORD64:8,ULONGLONG:8,ULONG64:8,DWORD_PTR:" A_PtrSize ",HACCEL:" A_PtrSize ",HANDLE:" A_PtrSize "
     ,HBITMAP:" A_PtrSize ",HBRUSH:" A_PtrSize ",HCOLORSPACE:" A_PtrSize ",HCONV:" A_PtrSize ",HCONVLIST:" A_PtrSize ",HCURSOR:" A_PtrSize ",HDC:" A_PtrSize "
     ,HDDEDATA:" A_PtrSize ",HDESK:" A_PtrSize ",HDROP:" A_PtrSize ",HDWP:" A_PtrSize ",HENHMETAFILE:" A_PtrSize ",HFONT:" A_PtrSize ",USAGE:" 2 "
   )"
  static _types_:=_types__ "
  (LTrim Join
     ,HGDIOBJ:" A_PtrSize ",HGLOBAL:" A_PtrSize ",HHOOK:" A_PtrSize ",HICON:" A_PtrSize ",HINSTANCE:" A_PtrSize ",HKEY:" A_PtrSize ",HKL:" A_PtrSize "
     ,HLOCAL:" A_PtrSize ",HMENU:" A_PtrSize ",HMETAFILE:" A_PtrSize ",HMODULE:" A_PtrSize ",HMONITOR:" A_PtrSize ",HPALETTE:" A_PtrSize ",HPEN:" A_PtrSize "
     ,HRGN:" A_PtrSize ",HRSRC:" A_PtrSize ",HSZ:" A_PtrSize ",HWINSTA:" A_PtrSize ",HWND:" A_PtrSize ",LPARAM:" A_PtrSize ",LPBOOL:" A_PtrSize ",LPBYTE:" A_PtrSize "
     ,LPCOLORREF:" A_PtrSize ",LPCSTR:" A_PtrSize ",LPCTSTR:" A_PtrSize ",LPCVOID:" A_PtrSize ",LPCWSTR:" A_PtrSize ",LPDWORD:" A_PtrSize ",LPHANDLE:" A_PtrSize "
     ,LPINT:" A_PtrSize ",LPLONG:" A_PtrSize ",LPSTR:" A_PtrSize ",LPTSTR:" A_PtrSize ",LPVOID:" A_PtrSize ",LPWORD:" A_PtrSize ",LPWSTR:" A_PtrSize "
     ,PHANDLE:" A_PtrSize ",PHKEY:" A_PtrSize ",PINT:" A_PtrSize ",PINT_PTR:" A_PtrSize ",PINT32:" A_PtrSize ",PINT64:" A_PtrSize ",PLCID:" A_PtrSize "
     ,PLONG:" A_PtrSize ",PLONGLONG:" A_PtrSize ",PLONG_PTR:" A_PtrSize ",PLONG32:" A_PtrSize ",PLONG64:" A_PtrSize ",POINTER_32:" A_PtrSize "
     ,POINTER_UNSIGNED:" A_PtrSize ",PSHORT:" A_PtrSize ",PSIZE_T:" A_PtrSize ",PSSIZE_T:" A_PtrSize ",PSTR:" A_PtrSize ",PTBYTE:" A_PtrSize "
     ,PTCHAR:" A_PtrSize ",PTSTR:" A_PtrSize ",PUCHAR:" A_PtrSize ",PUHALF_PTR:" A_PtrSize ",PUINT:" A_PtrSize ",PUINT_PTR:" A_PtrSize "
     ,PUINT32:" A_PtrSize ",PUINT64:" A_PtrSize ",PULONG:" A_PtrSize ",PULONGLONG:" A_PtrSize ",PULONG_PTR:" A_PtrSize ",PULONG32:" A_PtrSize "
     ,PULONG64:" A_PtrSize ",PUSHORT:" A_PtrSize ",PVOID:" A_PtrSize ",PWCHAR:" A_PtrSize ",PWORD:" A_PtrSize ",PWSTR:" A_PtrSize ",SC_HANDLE:" A_PtrSize "
     ,SC_LOCK:" A_PtrSize ",SERVICE_STATUS_HANDLE:" A_PtrSize ",SIZE_T:" A_PtrSize ",UINT_PTR:" A_PtrSize ",ULONG_PTR:" A_PtrSize ",VOID:" A_PtrSize "
     )"
  max:=0,i:=0
  s:=trim(s,"`n`r`t ")
  If InStr(s,"}"){
    Loop,Parse,s
      if (A_LoopField="{")
        i++
      else if (A_LoopField="}"){
        if --i<1{
          end:=A_Index
          break
        }
      }
    if end
      s:=SubStr(s,1,end)
  }
  Loop,Parse,s,`n,`r
  {
    _struct_:=(i:=InStr(A_LoopField," //"))?SubStr(A_LoopField,1,i):A_LoopField
    Loop,Parse,_struct_,`;`,{},%A_Space%%A_Tab%
      if A_LoopField&&!InStr(".union.struct.","." A_LoopField ".")
        if (!InStr(A_LoopField,A_Tab)&&!InStr(A_LoopField," "))
          max:=max<4?4:max
        else if (sizeof(A_LoopField,0,size:=0) && max<size)
          max:=size
  }
  return max
}

I actually wrote something myself, to notify me when I change the volume using the Progress command.
:D Typical AHK, small efforts gives something useful.

Cheers.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Any mpc-hc/_struct users can take a look at this api?

24 Oct 2017, 13:33

- Is MPC your main video player? A lot of people use VLC, but I've always liked MPC.
- My script showed 'test' in top-right corner with AHK x64 and x32, so by that criterion, it worked. Did you test my script?
- My script was to show a minimal fix, although personally I wouldn't use _struct(), I would want to reduce the number of dependencies.
- Changing &lpData to lpData, was because the struct required the address where the struct began, lpData gave this address, whereas &lpData in this case gave the address of a variable containing a number.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Any mpc-hc/_struct users can take a look at this api?

24 Oct 2017, 14:47

jeeswg wrote:- Is MPC your main video player? A lot of people use VLC, but I've always liked MPC.
Yes :) (unfortunately I almost never use it :cry: )
it worked. Did you test my script?
I did not, but I did now and it didn't.
- My script showed 'test' in top-right corner
Did you test my? Note,
MpcApi.h wrote:

Code: Select all

typedef enum {
    OSD_NOMESSAGE,
    OSD_TOPLEFT,
    OSD_TOPRIGHT
} OSD_MESSAGEPOS;

- My script was to show a minimal fix, although personally I wouldn't use _struct(), I would want to reduce the number of dependencies.
It is still a minimal fix from being fixed :thumbup:. I do not mind dependencies for my own usage, I tend to avoid dependencies for code I intend to share though, because I generally want to release without any limitations on its usage. (except it should be for peaceful purposes, i.e., non-hostile use :lol: )
- Changing &lpData to lpData, was because the struct required the address where the struct began, lpData gave this address, whereas &lpData in this case gave the address of a variable containing a number.
Yes, but what are you really passing it? :think: ;)

Cheers.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Any mpc-hc/_struct users can take a look at this api?

24 Oct 2017, 16:53

With this script, everything seems to work fine.

Code: Select all

;note: the OSD only displays while a file is playing/loaded
;note: OSD must be enabled:
;View, Options...,
;Player, Other, Show OSD (requires restart)

;links:
;mpcapi.h
;https://raw.githubusercontent.com/jeeb/mpc-be/master/src/apps/mplayerc/mpcapi.h
;Any mpc-hc/_struct users can take a look at this api? - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=5&t=38700

vScriptHwnd := A_ScriptHwnd + 0
Run, mpc-hc64.exe /new /slave %vScriptHwnd%,,, vPID
WinWait, % "ahk_pid " vPID
hWnd := WinExist("ahk_pid " vPID)
return

w:: ;media player classic - on-screen display
vCount++
;OSD_NOMESSAGE := 0
;OSD_TOPLEFT := 1
;OSD_TOPRIGHT := 2
;centre column (3)
vPosType := (vCount & 32) ? 2 : 1
vDuration := 1000
vText := "[" vCount "]"
vCmd := 0xA0005000 ;CMD_OSDSHOWMESSAGE := 0xA0005000

vSize := 8 + (128 << !!A_IsUnicode)
VarSetCapacity(MPC_OSDDATA, vSize, 0)
NumPut(vPosType, &MPC_OSDDATA, 0, "Int")
NumPut(vDuration, &MPC_OSDDATA, 4, "Int")
StrPut(vText, &MPC_OSDDATA+8, 128)

VarSetCapacity(COPYDATASTRUCT, A_PtrSize?8=24:12, 0)
NumPut(vCmd, &COPYDATASTRUCT, 0, "UPtr")
NumPut(vSize, &COPYDATASTRUCT, A_PtrSize=8?8:4, "UInt")
NumPut(&MPC_OSDDATA, &COPYDATASTRUCT, A_PtrSize=8?16:8, "Ptr")

SendMessage, 0x4A, % A_ScriptHwnd, &COPYDATASTRUCT,, % "ahk_id " hWnd ;WM_COPYDATA := 0x4A
return
My quick fix script appeared to work with AHK x32, anyhow, the message did display. I looked over it, I don't know what you think is the issues are, if you'd like to be more specific.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
hachi
Posts: 15
Joined: 16 Jan 2017, 19:29

Re: Any mpc-hc/_struct users can take a look at this api?

24 Oct 2017, 19:26

jeeswg wrote:I had never used OSD before, it's quite nice, you get a little dark grey box with white text in the top-left corner, that notifies you when you play/pause or change the volume etc. The problem is that the Pause message stays for a while.
I was kind of blown away by this tbh, couldn't imagine doing without it. this is one of my peeves too, strange since duration is already an implemented param, why not include it in the ui.
Helgef wrote:I took another look, please try this,
great, this is producing reliable output. so it does come down to wrong size in the cbdata member, is there no way to properly derive this based only on the final lpdata payload?

I could not wrap my head around why this result should be different than my previous maths, I'm using that as a common lib function for all sorts of copydata messages where the size is not normally calculated in advance. also why I considered switching to _struct for the whole stack, this was my test case and I probably should have nested them in the same object.

thanks you all for the help
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Any mpc-hc/_struct users can take a look at this api?

25 Oct 2017, 03:02

so it does come down to wrong size in the cbdata member
No, as I said, the main issue is with the struct() function (not _struct class). Ofc, &lpData needs to be lpData as jeeswg pointed out.

Regarding the size. You do calculate it wrong, you need to include the size of the two first members of the struct, that is,

Code: Select all

int nMsgPos;  
int nDurationMS;
which is 8 bytes. Now, there is no info on the string length in the struct, so mpc will probably rely on it being null terminated, so the string length (considering unicode) + 8 will probably suffice, but the correct size really is the size of the struct. You see how jeeswg does it, I was sloppy. Also, the _struct object has a size() method it seems, you could use that.
With this script, everything seems to work fine.
Indeed :thumbup:
My quick fix script appeared to work with AHK x32, anyhow, the message did display.
I doubt you will get consistent result with the quick fix script, if you do, you are really unlucky ;). It didn't work for me, not 32 bit and not on 64 bit. The quick fix really is close, but you miss the key issue (struct()). You will be very happy when you figure it out, I will not spoil it for you :xmas: (I hope you don't think I'm a something not nice, I mean only well)

Cheers. :wave:
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Any mpc-hc/_struct users can take a look at this api?

25 Oct 2017, 03:33

If I add global obj underneath struct(nMsgPos, nDurationMS, strMsg) { then the quick fix works fine in AHK x64 and x32. I had been concerned that by defining 'obj' within a function, and it not being a parameter, then it would get deleted before you could use it, but I kept getting the message in AHK x32 regardless. And the pointer would still point to where the data would have been, where perhaps the data still remained. The question is: what does and doesn't remain when the object is discarded? Perhaps for me in AHK x32, the string remained intact, but not the 2 integers.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: gongnl, marypoppins_1 and 112 guests