Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Windows API Call Question: Structures


  • Please log in to reply
7 replies to this topic
IsNull
  • Moderators
  • 990 posts
  • Last active: May 15 2014 11:56 AM
  • Joined: 10 May 2007
Hi folks,

Well, I havn't problems (at least mostly) to call any dll. But there are some API Calls which require a pointer to a "Structure". And I don't know how to create this information structures.

For example: "AddPrinter" requieres an information buffer

HANDLE AddPrinter(
  LPTSTR *pName,     // server name
  DWORD Level,      // printer information level
  LPBYTE pPrinter   // printer information buffer
);

Well, this BUffer ist described here :arrow: http://msdn.microsof...023(VS.85).aspx


But how can I create this Typedef struct?

This "Information-Buffer" exists in many other cases (required in many api call ), so I have to understand that part well.

Hope someone can explain. :D

greetings
IsNull

[ Moderator!: MSDN link fixed ]

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

Hope someone can explain. :D


I have tried my best to explain how the structure stuff works..

[color=indigo]/*

Function DummyDllCall(
  LPBYTE pUserData // user information buffer
);

The USERDATA structure specifies detailed user information

typedef struct USERDATA {
  LPTSTR    pNick;
  LPTSTR    pJoined;
  DWORD     Posts;
  LPTSTR    pLocation;
}    


*/[/color]


Nick=IsNull
Joined=10 May 2007
Posts=66
Location=.switzerland

; Items 1,2 & 4 are strings - we have to obtain Pointers to null terminated strings
; Item 3 is already an Integer, so we can feed it into structure as value

pNick     := &Nick     
pJoined   := &Joined
pLocation := &Location 

; Lets view the Pointers

; MsgBox,0, Just viewing the Pointers,  % pNick "`n" pJoined "`n" pLocation


; // Encoding structure USERDATA //

; Items 1,2,3,4 - all are now UINTs. 
; 1 UINT needs 4 bytes, therefore 4 UINTs need 16 bytes

VarSetCapacity( USERDATA,16,0 ) ; empty structure created - with length of 16 bytes

; Now, put those 4 UINTs into Structure
NumPut( pNick,     USERDATA, 0, "UInt" ) ; Pointer inserted @ offset 0   
NumPut( pJoined,   USERDATA, 4, "UInt" ) ; Pointer inserted @ offset 4
NumPut( Posts,     USERDATA, 8, "UInt" ) ; UINT equals a DWORD - UINT inserted @ offset 8
NumPut( pLocation, USERDATA,12, "UInt" ) ; Pointer inserted @ offset 12

; Therefore -
; Structure USEDATA has been encoded with 4 elements
; 1,2 & 4 are Pointers to null terminated strings
; Item 3 is already a DWORD and so has been fed in directly

; // Lets call the Function DummyDllCall() and pass the structure USERDATA as parameter

DummyDllCall( &USERDATA )


Return                                                 ; // end of auto-execute section //

; The following WORKING FUNCTION will give you a crude idea on how the DLL Funtion would 
; retrieve the data from the structure USERDATA
 
DummyDllCall( pUserdata ) {
  pNick     := NumGet( pUserData+0 , 0, "UInt" ) ; Pointer to Null Terminated String     
  pJoined   := NumGet( pUserData+4 , 0, "UInt" ) ; Pointer to Null Terminated String
  Posts     := NumGet( pUserData+8 , 0, "UInt" ) ; is already Integer Data
  pLocation := NumGet( pUserData+12, 0, "UInt" ) ; Pointer to Null Terminated String
  
  VarSetCapacity( Nick    ,20,0 )
  VarSetCapacity( Joined  ,20,0 )
  VarSetCapacity( Location,20,0 )
      
  DllCall( "lstrcpyA", UInt,&Nick    , UInt,pNick )
  DllCall( "lstrcpyA", UInt,&Joined  , UInt,pJoined )
  DllCall( "lstrcpyA", UInt,&Location, UInt,pLocation )

  ; Repair the variables - i.e., Set Internal Variable Length right!
  VarSetCapacity( Nick, -1 ), VarSetCapacity( Joined,-1 ), VarSetCapacity( Location, -1 )
  
  MsgBox,0,DummyDllCall(), % Nick "`n" Joined "`n" Posts "`n" Location
}

:)
kWo4Lk1.png

IsNull
  • Moderators
  • 990 posts
  • Last active: May 15 2014 11:56 AM
  • Joined: 10 May 2007
wow, many many thanks SKAN, I think I understand most of that! :D

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

I think I understand most of that! :D


Do not hesitate to ask questions/clarification.. and BTW,
Are you comfortable with NumGet() and NumPut()?
Do you need explanation on how it works?

IsNull
  • Moderators
  • 990 posts
  • Last active: May 15 2014 11:56 AM
  • Joined: 10 May 2007
Hey SKAN,

Well I think I understand NUMPUT and NUMGET. Also Pointers and Adresses is clear for me.

Do not hesitate to ask questions/clarification..

I will not do so. :D

At the moment I'm writing a Tutorial about this "STRUCT" thing. It is in german, but I can translate it to english. For me, it's the best way to learn such things -writing a Tutorial for others shows my self how certain I am.

Well, there is still one little question:

Strings are normally submittet as "Pointer" (adress) -> uint (4 bytes)
Numbers are normally submittet directly, as DWORD, -> uint (4 bytes)

But, if a Number is too large for the uint, what happens?

Well, maby can use int64, (8 bytes), but you see, the core of the problem persists. What happens when the int64 is too small?
In this case, will the number be submittet as Pointer too?

Z_Gecko
  • Guests
  • Last active:
  • Joined: --
i might be totally wrong, but
i donĀ“t think integers can be bigger than 64-bit (8-byte).

For integers, 64-bit signed values are supported, which range from -9223372036854775808 (-0x8000000000000000) to 9223372036854775807 (0x7FFFFFFFFFFFFFFF).

as i understand this, anything longer will be treated as a string by ahk(and probably by any other 32/64-bit programming language).
So you can probably not submit any number large than 64-bit without using a pointer.

IsNull
  • Moderators
  • 990 posts
  • Last active: May 15 2014 11:56 AM
  • Joined: 10 May 2007

So you can probably not submit any number large than 64-bit without using a pointer.

Then, my guess was right. If something ist bigger, I have to handle it with a pointer,too.

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

Strings are normally submittet as "Pointer" (adress) -> uint (4 bytes)
Numbers are normally submittet directly, as DWORD, -> uint (4 bytes)
But, if a Number is too large for the uint, what happens?


The most significant bit/byte is ignored .. and this is documented under NumPut()
Strictly speaking, I have never encountered a neccessity for Large Integer with API till date, expect for File size, for which an UINT offers only 4GB as number.

Note: Natively, the maximum number AHK can handle is (2**63)-1
MsgBox, % (2**63)-1

In case, one needs to handle large integers, there is always: Machine code functions: Bit Wizardry posted by Laszlo

I repeat, even if one uses 8 byte to store an integer, which would occupy 64 bits, AHK would be able to extract unsigned integer from 63 bits only.

:)