Jump to content

DllCall and User32.dll Help Please


Recommended Posts

  • Moderators

The rect parameter is ok because 0 means use the client area. The problem is that the 4 is in the wrong place.

Here is ssubirias3's code with just the 4 moved. This works for me.

Opt("WinTitleMatchMode", 4)

For $n = 0 To 14
    Run("notepad.exe")
Next
Sleep(2000);; allow all notepads to be grouped by WinXP
$avHWND = WinList("[Class:Notepad]")

$Kids = DllStructCreate("int[15]");; 15 notepad windows to cascade
For $n = 1 To $avHWND[0][0]
    DllStructSetData($Kids, 1, $avHWND[$n][1], $n)
Next
$pKids = DllStructGetPtr($Kids)
DllCall("USER32.dll", "int", "CascadeWindows", "hwnd", 0, "int", 0, "int", 4, "int", $nArraysize, "int", $ptHWND)

BTW ssubirias3, I would have liked it if you had added something to delete all those notepads you left scattered across my desktop!

That's a good point... I did it quickly (btw.. your code is using the wrong vars)

@weapon yes... we are looping :)

Fun Times:

WinSetState(WinGetHandle(""), "", @SW_MINIMIZE)
_WinCascade("Notepad");Note I believe the class is case sensitive
Sleep(3000)
_WinTile("Notepad")

Func _WinCascade($szClassName)
    Local $aWL = WinList('[Class:' & $szClassName & ']')
    If IsArray($aWL) = 0 Then Return SetError(1, 0, 0)
    Local $tStruct = DllStructCreate('hwnd[' & UBound($aWL) & ']')
    For $iCC = 1 To UBound($aWL) - 1
        DllStructSetData($tStruct, 1, $aWL[$iCC][1], $iCC)
    Next
    Local $ptHWND = DllStructGetPtr($tStruct)
    DllCall("USER32.dll", "int", "CascadeWindows", "hwnd", 0, "int", 0, "int", 0, "int", $aWL[0][0], "ptr", $ptHWND)
    Return (@error = 0)
EndFunc
Func _WinTile($szClassName, $nVert = 0)
    ;MDITILE_VERTICAL = &H0
    ;MDITILE_HORIZONTAL = &H1
    ;MDITILE_SKIPDISABLED = &H2
    ;MDITILE_ZORDER = &H4
    Local $aWL = WinList('[Class:' & $szClassName & ']')
    If IsArray($aWL) = 0 Then Return SetError(1, 0, 0)
    Local $tStruct = DllStructCreate('hwnd[' & UBound($aWL) & ']')
    For $iCC = 1 To UBound($aWL) - 1
        DllStructSetData($tStruct, 1, $aWL[$iCC][1], $iCC)
    Next
    Local $ptHWND = DllStructGetPtr($tStruct)
    DllCall("USER32.dll", "int", "TileWindows", "hwnd", 0, "int", $nVert, "int", 0, "int", $aWL[0][0], "ptr", $ptHWND)
    Return (@error = 0)
EndFunc
Edited by SmOke_N

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

@weaponx - yeah looks like you were on da money about having to loop. Any attempts I've made without the loop did not produce the desired end result. Sure the 2 seconds could be a non-issue in most cases, but in my situation I'm using this with something other than notepad and there are more than 15 windows ;). As the number of windows increases so does the lag. Even with the loop and extra lines of code for the DllStruct...() stuff, this is blazing fast compared to WinSetState() and WinActivate()! Didn't mean to come across wrong if I did.

@Martin - Thanks for breaking it down a second time in pre-skool terms for me :) And that's pretty amazing that you claim you didn't know this stuff until recently? Very cool, hats off to you for sure! But one thing that doesn't jive with me is the Help file suggests the values and parameters after the function name are "optional." I guess that's what was kinda throwing me off a bit. Now that I know to first check out msdn to see what the function needs. If it has 8 parameters then I should provide 16 values (8 sets) after the function name, just to be safe. Right?

@SmOke_N - some good looking functions there brother! Couple of questions, if you don't mind. If we're using WinList() to get the handles and WinList() returns a 2d array, why are you using IsArray? Even if you set $avTest = WinList("[Class:IDontExist]") the array is still created. Atleast in my test _ArrayDisplay thought $avTest was a valid array.

Also in my testing I didn't see any difference between the following snippets. Just wondering why you elected to use "hwnd" and "ptr" instead of "int". It seems to make more sense your way. I want to make sure I'm not missing an important reason/detail.

DllCall("user32.dll", "int", "CascadeWindows", "int", 0, "int", 0, "int", 0, "int", $avHWND[0][0], "int", $pKids)oÝ÷ Ù«­¢+Ù±±
±° ÅÕ½ÐíUMHÌȹ±°ÅÕ½Ðì°ÅÕ½Ðí¥¹ÐÅÕ½Ðì°ÅÕ½Ðí
Í]¥¹½ÝÌÅÕ½Ðì°ÅÕ½Ðí¡Ý¹ÅÕ½Ðì°À°ÅÕ½Ðí¥¹ÐÅÕ½Ðì°À°ÅÕ½Ðí¥¹ÐÅÕ½Ðì°À°ÅÕ½Ðí¥¹ÐÅÕ½Ðì°ÀÌØíÙ!]9lÁulÁt°ÅÕ½ÐíÁÑÈÅÕ½Ðì°ÀÌØíÁ-¥Ì

This has been fun and educational, at least for me! Hopefully other noobs interested in DllCall() will find this helpful. Very cool stuff, but still much to learn I have.

Link to comment
Share on other sites

  • Moderators

@SmOke_N - some good looking functions there brother! Couple of questions, if you don't mind. If we're using WinList() to get the handles and WinList() returns a 2d array, why are you using IsArray? Even if you set $avTest = WinList("[Class:IDontExist]") the array is still created. Atleast in my test _ArrayDisplay thought $avTest was a valid array.

It's a habit from usually trying to error check my work, if you're playing with arrays, and are "generating" one from a var that isn't already one, you want to check if it is an array before continue so you don't GPF all over the place.

Also in my testing I didn't see any difference between the following snippets. Just wondering why you elected to use "hwnd" and "ptr" instead of "int". It seems to make more sense your way. I want to make sure I'm not missing an important reason/detail.

Not till recently had I really played with DLLs, matter of fact, not until about a month ago... I try to follow the set pattern that the api has set out for it... AutoIt makes room for some options.

http://www.autoitscript.com/forum/index.php?showtopic=7072

So when you are looking up API calls such as CascadeWindows you'll see the reference to the type it is referring too next to it:

WORD CascadeWindows(

HWND hwndParent,

UINT wHow,

const RECT *lpRect,

UINT cKids,

const HWND *lpKids

);

The red is the return type, if you look on the allowed DLL call types, you won't see WORD so it was substituted with int

On the orange one, even though it says HWND you'll see the * next to lpKids, if you didn't read the documentation (which obviously you would want to) that's an indicator that it is a "ptr", since we can't define two HWND_PTR like they (autoit) have INT_PTR I just used ptr.

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

Not till recently had I really played with DLLs, matter of fact, not until about a month ago... I try to follow the set pattern that the api has set out for it... AutoIt makes room for some options.

http://www.autoitscript.com/forum/index.php?showtopic=7072

So when you are looking up API calls such as CascadeWindows you'll see the reference to the type it is referring too next to it:

The red is the return type, if you look on the allowed DLL call types, you won't see WORD so it was substituted with int

On the orange one, even though it says HWND you'll see the * next to lpKids, if you didn't read the documentation (which obviously you would want to) that's an indicator that it is a "ptr", since we can't define two HWND_PTR like they (autoit) have INT_PTR I just used ptr.

I think I'm starting to make some progress. BTW, that link you and Zedna gave me I had already read through the complete thread before posting this question, I didn't really understand what Jon and the "developers" was talking about until now. Let's see if I got this straight, please bear with me and thanks for your patience.

Moving forward, what I and other noobs should be able to do is

  • search the dll function we want to use with DllCall at the msdn library
  • get the function's parmeters, i.e., CascadeWindows
    WORD CascadeWindows(      
        HWND hwndParent,
        UINT wHow,
        const RECT *lpRect,
        UINT cKids,
        const HWND *lpKids
    );
  • match up the all caps words (Windows DataType), not including WORD, against Jon's list (topic 7072's link mentioned above)
  • if necessary build the DllStruct using DllStructCreate(), DllStructSetData(), DllStructGetPtr()
  • use the correct autoit DllCall type in the DllCall() command
If this is correct, it seems pretty easy after you guys helped me get a grasp on this. But I couldn't find the Windows DataType RECT in Jon's list or the msdn full list of Windows DataTypes. Based on what you explained about the *lp meaning pointer or "ptr" why didn't you use "ptr" instead of "int" as you did with HWND *lpKids? Likewise, if we use Jon's List to convert Windows DataTypes to AutoIt DllCall Types with MSDN and examine the following DllCall() Help file example code snippet, a similiar question can be asked.

DLLCALL HELP FILE SNIPPET:

DllCall("kernel32.dll", "int", "WideCharToMultiByte", "int", 0, "int", 0x00000200, "ptr", DllStructGetPtr($stString), "int", -1, "ptr", DllStructGetPtr($stFile), "int", $nBuffersize[0], "ptr", 0, "ptr", 0)

WIDECHARTOMULTIBYTE PARAMETERS FROM MSDN2

int WideCharToMultiByte(
  UINT CodePage, 
  DWORD dwFlags, 
  LPCWSTR lpWideCharStr,
  int cchWideChar, 
  LPSTR lpMultiByteStr, 
  int cbMultiByte,
  LPCSTR lpDefaultChar, 
  LPBOOL lpUsedDefaultChar
);

EXCERPT FROM MSDN2 ON WINDOWS DATATYPES

LPCSTR Pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts.

LPCTSTR An LPCWSTR if UNICODE is defined, an LPCSTR otherwise.

LPCWSTR Pointer to a constant null-terminated string of 16-bit Unicode characters. For more information, see Character Sets Used By Fonts.

EXCERPT FROM JON'S LIST

INT = "int"

LONG = "long"

LPARAM = "long"

LPCTSTR = "str" ("wstr" if a UNICODE function)

LPINT = "int_ptr"

LPLONG = "long_ptr"

UINT = "int"

Using the MSDN2 information the snippet looks correct using "ptr", however using Jon's List, shouldn't the Help file snippet use "str" instead of "ptr"? Or does it really not matter since its all the same if you use "int" or "str" or "ptr" or "int_ptr"? My apologies if this is a really stupid question. I'm just trying to make clear sense of the available information. Again I do appreciate all the insight and hand holding on this topic.
Link to comment
Share on other sites

  • Moderators

We are full of questions aren't we... that's good :)

Instead of copying and pasting, I'm going to try and answer them as I saw specific questions.

  • I didn't use "ptr" for the rect because if you read the "allowed" values, there was a "ptr" to a rectangle, or a "NULL" value. We don't have a NULL option, so we use "0" which is an integer in it's place, I could have also done that with the null hwnd I suppose.
  • a RECT ptr has 4 values.

    ptr.left < (left) that's the starting point of the "X" value of the rectangle (top left)

    ptr.top < (top) that's the starting point of the "Y" value of the rectangle (top left)

    ptr.right < (right) that's the ending point of the "X" value of the rectangle (bottom right)

    ptr.bottom < (bottom) that's the ending point of the "Y" value of the rectangle (bottom right)

    With those 4 values you have a starting x and y and an ending x and y that make up your rectangle.

    Since we don't have the means of using RECT if you were ever going to use it you would probably do something like (mind you, I've never had to use RECT with autoit up to this point):

    $tStruct = DllStructCreate("int[4]");4 points of values that are integers
    $left = 0
    $top = 0
    $right = @DesktopWidth
    $bottom = @DesktopHeight
    DllStructSetData($tStruct, 1, $left, 1)
    DllStructSetData($tStruct, 1, $top, 2)
    DllStructSetData($tStruct, 1, $right, 3)
    DllStructSetData($tStruct, 1, $bottom, 4)
    $rect = DllStructGetPtr($tStruct);Now $rect holds our left/top/right/bottom values in a type of array basically
    
    Then when retrieving the data later, you would use DllStructGetData($tStruct, 1, N).. N being the number you want to retrieve of the "ptr/array"

    Obviously it's not necessary in this point to have the variables $left/$top etc... when you could just set the values manually int he SetValue, but you may want to create some of your own functions with parameters like that, so this would give you an idea on how to make it work.

    I don't know if the above is a working example, I typed it in the fast reply box.

  • I'm not sure what you're asking about the helpfile snippet, but the little bit I looked at it, it seemed they followed the list, keeping in mind that not all the data types are available, so you try to make the best with what you have and pray for no GPF's ;)

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

@SmOke_N - again thank you so much for your patience and yes, my level of inquisitiveness can be off the chart at time :). Your first response seems to support my previous conclusion. That using any of the AutoIt DllCall Types in place of Windows' DataTypes doesn't really matter. As you said we could have used "int", "ptr", or "hwnd" its basically the same difference. And earlier I thought you said you used "ptr" instead in "int_ptr" for the parameter const HWND *lpKids

even though it says HWND you'll see the * next to lpKids, ... that's an indicator that it is a "ptr", .... (autoit) have INT_PTR I just used ptr.

Your second response about RECT makes more sense now. I guess since the left, top, right, bottom coord were not specified Windows starts the cascade from the 0,0 position. And one possible reason to use something other than "int", 0 would be if you wanted to create a RECTangle area the cascade should stay within??

The reason for my mentioning the DllCall Help file snippet was to make sense of which AutoIt DllCall Types were the correct ones to use. From my noob perspective, there seems to be a contradiction with Jon's list or it really doesn't matter what AutoIt DllCall Types are used. Meaning Jon's list suggestions for DllCall Types inplace of Windows DataTypes beginning with "LP". Here's an MSDN2 quote from the 2nd paragraph of Windows DataTypes page.

... the following types: character, integer, Boolean, pointer, and handle. .... Most of the pointer-type names begin with a prefix of P or LP. ...

It's not clear to me why Jon's list suggests the Windows DataType LPARAM = AutoIt DllCall DataType "long" or LPCTSTR = "str" or "wstr" instead of "ptr".

LPARAM = "long"

LPCTSTR = "str" ("wstr" if a UNICODE function)

LPINT = "int_ptr"

LPLONG = "long_ptr"

Based on my testing the following AutoIt DllCall Types seem to have the same effect and appear to be interchangeable; "int", "ptr", "hwnd", "long". If they are interchangeable, thereby suggesting they are the same, why not simplify this and say that Windows DataTypes will fall into one of a shorter and less redundant AutoIt DllCall Types list? Having 4 DllCall Types that do or mean the same thing seems to make this more confusing than it needs to be. Then again it could just be me. I don't want to overlook any small but important detail. I do thank you and others for helping me get a better understanding around this.

Btw, the reason I think "int", "ptr", "hwnd", "long" have the same effect is the following snippets produces the same result.

DllCall("USER32.dll", "int", "CascadeWindows", "int", 0, "int", 0, "int", 0, "int", $avHWND[0][0], "int", $pKids)

DllCall("USER32.dll", "ptr", "CascadeWindows", "ptr", 0, "ptr", 0, "ptr", 0, "ptr", $avHWND[0][0], "ptr", $pKids)

DllCall("USER32.dll", "hwnd", "CascadeWindows", "hwnd", 0, "hwnd", 0, "hwnd", 0, "hwnd", $avHWND[0][0], "hwnd", $pKids)

DllCall("USER32.dll", "long", "CascadeWindows", "long", 0, "long", 0, "long", 0, "long", $avHWND[0][0], "long", $pKids)

DllCall("USER32.dll", "hwnd", "CascadeWindows", "ptr", 0, "int", 0, "hwnd", 0, "int", $avHWND[0][0], "long", $pKids)
Link to comment
Share on other sites

  • Moderators

Just because you're able to pass a windows API a certain type of call, doesn't mean that you will be able to do that with all the dll's you play with.

Mine is not to reason why :) ...

I do know, as you move into other languages, you'll be hard pressed to find them as forgiving as autoit is at times, so it's better to start learning "good" habits rather than forming bad ones (harder to break).

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

Mine is not to reason why :) ...

I do know, as you move into other languages, you'll be hard pressed to find them as forgiving as autoit is at times, so it's better to start learning "good" habits rather than forming bad ones (harder to break).

Now you're speaking my language and that's one reason I ask so many questions. I want to understand why so I can guard against bad habits before they start. Mine is not to accept it just because ;). I'll ask Jon if he can help me understand the reason or value of having "int", "ptr", "hwnd", and "long" act the same way. Thanks again SmOke_N, Marin, and the others on this thread for splain'n dis to me betta.
Link to comment
Share on other sites

  • Administrators

On 32 bit machines int, long, HWND (which is a ptr), ptr are all stored as 32 bit values. At the assembly level, when you call a function you just "push" the parameters (all 32 bits) onto the stack and then the function "pops" them off the stack. There is no concept of "type" at that level.

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...