Sign in to follow this  
Followers 0
ssubirias3

DllCall and User32.dll Help Please

30 posts in this topic

I found the following code in the forum but I'm having some trouble making sense of it when I try and match it up against the Help file.

DllCall

--------------------------------------------------------------------------------

Dynamically calls a function in a DLL.

DllCall ( "dll", "return type", "function" [, "type1", param1 [, "type n", param n]] )

DllCall("user32.dll", "int", "CascadeWindows", "int", 0, "int", 4, "int", 0, "int", 0, "int", 0)

The code works, but not like I want it to. If you right click the WinXP taskbar you will see several options from Cascade to Tile windows. Clicking these options will effect the selected command on all open windows. What I want is to cascade only a group of windows. For example if I have 5 notepad and 3 explorer windows open I want to Cascade the 5 notepad windows without affected the 3 explorer windows. Hopefully this makes sense.

I'm guessing the tweak will be to modify the "4" in the above code, but I'm not having any luck getting the desired effect. And I'd really appreciate if some of the gurus/developers would help me understand how to use this really cool feature. It could just be me, but this syntax format isn't the easiest or clearest to understand. Not having a background in this stuff doesn't make it any easier for me :).

What I'm guessing the above code is telling the script to ... "call the CascadeWindows function from withing the user32.dll." But the whole "int" / return a 32 bit integer and other "optional" stuff in the command is total greek to me. Please, please, pretty please, help me. Thanks in advance!

Share this post


Link to post
Share on other sites



I found the following code in the forum but I'm having some trouble making sense of it when I try and match it up against the Help file.

DllCall("user32.dll", "int", "CascadeWindows", "int", 0, "int", 4, "int", 0, "int", 0, "int", 0)

The code works, but not like I want it to. If you right click the WinXP taskbar you will see several options from Cascade to Tile windows. Clicking these options will effect the selected command on all open windows. What I want is to cascade only a group of windows. For example if I have 5 notepad and 3 explorer windows open I want to Cascade the 5 notepad windows without affected the 3 explorer windows. Hopefully this makes sense.

I'm guessing the tweak will be to modify the "4" in the above code, but I'm not having any luck getting the desired effect. And I'd really appreciate if some of the gurus/developers would help me understand how to use this really cool feature. It could just be me, but this syntax format isn't the easiest or clearest to understand. Not having a background in this stuff doesn't make it any easier for me :).

What I'm guessing the above code is telling the script to ... "call the CascadeWindows function from withing the user32.dll." But the whole "int" / return a 32 bit integer and other "optional" stuff in the command is total greek to me. Please, please, pretty please, help me. Thanks in advance!

You need to read up on the function here.

To limit the number of windows cascaded you need to set up an array of handles to the child windows to cascade then pass a pointer to the array as the final parameter. Does that make sense? (Assuming I read it right.)


Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

You need to read up on the function here.

To limit the number of windows cascaded you need to set up an array of handles to the child windows to cascade then pass a pointer to the array as the final parameter. Does that make sense? (Assuming I read it right.)

Thanks for the quick reply Martin! The only problem is that this stuff at msdn looks greet to me too. What I'm trying to figure out is how the autoit code matches up with the msdn code??
DllCall("user32.dll", "int", "CascadeWindows", "int", 0, "int", 4, "int", 0, "int", 0, "int", 0)

MSDN code:

WORD CascadeWindows(      
    HWND hwndParent,
    UINT wHow,
    const RECT *lpRect,
    UINT cKids,
    const HWND *lpKids
);

And to your point of having an array, yes already have that setup by using Global $avWHL = WinList("[Class:Notepad]"). So my message is asking for three things -- a. what modification is necessary to the above autoit code, b. the value "4" in the above dllcall code represents what; wHow, lpRect, cKids??, and c. how does the autoit dllcall translate to the msdn stuff. How does a noob know what to type into the "optional" paramaters to get their expected result. Thanks!

Share this post


Link to post
Share on other sites

Thanks for the quick reply Martin! The only problem is that this stuff at msdn looks greet to me too. What I'm trying to figure out is how the autoit code matches up with the msdn code??

DllCall("user32.dll", "int", "CascadeWindows", "int", 0, "int", 4, "int", 0, "int", 0, "int", 0)

MSDN code:

WORD CascadeWindows(      
    HWND hwndParent,
    UINT wHow,
    const RECT *lpRect,
    UINT cKids,
    const HWND *lpKids
);

And to your point of having an array, yes already have that setup by using Global $avWHL = WinList("[Class:Notepad]"). So my message is asking for three things -- a. what modification is necessary to the above autoit code, b. the value "4" in the above dllcall code represents what; wHow, lpRect, cKids??, and c. how does the autoit dllcall translate to the msdn stuff. How does a noob know what to type into the "optional" paramaters to get their expected result. Thanks!

What youneed to do is

1) get the handles for all the child windows you need to cascade. You've not quite done that; WInGetList returns an array of titles.

So have some loop or something to get the handles $ChildHandle[0] = WinGetHandle($avWHL[0]) say

2) Create a struct like this

$Kids = DllStructCreate("int[4]");assuming there are 4 windows to cascade

3) set the values of each element with the handles of the windows

for $n = 1 to 4

DllStructSetData($Kids,1,$ChildWindowHandle[$n-1],$n)

next

4) Get a pointer to the struct

$pKids = DllStructGetPtr($Kids)

5) in the DllCall, instead of 0 for the last parameter, put $pKids

That should do it.


Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

And to your point of having an array, yes already have that setup by using Global $avWHL = WinList("[Class:Notepad]"). So my message is asking for three things -- a. what modification is necessary to the above autoit code, b. the value "4" in the above dllcall code represents what; wHow, lpRect, cKids??, and c. how does the autoit dllcall translate to the msdn stuff. How does a noob know what to type into the "optional" paramaters to get their expected result. Thanks!

1) 4 is for wHow

2) about DllCall also look here

Share this post


Link to post
Share on other sites

What youneed to do is

1) get the handles for all the child windows you need to cascade. You've not quite done that; WInGetList returns an array of titles....

Very cool! Thank you Martin [da man!] and Zedna for the answers and direction. I'll follow up with my results and what I landed on with the final code! Meanwhile, I did want to mention that I'm using WinList not WinGetTitle :). WinList returns a 2d array w/ the title and handles, a very cool feature that PsaltyDS schooled me on a while back.

WinList

--------------------------------------------------------------------------------

Retrieves a list of windows.

WinList ( ["title" [, "text"]] )

:

Return Value

Returns an array of matching window titles and handles.

Share this post


Link to post
Share on other sites

Meanwhile, I did want to mention that I'm using WinList not WinGetTitle :). WinList returns a 2d array w/ the title and handles, a very cool feature that PsaltyDS schooled me on a while back.

Oh yes, sorry I didn't read that correctly.


Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

Hi, thanks for the info in this thread, works great.

The only thing I think that sorta bites is when you cascade your selected windows , if you have other windows Maximized then they get restored...

CascadeSelectedWindows("[Class:Notepad]")

Func CascadeSelectedWindows($wTitle, $wTText = "")
    Dim $nWL = WinList($wTitle, $wTText)
    If $nWL[0][0] > 0 Then
        Local $lpkids = DllStructCreate("int[" & $nWL[0][0] & "]")
        For $i = 1 to $nWL[0][0]
            DllStructSetData($lpkids,1,$nWL[$i][1],$i)
        Next
        DllCall("user32.dll", "int", "CascadeWindows", "int", 0, "int", 4, "int", 0, "int", $nWL[0][0], "int", DllStructGetPtr($lpKids))
        $lpkids = 0
    Else
        MsgBox(0, "No Matching Windows", "No matching windows to cascade")
    EndIf
EndFunc

Cheers

Edited by smashly

Share this post


Link to post
Share on other sites

Cascade only affects windows that aren't minimized to the taskbar, just minimize all windows that aren't notepad and then run your cascade dllcall. This just seems easier to me.

WinMinimizeAll ( )
$List = WinList("[Class:Notepad]")

For $X = 1 to $List[0][0]
        WinSetState ( $List[$X][0], "", @SW_MAXIMIZE)
Next
DllCall("user32.dll", "int", "CascadeWindows", "int", 0, "int", 4, "int", 0, "int", 0, "int", 0)

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

Hi,

That in theory sounds good weaponx , but it fails for me when I tried your example ..

But I do like the logic you used :)

Cheers

Edit: It works if I use the handle instead of title though eg; WinSetState ( $List[$X][1], "", @SW_RESTORE)

Edited by smashly

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

Hi,

That in theory sounds good weaponx , but it fails for me when I tried your example ..

But I do like the logic you used :)

Cheers

Edit: It works if I use the handle instead of title though eg; WinSetState ( $List[$X][1], "", @SW_RESTORE)

Works fine for me. Did you have any notepad windows opened?

Edit: late post

Edited by weaponx

Share this post


Link to post
Share on other sites

15 notepad windows open at the time.. :)

Share this post


Link to post
Share on other sites

Cascade only affects windows that aren't minimized to the taskbar, just minimize all windows that aren't notepad and then run your cascade dllcall. This just seems easier to me.

WinMinimizeAll ( )
$List = WinList("[Class:Notepad]")

For $X = 1 to $List[0][0]
        WinSetState ( $List[$X][0], "", @SW_MAXIMIZE)
Next
DllCall("user32.dll", "int", "CascadeWindows", "int", 0, "int", 4, "int", 0, "int", 0, "int", 0)oÝ÷ Ûú®¢×°yªh.¦Ë©z¸^®ájy,~íë.¬¶*'¡û¬xtµ+Zµæ§vØ^IcdGåj¡jg¨g¢¹èµÉZ®'âaÊh{^j¹bz¶î¶Ø^­æ¬¢r0j{^.±àå&¥+ºÊ^yßîý²Ê¡j÷µæz-)Ý£(¥éÚÙh¢a® Ø^ÚØ^­h§IëRµ«^IcdJ+Z)Àrدj×­«p¢¹,~)Þ>ºé¢²ØZ¶+}ýµ«jËb*.®(!µÉbrKazz-.¦íëZ²FÚ­©Ý±é^rбÆzÓÙ^Z)Ý£wZ)×>IèÂÌ!z{h    «i×"Ú0²Úº.¦ðwhÂÇ^¥éÝx(^­ëaz¸ ×%É"±ì^^uúèØZ·l­#f¶¼¢hzk¥j׶ÇÆÚÞvéÝz{m¢¯y«­¢+e¢mº.§jºÚÉú+©Ýë0é×=Ú²}ýµÊ'²émjv®¶­jºÚÊÚ)z·è®kax&¬q§^~éܶ*'¢v ®©¡ü"Ú0°¸¤{¬{^*.®(!µÉbrJ'j
躧¶«z+mí ȧh³xjèº0¢é]mè+y«b}h§2)â,ÞYp¢é]²êi¢»mëb¶W¬¢ØZµh§2)â,ÞYjºB«,6^¥§jºp¢é]¢yr)â,ÞjYpwhÂɵÈbajÛb¶Wjg­)àÂ+aZ)Ìx¦7U'v®Ø§Êë¢Ø^¬èZ0yܨº¸§²ÚîrبÆÞ²Ò¢é]m觩衶§u©enëb¶Éè·
+)àêÞßÛ-ç(uæ§Ê'^jÌ!Ê+'ßÛg¢Ü(®H§«Æµç@Ê"~Øb±Ú²}ýµé®«^z«ÞÅÇ¥h­j×°Ø^}ú+¶Úªæ¥¢».®¬²Ø^®(!µÉbrH§Úº.¥©Ý±é^rا&¬q§^¶§q©ò¢è.ÊÈ^iÈbz÷¦Ê
8ZK"§ojwßv®¶­sd÷BgV÷CµvåFFÆTÖF6ÖöFRgV÷C²ÂB ¤f÷"b33c¶âÒFò@ 'VâgV÷C¶æ÷FWBæWRgV÷C²¤æW@¥6ÆVW#³²ÆÆ÷rÆÂæ÷FWG2Fò&Rw&÷WVB'vå¢b33c¶dtäBÒväÆ7BgV÷Cµ´6Æ73¤æ÷FWEÒgV÷C² ¢b33c´¶G2ÒFÆÅ7G'V7D7&VFRgV÷C¶çE³UÒgV÷C²³²Ræ÷FWBvæF÷w2Fò666FP¤f÷"b33c¶âÒFòb33c¶dtäE³Õ³Ð FÆÅ7G'V7E6WDFFb33c´¶G2ÂÂb33c¶dtäE²b33c¶åÕ³ÒÂb33c¶â¤æW@¢b33c·¶G2ÒFÆÅ7G'V7DvWEG"b33c´¶G2¤FÆÄ6ÆÂgV÷C·W6W#3"æFÆÂgV÷C²ÂgV÷C¶çBgV÷C²ÂgV÷C´666FUvæF÷w2gV÷C²ÂgV÷C¶çBgV÷C²ÂÂgV÷C¶çBgV÷C²ÂBÂgV÷C¶çBgV÷C²ÂÂgV÷C¶çBgV÷C²ÂÂgV÷C¶çBgV÷C²Âb33c·¶G2

Share this post


Link to post
Share on other sites

15 notepad windows open at the time.. :)

What version of autoit are you using, I had 13 notepads open and it worked fine... is this throwing it off?
WinList("[Class:Notepad]")
? Might try wintitlematchmode, 4 and "classname=Notepad"

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.

Share this post


Link to post
Share on other sites

smashly was kind of right, this worked better:

WinMinimizeAll ( )
$List = WinList("[Class:Notepad]")

For $X = 1 to $List[0][0]
        WinSetState ( $List[$X][1], "", @SW_MAXIMIZE)
Next
DllCall("user32.dll", "int", "CascadeWindows", "int", 0, "int", 4, "int", 0, "int", 0, "int", 0)

And after I compiled it was quite fast. At some point you are going to have to loop through a list of windows.

Share this post


Link to post
Share on other sites

Hey, there's a lot you can do with this... I don't have time, but someone should add the RECT/PARENT param

WinSetState(WinGetHandle(""), "", @SW_MINIMIZE);I was using SciTe and wanted to watch the cascade.
Sleep(3000)
MsgBox(0,"Return Value",_WinCascade("Notepad"));Note I believe the class is case sensitive


Func _WinCascade($szClassName, $bMinAll = 0);Probably want to add the other 2 or 3 options (rect/parent etc)
    Local $aWL = WinList('[Class:' & $szClassName & ']')
    Local $sHoldHwnd, $nArraysize, $tStruct, $ptHWND
    For $iCC = 1 To UBound($aWL) - 1
        $sHoldHwnd &= "hwnd;"
    Next
    $tStruct = DllStructCreate(StringTrimRight($sHoldHwnd, 1))
    For $iCC = 1 To UBound($aWL) - 1
        ConsoleWrite($awl[$iCC][0] & @LF)
        DllStructSetData($tStruct, $iCC, $aWL[$iCC][1])
        $nArraysize += 1
    Next
    $ptHWND = DllStructGetPtr($tStruct)
    DllCall("USER32.dll", "int", "CascadeWindows", "hwnd", 0, "int", 4, "int", 0, "int", $nArraysize, "int", $ptHWND)
    Return (@error = 0)
EndFunc


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.

Share this post


Link to post
Share on other sites

#17 ·  Posted (edited)

Hey, there's a lot you can do with this... I don't have time, but someone should add the RECT/PARENT param

WinSetState(WinGetHandle(""), "", @SW_MINIMIZE);I was using SciTe and wanted to watch the cascade.
Sleep(3000)
MsgBox(0,"Return Value",_WinCascade("Notepad"));Note I believe the class is case sensitive
Func _WinCascade($szClassName, $bMinAll = 0);Probably want to add the other 2 or 3 options (rect/parent etc)
    Local $aWL = WinList('[Class:' & $szClassName & ']')
    Local $sHoldHwnd, $nArraysize, $tStruct, $ptHWND
    For $iCC = 1 To UBound($aWL) - 1
        $sHoldHwnd &= "hwnd;"
    Next
    $tStruct = DllStructCreate(StringTrimRight($sHoldHwnd, 1))
    For $iCC = 1 To UBound($aWL) - 1
        ConsoleWrite($awl[$iCC][0] & @LF)
        DllStructSetData($tStruct, $iCC, $aWL[$iCC][1])
        $nArraysize += 1
    Next
    $ptHWND = DllStructGetPtr($tStruct)
    DllCall("USER32.dll", "int", "CascadeWindows", "hwnd", 0, "int", 4, "int", 0, "int", $nArraysize, "int", $ptHWND)
    Return (@error = 0)
EndFunc

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!

Edited by martin

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

#18 ·  Posted (edited)

And after I compiled it was quite fast. At some point you are going to have to loop through a list of windows.

After it was compiled?? That's not in scope, my brother! ;) I don't want to accept the idea of having to loop through the handles... NO, NO, NO! :) Like I said before Windows doesn't have to loop through any stinking array to quickly Cascade, Title, Minimize, or Close a Group.

Hey, there's a lot you can do with this... I don't have time, but someone should add the RECT/PARENT param

SmOke_N you are one of "da man" around here, that's for sure!! I'll have to dissect this code later and I'm sure I'll learn a lot by looking through this. As I've said before you are an ocean of knowledge... I just need to make sure I'm wearing my water wings if you know what I mean :(.

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!

You funny Martin! If you Group similar taskbar buttons then all you gots to do is right click and Close Group. But I'm sure you already knew that, being the bad mama-a-jama that you are! Thanks for telling me that the "4" was in the wrong place, but how should have a noob known to move it out?? Like I said in da beginning I ain't gots no background in dis here stuff. However, by playing with the 4 in its "correct" position I've figured out that the 4 equals the number of windows to Cascade. So close but no cigar. I then changed the 4 to $avHWND[0][0] and it worked like a dream!!! Here's what I finally landed on AND its not compiled ;)

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]")
MsgBox(0,"ready", "set... go")
$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", "int", 0, "int", 0, "int", 0, "int", $avHWND[0][0], "int", $pKids)

Thanks again guys, I knew we could figure this one out! Now to put this new found knowledge to use in the actual script ;).

Edit: I answered my own question if the DllStruct...() stuff is necessary. Without it we're back to square one where all unminimized windows will be affected. Only remaining question is... does it make sense to improve WinMinimizeAll() and WinMinimizeAllUndo() to control groups of windows with the same title/whnd?

Edited by ssubirias3

Share this post


Link to post
Share on other sites

#19 ·  Posted (edited)

Hey all the other code here is using WinList() and thusly is being looped through. But you're right, due to the slowness of WinSetState my script comes in about 2 seconds slower.

Edited by weaponx

Share this post


Link to post
Share on other sites

... how should have a noob known to move it out??

The link I gave in post #2 should have told you, but perhaps it isn't obvious.

This is how the function is defined

WORD CascadeWindows(

HWND hwndParent,

UINT wHow,

const RECT *lpRect,

UINT cKids,

const HWND *lpKids

);

There are 5 parameters. In the dllcall you also have to send 5 parameters and in the same order., but in DllCall you have to tell the dllcall what sort of variable each parameter is. So instead of having a parameter hwndParent, you have "int",hwndParent. In this case 0 to indicate the desktop. So 5 parameters for the real dll means 10 parameters, or 5 pairs for dllcall. The same applies to the function itself, so before the function name you have to have the type of variable the function returns.

The msn documentation explains that cKids

Specifies the number of elements in the array specified by the lpKids parameter. This parameter is ignored if lpKids is NULL.

So by reading that I knew that the 4, which I thought was because you wanted to cascade 4 windows, was in the wrong place.

Only a few weeks ago, well maybe months, I knew less than you do about all this, and it only takes a bit of knowledge to make it all much easier. Of course in another few months I might have forgotten it all.


Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
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
Sign in to follow this  
Followers 0