Jump to content

DllCall() and proper types


 Share

Go to solution Solved by trancexx,

Recommended Posts

I'm having troubles understanding some special situations that I encounterd recently and that are closly related to function DllCall() and types used whith DllCall() function.

For example one call to function MessageBox from user32.dll. There shouldn't be any unknown things there:

MSDN description:

int MessageBox(   
    HWND hWnd,
    LPCTSTR lpText,
    LPCTSTR lpCaption,
    UINT uType
);

Autoit:

DllCall("user32.dll", "int", "MessageBox", "hwnd", 0, "str", "Text", "str", "Title", "dword", 48)

SmOke_N suggested that it could be done like this and in fact that it's the more proper way of diong the call (he demonstrated on function FindWindowEx):

DllCall("user32.dll", "int", "MessageBox", "hwnd", 0, "ptr", "Text", "ptr", "Title", "dword", 48)

If you run it you will see that it's obviously not a proper way.

Another way is to create structures and use pointers to them in DllCall():

$sTitle = "Title"
$tTitle = DllStructCreate("char[" & StringLen($sTitle) + 1 & "]") 
DllStructSetData($tTitle, 1, $sTitle)

$sText = "Text"
$tText = DllStructCreate("char[" & StringLen($sText) + 1 & "]") 
DllStructSetData($tText, 1, $sText)

DllCall("user32.dll", "int", "MessageBox", "hwnd", 0, "ptr", DllStructGetPtr($tText), "ptr", DllStructGetPtr($tTitle), "dword", 48)

Of course there could be any combination of two methods:

$sTitle = "Title"
$tTitle = DllStructCreate("char[" & StringLen($sTitle) + 1 & "]") 
DllStructSetData($tTitle, 1, $sTitle)

DllCall("user32.dll", "int", "MessageBox", "hwnd", 0, "str", "Text", "ptr", DllStructGetPtr($tTitle), "dword", 48)

... and the other way arround.

What can be concluded so far?

- "str", "string" will create pointer to null-terminated string in calls

- "ptr", $pointer will do the same thing if structure is oversized by 1 to make string null-terminated. Not oversizing is bad because pointer is not pointing to null-terminated string:

$sTitle = "Title"
$tTitle = DllStructCreate("char[" & StringLen($sTitle) & "]") 
DllStructSetData($tTitle, 1, $sTitle)

$sText = "Text"
$tText = DllStructCreate("char[" & StringLen($sText) & "]") 
DllStructSetData($tText, 1, $sText)

DllCall("user32.dll", "int", "MessageBox", "hwnd", 0, "ptr", DllStructGetPtr($tText), "ptr", DllStructGetPtr($tTitle), "dword", 48)

Btw, truncation of largely oversized char buffer is done by default and pointer to that will be pointer to null-terminated string.

That all looks logical but then there were this mentioned function FindWindowEx from user32.dll.

Something is wrong there, at least I cannot comprehend it. Situation there is that "ptr", $pointer works and "str", "string" is not working.

Will make new post (double-post, hate that) because this one is getting too large to follow.

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

First to go back and to mention the secial case when NULL pointer could be required in functions.

"str", "" is not the same as "ptr", 0 as I was noted by one member of stuff here. First is pointer to empty string. Pointer to something. Latter is null-pointer, pointer to nothing (to say it that way). There is a great difference.

OK, function is FindWindowEx from user32.dll. MSDN says:

HWND FindWindowEx(    
    HWND hwndParent,
    HWND hwndChildAfter,
    LPCTSTR lpszClass,
    LPCTSTR lpszWindow
);

What is different here? When you look to what is in code tags, almost nothing is different.

The difference is in description of parameters. You can find that here. That last parameter LPCTSTR lpszWindow can be either pointer to null-terminated string or NULL.

Since "str", "..." cannot produce NULL, only pointer to empty string in best case, to get the most of this function it would be better to use pointers. But... and this is what confuses me, and to show what is it I will repost working SmOke_N code:

hideStartButton()
Sleep(2000)
showStartButton()

Func hideStartButton()
   ;This Function Hides the Start Button
    Local Const $_SW_HIDE = 0
    
    Local $h_parent = _FindWindow("Shell_TrayWnd")
    If @error Then Return SetError(1, 0, 0)
    
    Local $h_child = _FindWindowEx("Button", "", $h_parent)
    If @error Then Return SetError(2, 0, 0)
    
    If _ShowWindow($h_child, $_SW_HIDE) Then Return SetError(0, 0, 1)
    Return SetError(3, 0, 0)
EndFunc

Func showStartButton()
   ;This Function Shows the Start Button
    Local Const $_SW_SHOW = 5
    Local $h_parent = _FindWindow("Shell_TrayWnd")
    If @error Then Return SetError(1, 0, 0)
    
    Local $h_child = _FindWindowEx("Button", "", $h_parent)
    If @error Then Return SetError(2, 0, 0)
    
    If _ShowWindow($h_child, $_SW_SHOW) Then Return SetError(0, 0, 1)
    Return SetError(3, 0, 0)
EndFunc

Func _FindWindow($s_class, $s_title = "")
    Local $t_class = DllStructCreate("char[" & StringLen($s_class) + 1 & "]")
    DllStructSetData($t_class, 1, $s_class)
    
    Local $t_title = DllStructCreate("char[" & StringLen($s_title) + 1 & "]")
    DllStructSetData($t_title, 1, $s_title)
    
    Local $h_wnd = DllCall("user32.dll", "hwnd", "FindWindow", _
                    "ptr", DllStructGetPtr($t_class), _
                    "ptr", DllStructGetPtr($s_title))
    
    If Not $h_wnd[0] Then Return SetError(1, 0, 0)
    Return $h_wnd[0]
EndFunc

Func _FindWindowEx($s_class, $s_title = "", $h_parent = 0, $h_child = 0)
    Local $t_class = DllStructCreate("char[" & StringLen($s_class) + 1 & "]")
    DllStructSetData($t_class, 1, $s_class)
    
    Local $t_title = DllStructCreate("char[" & StringLen($s_title) + 1 & "]")
    DllStructSetData($t_title, 1, $s_title)
    
    Local $h_wnd = DllCall("user32.dll", "hwnd", "FindWindowEx", _
                    "hwnd", $h_parent, _
                    "hwnd", $h_child, _
                    "ptr", DllStructGetPtr($t_class), _
                    "ptr", DllStructGetPtr($s_title))
    
    If Not $h_wnd[0] Then Return SetError(1, 0, 0)
    Return $h_wnd[0]
EndFunc

Func _ShowWindow($h_wnd, $i_flag)
    Local $a_ret = DllCall("user32.dll", "int", "ShowWindow", "hwnd", $h_wnd, "int", $i_flag)
    Return ($a_ret[0] <> 0)
EndFunc

That script will hide start button on XP for two seconds.

It's done with pointers and all works well. That code will never produce NULL pointer to pass to function call because all structures are by 1 larger then lenght of strings that fills them.

For example, empty string:

$sString = ""
$tString = DllStructCreate("char[" & StringLen($sString) + 1 & "]") 
DllStructSetData($tString, 1, $sString)
ConsoleWrite(DllStructGetPtr($tString, 1) & @CRLF)

My question is, why that script works and this one isn't?

hideStartButton()
Sleep(2000)
showStartButton()

Func hideStartButton()
   ;This Function Hides the Start Button
    Local Const $_SW_HIDE = 0
    
    Local $h_parent = _FindWindow("Shell_TrayWnd")
    If @error Then Return SetError(1, 0, 0)
    
    Local $h_child = _FindWindowEx("Button", "", $h_parent)
    If @error Then Return SetError(2, 0, 0)
    
    If _ShowWindow($h_child, $_SW_HIDE) Then Return SetError(0, 0, 1)
    Return SetError(3, 0, 0)
EndFunc

Func showStartButton()
   ;This Function Shows the Start Button
    Local Const $_SW_SHOW = 5
    Local $h_parent = _FindWindow("Shell_TrayWnd")
    If @error Then Return SetError(1, 0, 0)
    
    Local $h_child = _FindWindowEx("Button", "", $h_parent)
    If @error Then Return SetError(2, 0, 0)
    
    If _ShowWindow($h_child, $_SW_SHOW) Then Return SetError(0, 0, 1)
    Return SetError(3, 0, 0)
EndFunc

Func _FindWindow($s_class, $s_title = "")
    
    Local $h_wnd = DllCall("user32.dll", "hwnd", "FindWindow", _
                    "str", $s_class, _
                    "str", $s_title)
    
    If Not $h_wnd[0] Then Return SetError(1, 0, 0)
    Return $h_wnd[0]
EndFunc

Func _FindWindowEx($s_class, $s_title = "", $h_parent = 0, $h_child = 0)
    
    Local $h_wnd = DllCall("user32.dll", "hwnd", "FindWindowEx", _
                    "hwnd", $h_parent, _
                    "hwnd", $h_child, _
                    "str", $s_class, _
                    "str", $s_title)
    
    If Not $h_wnd[0] Then Return SetError(1, 0, 0)
    Return $h_wnd[0]
EndFunc

Func _ShowWindow($h_wnd, $i_flag)
    Local $a_ret = DllCall("user32.dll", "int", "ShowWindow", "hwnd", $h_wnd, "int", $i_flag)
    Return ($a_ret[0] <> 0)
EndFunc

If someone would care to explain it to me I would be deeply gratified.

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

  • Solution

The only difference between those two scripts is data types used in function DllCall().

One is "ptr" and pointer to buffer with null terminated string and the other is "str" and string.

At least I thought so till about 30 minutes ago.

SmOke_N made a mistake there. His passing pointers to strings (literaly) thus creating "ptr", 0 situation and that's why it appears that his code is working as it should be.

I guess not wanting to answer is also an answer (this person will know what I mean). Thanks again.

Knowing this, function _WinAPI_FindWindow() from WinAPI.au3 looks like it could be written maybe to be more complete. At least description of parameters should be modified. Currently is, for example:

$WindowName - A string that specifies the window name. If this parameter is blank, all window names match.

Not if blank and never in its current form.

Edited by trancexx

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

  • Moderators

The only difference between those two scripts is data types used in function DllCall().

One is "ptr" and pointer to buffer with null terminated string and the other is "str" and string.

At least I thought so till about 30 minutes ago.

SmOke_N made a mistake there. His passing pointers to strings (literaly) thus creating "ptr", 0 situation and that's why it appears that his code is working as it should be.

I guess not wanting to answer is also an answer (this person will know what I mean). Thanks again.

Knowing this, function _WinAPI_FindWindow() from WinAPI.au3 looks like it could be written maybe to be more complete. At least description of parameters should be modified. Currently is, for example:

$WindowName - A string that specifies the window name. If this parameter is blank, all window names match.

Not if blank and never in its current form.

I didn't make a mistake doing that, you may want to read what the options were for those two parameters I passed a null string ptr to.

I'm not sure what you mean by "not wanting to answer" and or if that was directed to me, I don't read every single post...

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

I didn't make a mistake doing that, you may want to read what the options were for those two parameters I passed a null string ptr to.

I'm not sure what you mean by "not wanting to answer" and or if that was directed to me, I don't read every single post...

Thing is that if one of you guys (green, red, blue) make a statement, not opinion (well... you know what I mean) here on forum I expect it to be true. So if you or anyone mentioned say for example: "This is true... this is true tooo,... this is not", I would expect first thing to be true, second also and third not. Otherwise too much energy is wasted on things that shouldn't be wasted on.

I'm sorry but that's the way I percept things. Burden is on you guys and you took it by your own free will.

Code posted by colored users is almost a fact (to me, that is).

You made a mistake in your code. This how (will stick to FindWindowEx function):

Func _FindWindowEx($s_class, $s_title = "", $h_parent = 0, $h_child = 0)
    Local $t_class = DllStructCreate("char[" & StringLen($s_class) + 1 & "]")
    DllStructSetData($t_class, 1, $s_class)
    
    Local $t_title = DllStructCreate("char[" & StringLen($s_title) + 1 & "]")
    DllStructSetData($t_title, 1, $s_title)
    
    Local $h_wnd = DllCall("user32.dll", "hwnd", "FindWindowEx", _
                    "hwnd", $h_parent, _
                    "hwnd", $h_child, _
                    "ptr", DllStructGetPtr($t_class), _
                    "ptr", DllStructGetPtr($s_title))
    
    If Not $h_wnd[0] Then Return SetError(1, 0, 0)
    Return $h_wnd[0]
EndFunc

You are creating structure named $t_title. Why? What is the use for it in your code?

There isn't any because there's no pointer to that. On the other hand you are making pointer to $s_title. Pointer to something that is not dll structure. The result of that is raising error and DllStructGetPtr() returning 0.

Respond to that is success of FindWindowEx funcion (sounds bizar) since it's provided by NULL ("ptr", 0)

Do you still think there's no mistake?

So, I guess, everyone makes mistakes, you here, PaulIA in description of _WinAPI_FindWindow() in WinAPI.au3, PsaltyDS the other day with $SystemPowerInformation structure (wrong data types, signed - unsigned) etc...

Morteza's code was as correct as yours (he is having array issue) only thing is that the last parameter in his FindWindowEx function should have been "str", "start".

- "not wanting to answer" was not about you.

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

  • Moderators

lpszWindow

[in] Pointer to a null-terminated string that specifies the window name (the window's title). If this parameter is NULL, all window names match.

So, if I actually pass a window title, it will be convert it to the null-terminated pointer that MSDN specifically indicates there. If I pass a blank string, it will convert it to a null-terminated pointer.

When you say someone is wrong. Please be sure they are.

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

So, if I actually pass a window title, it will be convert it to the null-terminated pointer that MSDN specifically indicates there. If I pass a blank string, it will convert it to a null-terminated pointer.

When you say someone is wrong. Please be sure they are.

"str", "string" is pointer to null-terminated string "string"

"str", "" is pointer to null-terminated empty string

"ptr", 0 is NULL

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...