Discussion:
Q: Cannot control vista api "SHGetKnownFolderPath" using shell32.dll in Delphi 7 on Windows XP.
(too old to reply)
news2.homelinux.org
2007-02-21 05:05:19 UTC
Permalink
Q: Cannot control vista api "SHGetKnownFolderPath" using shell32.dll
in Delphi 7 on Windows XP.

OS: Windows XP
Target: Windows Vista
RAD: Delphi 7 (on Windows XP)


Below code which vista api in shell32.dll as dynamic-loading has
access violation error.
I wanna get user's (shared) folder full path so,
i've coded using vista api "SHGetKnownFolderPath" as a function
pointer by dynamic-load "shell32.dll".
Okay, i think function pointer works good, but i don't know exactly
why write to my array variable(call-by-reference)
at "SHGetKnownFolderPath" in "shell32.dll".


Let me know what is problem. Any help is truly appreciated.
thanks.


Best Regards,
godmode2k


// CODE
//
-------------------------------------------------------------------------------
...


type
TSHGetKnownFolderPath = function(FOLDERID_LocalAppDataLow: TGUID;
dwFlags: DWord; hToken: THandle; ppSzPath: pAnsiChar ) : HResult;
StdCall;


const
PRODUCT_BUSINESS = $00000006;
PRODUCT_HOME_BASIC = $00000002;
PRODUCT_HOME_PREMIUM = $00000003;
PRODUCT_STARTER = $0000000B;
PRODUCT_UNDEFINED = $00000000;
PRODUCT_ULTIMATE = $00000001;
PRODUCT_UNLICENSED = $ABCDABCD;
FOLDERID_LocalAppDataLow : TGUID =
(D1:$A520A1A4; D2:$1780; D3:$4FF6; D4:($BD,$18,$16,$73,$43,$C5,$AF,
$16));


var
...


m_SHGetKnownFolderPath: TSHGetKnownFolderPath;
m_pDllData: Pointer;
m_DllDataSize: Integer;
m_pMemoryModule: PBTMemoryModule;
m_hDll: Cardinal;


...


function BT_SHGetKnownFolderPath_File : BOOL;
begin
m_hDll := LoadLibrary( 'shell32.dll' );
...
@m_SHGetKnownFolderPath := GetProcAddress( m_hDll,
'SHGetKnownFolderPath' );
...
end;


function Vista_GetEnvironment : String;
var
// szPath: pAnsiChar;
szPath: array[0..MAX_PATH] of Char;
ret: HResult;
begin
BT_SHGetKnownFolderPath_File;


//
// Occurs error below line
// Message: Access Violation at address 75F15324 in module
'shell32.dll'. Write of address 16AFC543.
//
ret := m_SHGetKnownFolderPath( FOLDERID_LocalAppDataLow, 0, 0,
szPath );
...
if( m_hDll <> 0 ) then
begin
FreeLibrary( m_hDll );
end;
end;
//
-------------------------------------------------------------------------------


EOF
Rob Kennedy
2007-02-21 06:42:21 UTC
Permalink
Post by news2.homelinux.org
Below code which vista api in shell32.dll as dynamic-loading has
access violation error.
I wanna get user's (shared) folder full path so,
i've coded using vista api "SHGetKnownFolderPath" as a function
pointer by dynamic-load "shell32.dll".
Okay, i think function pointer works good, but i don't know exactly
why write to my array variable(call-by-reference)
at "SHGetKnownFolderPath" in "shell32.dll".
Are you sure you can't just use ShGetFolderPath instead? It's available
on all OS versions, so you won't need special code for Windows Vista.
Post by news2.homelinux.org
type
TSHGetKnownFolderPath = function(FOLDERID_LocalAppDataLow: TGUID;
dwFlags: DWord; hToken: THandle; ppSzPath: pAnsiChar ) : HResult;
StdCall;
The declaration in MSDN has the final parameter as a PWSTR*. That's a
pointer to a pointer to a wide character. In Delphi, that would be a
PPWideChar, or an "out PWideChar." And why that name for the first
parameter?

type
TShGetKnownFolderPath = function(const rfid: TGUID; dwFlags: DWord;
hToken: THandle; out ppszPath: PWideChar): HResult; stdcall;

The last parameter is passed by reference because the function allocates
the memory for you. That's why it tells you to free the memory with
CoTaskMemFree. Misdeclaring that last parameter is probably what's
causing the access violation.
Post by news2.homelinux.org
var
...
m_SHGetKnownFolderPath: TSHGetKnownFolderPath;
m_pDllData: Pointer;
m_DllDataSize: Integer;
m_pMemoryModule: PBTMemoryModule;
m_hDll: Cardinal;
By C++ convention, the "m_" prefix denotes a member variable, a field of
a class. It's just confusing to other readers when they're actually
global variables. Delphi convention uses a prefix of "F" for fields. A
prefix for global variables isn't as widespread, but I see "G" and "g_"
sometimes.
Post by news2.homelinux.org
function BT_SHGetKnownFolderPath_File : BOOL;
begin
m_hDll := LoadLibrary( 'shell32.dll' );
...
@m_SHGetKnownFolderPath := GetProcAddress( m_hDll,
'SHGetKnownFolderPath' );
...
end;
function Vista_GetEnvironment : String;
var
// szPath: pAnsiChar;
szPath: array[0..MAX_PATH] of Char;
ret: HResult;
begin
BT_SHGetKnownFolderPath_File;
You're ignoring the return value.
Post by news2.homelinux.org
//
// Occurs error below line
// Message: Access Violation at address 75F15324 in module
'shell32.dll'. Write of address 16AFC543.
//
ret := m_SHGetKnownFolderPath( FOLDERID_LocalAppDataLow, 0, 0,
szPath );
...
if( m_hDll <> 0 ) then
begin
FreeLibrary( m_hDll );
end;
Make sure to set m_hDll back to zero again.
Post by news2.homelinux.org
end;
Usually, if a function is being loaded dynamically for every call, the
load and the call occur in the same function. It would look like this:

function ShGetKnownFolderPath(const rfid: TGUID; dwFlags: DWord; hToken:
THandle; out ppszPath: PWideChar): HResult;
var
Shell: HModule;
Fn: TShGetKnownFolderPath;
begin
Shell := LoadLibrary('shell32.dll');
Win32Check(Shell <> 0);
try
@Fn := GetProcAddress(Shell, 'SHGetKnownFolderPath');
Win32Check(Assigned(Fn));
Result := Fn(rfid, dwFlags, hToken, ppszPath);
finally
FreeLibrary(Shell);
end;
end;

Now the rest of your program can simply call ShGetKnownFolderPath, just
as though it were a normal API function. All the loading and linking
takes place local to that function instead of cluttering the environment
with global variables and support functions that need to be called in
just the right order.

You can wrap the API function in a Delphi function like the following.
It will raise an exception if the API function fails. Otherwise, it will
return a WideString with the path you ask for. This saves you from
having to call CoTaskMemFree later.

function GetKnownFolderPath(const rfid: TGUID; dwFlags: DWord; hToken:
THandle): WideString;
var
buffer: PWideChar;
ret: HResult;
begin
ret := ShGetKnownFolderPath(rfid, dwFlags, hToken, buffer);
OleCheck(ret);
try
Result := buffer;
finally
CoTaskMemFree(buffer);
end;
end;
--
Rob
g***@gmail.com
2007-02-22 06:21:05 UTC
Permalink
Post by Rob Kennedy
Post by news2.homelinux.org
Below code which vista api in shell32.dll as dynamic-loading has
access violation error.
I wanna get user's (shared) folder full path so,
i've coded using vista api "SHGetKnownFolderPath" as a function
pointer by dynamic-load "shell32.dll".
Okay, i think function pointer works good, but i don't know exactly
why write to my array variable(call-by-reference)
at "SHGetKnownFolderPath" in "shell32.dll".
Are you sure you can't just use ShGetFolderPath instead? It's available
on all OS versions, so you won't need special code for Windows Vista.
Post by news2.homelinux.org
type
TSHGetKnownFolderPath = function(FOLDERID_LocalAppDataLow: TGUID;
dwFlags: DWord; hToken: THandle; ppSzPath: pAnsiChar ) : HResult;
StdCall;
The declaration in MSDN has the final parameter as a PWSTR*. That's a
pointer to a pointer to a wide character. InDelphi, that would be a
PPWideChar, or an "out PWideChar." And why that name for the first
parameter?
type
TShGetKnownFolderPath = function(const rfid: TGUID; dwFlags: DWord;
hToken: THandle; out ppszPath: PWideChar): HResult; stdcall;
The last parameter is passed by reference because the function allocates
the memory for you. That's why it tells you to free the memory with
CoTaskMemFree. Misdeclaring that last parameter is probably what's
causing the access violation.
Post by news2.homelinux.org
var
...
m_SHGetKnownFolderPath: TSHGetKnownFolderPath;
m_pDllData: Pointer;
m_DllDataSize: Integer;
m_pMemoryModule: PBTMemoryModule;
m_hDll: Cardinal;
By C++ convention, the "m_" prefix denotes a member variable, a field of
a class. It's just confusing to other readers when they're actually
global variables.Delphiconvention uses a prefix of "F" for fields. A
prefix for global variables isn't as widespread, but I see "G" and "g_"
sometimes.
Post by news2.homelinux.org
function BT_SHGetKnownFolderPath_File : BOOL;
begin
m_hDll := LoadLibrary( 'shell32.dll' );
...
@m_SHGetKnownFolderPath := GetProcAddress( m_hDll,
'SHGetKnownFolderPath' );
...
end;
function Vista_GetEnvironment : String;
var
// szPath: pAnsiChar;
szPath: array[0..MAX_PATH] of Char;
ret: HResult;
begin
BT_SHGetKnownFolderPath_File;
You're ignoring the return value.
Post by news2.homelinux.org
//
// Occurs error below line
// Message: Access Violation at address 75F15324 in module
'shell32.dll'. Write of address 16AFC543.
//
ret := m_SHGetKnownFolderPath( FOLDERID_LocalAppDataLow, 0, 0,
szPath );
...
if( m_hDll <> 0 ) then
begin
FreeLibrary( m_hDll );
end;
Make sure to set m_hDll back to zero again.
Post by news2.homelinux.org
end;
Usually, if a function is being loaded dynamically for every call, the
THandle; out ppszPath: PWideChar): HResult;
var
Shell: HModule;
Fn: TShGetKnownFolderPath;
begin
Shell := LoadLibrary('shell32.dll');
Win32Check(Shell <> 0);
try
@Fn := GetProcAddress(Shell, 'SHGetKnownFolderPath');
Win32Check(Assigned(Fn));
Result := Fn(rfid, dwFlags, hToken, ppszPath);
finally
FreeLibrary(Shell);
end;
end;
Now the rest of your program can simply callShGetKnownFolderPath, just
as though it were a normal API function. All the loading and linking
takes place local to that function instead of cluttering the environment
with global variables and support functions that need to be called in
just the right order.
You can wrap the API function in aDelphifunction like the following.
It will raise an exception if the API function fails. Otherwise, it will
return a WideString with the path you ask for. This saves you from
having to call CoTaskMemFree later.
THandle): WideString;
var
buffer: PWideChar;
ret: HResult;
begin
ret :=ShGetKnownFolderPath(rfid, dwFlags, hToken, buffer);
OleCheck(ret);
try
Result := buffer;
finally
CoTaskMemFree(buffer);
end;
end;
--
Rob
I do truly appreciate you.
I've solve it today from your advice.
I'll always be memorize your advice that what is problem(correct my
fault) exactly.

and, i've know "Out parameter" newly today.

thanks again.

Best Regards,
godmode2k

Jamie
2007-02-22 02:36:41 UTC
Permalink
Post by news2.homelinux.org
Q: Cannot control vista api "SHGetKnownFolderPath" using shell32.dll
in Delphi 7 on Windows XP.
OS: Windows XP
Target: Windows Vista
RAD: Delphi 7 (on Windows XP)
Below code which vista api in shell32.dll as dynamic-loading has
access violation error.
I wanna get user's (shared) folder full path so,
i've coded using vista api "SHGetKnownFolderPath" as a function
pointer by dynamic-load "shell32.dll".
Okay, i think function pointer works good, but i don't know exactly
why write to my array variable(call-by-reference)
at "SHGetKnownFolderPath" in "shell32.dll".
Let me know what is problem. Any help is truly appreciated.
thanks.
Best Regards,
godmode2k
I don't have Vista yet and most likely never will the way things
are looking here how ever.
I could be wrong but i'll wing it here.

If that is a Vista API call, then i can't see how it would be
available to you any ways.
It's most likely a 64 Bit call and Delphi only creates 32 bit apps.
UNless you're doing this in .NET? which i think the same will apply.

Maybe what you're looking for is the use of
SHGetSpecialFolderLocation API call ?

Maybe i am all wrong on this. Just my thoughts on it.
Loading...