Sign in to follow this  
Followers 0
wraithdu

DllCall to SHGetKnownFolderPath

10 posts in this topic

I'm trying to use DllCall for the SHGetKnownFolderPath (Vista only) function. I can't seem to get it to work. Here's the MSDN info -

HRESULT SHGetKnownFolderPath(     
    REFKNOWNFOLDERID rfid,
    DWORD dwFlags,
    HANDLE hToken,
    PWSTR *ppszPath
);

I'm wondering if AutoIt doesn't have the right data type for 'rfid'. It's supposed to be the GUID reference for the folder location. I don't know how to pass this value. So here's what I got so far -

Func _WinAPI_GetKnownFolderPath($nFolder, $dwFlags)
    $folder = DllCall("shell32.dll", "int", "SHGetKnownFolderPath", _
                                            "str", $nFolder, _
                                            "dword", $dwFlags, _
                                            "ptr", "", _
                                            "wstr", "" _
                                            )
    Return $folder[4]
EndFunc

Can anyone help? I've successfully got SHGetFolderPath working, but I want both versions.

Share this post


Link to post
Share on other sites



From MSDN:

rfid

[in] A reference to the KNOWNFOLDERID that identifies the folder.

Since it's a reference, try "..."str*", $nFolder, ..."

Can't test, because I am blissfully Vista free...

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Sorry, but that didn't work :)

Problem still is, I don't know what data type REFKNOWNFOLDERID is, or what the data is supposed to be exactly. Is it the GUID string, GUID binary data, with or without {}...where do I get that data or how do I convert it? Silly MSDN isn't much help...

Edited by wraithdu

Share this post


Link to post
Share on other sites

Sorry, but that didn't work :)

Problem still is, I don't know what data type REFKNOWNFOLDERID is, or what the data is supposed to be exactly. Is it the GUID string, GUID binary data, with or without {}...where do I get that data or how do I convert it? Silly MSDN isn't much help...

Try it as "int" and try 0 as the param first...

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

Sorry, but that didn't work ;)

Problem still is, I don't know what data type REFKNOWNFOLDERID is, or what the data is supposed to be exactly. Is it the GUID string, GUID binary data, with or without {}...where do I get that data or how do I convert it? Silly MSDN isn't much help...

You can get a list of them and see. According to MSDN, you can use the IKnownFolderManager::GetFolderIds method to get a list.

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

Thanks, but I don't need a list of the FOLDERIDs, I have the list of GUIDs already. I don't know what data TYPE I'm supposed to pass to the function. I think it's supposed to be a GUID type, but AutoIt doesn't seem to support it.

BTW, NSIS's System plugin does support the GUID data type, but I can't get this darn function to work in NSIS either.

@SmOke_N

The function crashes if the input data type is an int, ptr, or dword. str and wstr don't crash, but it doesn't work either. The return value is some crazy number. It should be 0 if it's successful.

Edited by wraithdu

Share this post


Link to post
Share on other sites

Thanks, but I don't need a list of the FOLDERIDs, I have the list of GUIDs already. I don't know what data TYPE I'm supposed to pass to the function. I think it's supposed to be a GUID type, but AutoIt doesn't seem to support it.

BTW, NSIS's System plugin does support the GUID data type, but I can't get this darn function to work in NSIS either.

@SmOke_N

The function crashes if the input data type is an int, ptr, or dword. str and wstr don't crash, but it doesn't work either. The return value is some crazy number. It should be 0 if it's successful.

Hmm... well, this generates a GUID, and the GUID it generates is a string:

$TypeLib = ObjCreate("Scriptlet.TypeLib")
$GUID = $TypeLib.Guid
ConsoleWrite("Debug: $GUID = " & $GUID & "  Type = " & VarGetType($GUID) & @LF)oÝ÷ ØƲmëaz"׫Ûø¬¶Þ¥«,yÖ®¶­sbb33cµ7G'V7DuTBÒFÆÅ7G'V7D7&VFRgV÷C¶6"uTE³3ÒgV÷C²¢b33cµGTÆ"Òö&¤7&VFRgV÷Cµ67&FÆWBåGTÆ"gV÷C²¢b33c´uTBÒb33cµGTÆ"äwV@¤6öç6öÆUw&FRgV÷C´FV'Vs¢b33c´uTBÒgV÷C²fײb33c´uTBfײgV÷C²GRÒgV÷C²fײf$vWEGRb33c´uTBfײgV÷C²ÆVâÒgV÷C²fײ7G&ætÆVâb33c´uTBfײÄb¤FÆÅ7G'V7E6WDFFb33cµ7G'V7DuTBÂgV÷C´uTBgV÷C²Âb33c´uTB¢b33c·G$uTBÒFÆÅ7G'V7DvWEG"b33cµ7G'V7DuTBÂgV÷C´uTBgV÷C² ¢b33c¶föÆFW"ÒFÆÄ6ÆÂgV÷C·6VÆÃ3"æFÆÂgV÷C²ÂgV÷C¶çBgV÷C²ÂgV÷Cµ4vWD¶æ÷väföÆFW%FgV÷C²Âð gV÷C·G"gV÷C²Âb33c·G$uTBÂð gV÷C¶Gv÷&BgV÷C²ÂÂð gV÷C·G"gV÷C²ÂgV÷C²gV÷C²Âð gV÷C·w7G"gV÷C²ÂgV÷C²gV÷C²

I'm guessing a lot now though, so feel free to ignore it...

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

Nice bit of code! I'll probably have to remember some of that in the future.

But alas, no luck. As I said above, passing a ptr to the function in param 1 crashes it, return code -1073741819.

It only accepts the str and wstr data types as far as I can tell.

Share this post


Link to post
Share on other sites

Ok, I'm 90% of the way there! I finally figured out how to pass the correct GUID structure (thanks to kichik and others at NSIS for the hints). Here's the working code I have so far -

#include <WinAPI.au3>

$tagstruct = DllStructCreate($tagGUID)
$tagptr = DllStructGetPtr($tagstruct)
_WinAPI_GUIDFromStringEx("{8983036C-27C0-404B-8F08-102D10DCFD74}", $tagptr)

$folder = DllCall("shell32.dll", "int", "SHGetKnownFolderPath", _
                        "ptr", $tagptr, _
                        "dword", 0x1000, _
                        "int", "", _
                        "ptr*", "" _
                        )
                        
ConsoleWrite("returncode = " & $folder[0] & @CRLF & "outaddr = " & $folder[4] & @CRLF)

DllCall("ole32.dll", "none", "CoTaskMemFree", _
                        "ptr", $folder[4] _
                        )

So the output here is the address to the pointer that contains the unicode path. How can I read this data? I can't use DllStructGetData cause I don't have a struct to read. I tried creating one ahead of time, but the function won't write to it. It would just write the pointer address anyway.

So how do I read memory where I just have the pointer address?

Share this post


Link to post
Share on other sites

Finally!!!

#include <WinAPI.au3>

$tagstruct = DllStructCreate($tagGUID)
$tagptr = DllStructGetPtr($tagstruct)
_WinAPI_GUIDFromStringEx("{8983036C-27C0-404B-8F08-102D10DCFD74}", $tagptr)

$folder = DllCall("shell32.dll", "int", "SHGetKnownFolderPath", _
                        "ptr", $tagptr, _
                        "dword", 0x1000, _
                        "int", "", _
                        "ptr*", "" _
                        )
                        
$len = DllCall("kernel32.dll", "int", "lstrlenW", _
                                "ptr", $folder[4] _
                                )

$pathstruct = DllStructCreate("wchar[" & $len[0] & "]")
$pathptr = DllStructGetPtr($pathstruct)

$path = DllCall("kernel32.dll", "int", "lstrcpyW", _
                                "ptr", $pathptr, _
                                "ptr", $folder[4] _
                                )

ConsoleWrite("returncode = " & $folder[0] & @CRLF & "outaddr = " & $folder[4] & @CRLF)
ConsoleWrite("path len = " & $len[0] & @CRLF & "path = " & DllStructGetData($pathstruct, 1) & @CRLF)

DllCall("ole32.dll", "none", "CoTaskMemFree", _
                        "ptr", $folder[4] _
                        )

Now, is there an easier way to do this? LOL

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