winapinameA vs winapinameW - Unicode vs Ansi - Delphi XE2

时间:2012-10-31 22:09:22

标签: delphi winapi unicode delphi-xe2 ansi

我正在使用Delphi XE2并从Shell32.dll导入SHGetFolderPath。我正在运行Windows Vista x64。运行SHGetFolderPathA时结果不清楚。

即:

uses
  Windows;

function SHGetFolderPath(hwnd: Cardinal; csidl: Integer; hToken: Cardinal; dwFlags: Cardinal; pszPath: PChar): Cardinal; stdcall;external 'Shell32.dll' name 'SHGetFolderPathA';

Var
  Path:Array [0..MAX_PATH] of Char;
  AppData:String;

begin
  SHGetFolderPath(0,$001A,0,0,@path[0]);
  MessageBox(0,Path,'a',0);
end.

结果是:

enter image description here

使用SHGetFolderPathW:

用途       视窗;

function SHGetFolderPath(hwnd: Cardinal; csidl: Integer; hToken: Cardinal; dwFlags: Cardinal; pszPath: PChar): Cardinal; stdcall;external 'Shell32.dll' name 'SHGetFolderPathW';

Var
  Path:Array [0..MAX_PATH] of Char;
  AppData:String;

begin
  SHGetFolderPath(0,$001A,0,0,@path[0]);
  MessageBox(0,Path,'a',0);
end.

结果清楚地说明了我的AppData文件夹的路径没有问题。

使用SHGetFolderPathA在x32 Vista上运行相同的代码时效果很好。

如果有人可以阐明为什么会这样?我的印象是“W”api通常用于Unicode机器......?


编辑:

我现在使用以下代码,但错误相同:

uses
  Windows;

function SHGetFolderPath(hwnd: HWND; csidl: Integer; hToken: THandle; dwFlags: DWord; pszPath: PAnsiChar): HRESULT; stdcall; external 'SHFolder.dll' name 'SHGetFolderPathA';

var
  path: array[0..MAX_PATH] of char;
begin
  SHGetFolderPath(0,$001A,0,0, @path[0]);
  MessageBox(0,path,'a',0);
end.

最终编辑:

谢谢大家的回复。上面的SHGetFolderPath声明很好。在查看了所有回复并收集每个回复中的信息之后,我得出了以下结果:

uses
  Windows;

function SHGetFolderPath(hwnd: HWND; csidl: Integer; hToken: THandle; dwFlags: DWord; pszPath: PAnsiChar): HRESULT; stdcall; external 'shell32.dll' name 'SHGetFolderPathA';

var
  path: array[0..MAX_PATH] of ansichar;
  xRes:String;
begin
  If SHGetFolderPath(0,$001A,0,0, @path[0]) = S_OK Then Begin
    xRes := Path;
    MessageBox(0,PWideChar(xRes),'Result',0);
  End Else
    MessageBox(0,'An error has occurred.','Result',0);
end.

生成的消息框正确显示我的AppData路径的路径。

再次感谢所有回复。

3 个答案:

答案 0 :(得分:4)

您将SHGetFolderPath的最终参数声明为类型PChar。在Delphi 2009及更高版本(包括您的版本,Delphi XE2)中,PCharPWideChar的别名,但您告诉Delphi将您声明的函数链接到“A”版本,该版本期望{{ 1}}字符。

当声明对字符类型敏感的函数时,我建议根本不使用AnsiChar。明确使用PCharPWideChar

“A”和“W”后缀与运行程序的 machine 无关。 所有支持的Windows版本现在都是Unicode - 最后一个非Unicode版本是Windows ME。 “A”和“W”指的是参数的字符类型。

至于为什么你的代码在64位版本失败时在32位版本的Vista上工作,我没有解释。也许你很幸运,操作系统做了一些转换,碰巧在你的情况下运行正常。

答案 1 :(得分:1)

Char在XE2中是Unicode,但您正在导入SHGetFolderPath()的Ansi版本并将Unicode输出缓冲区传递给它。这就是你的MessageBox()显示垃圾的原因 - 它试图在Unicode对话框中显示Ansi数据。您需要导入SHGetFolderPath()的Unicode版本:

uses
  Windows;

function SHGetFolderPath(hwnd: HWND; csidl: Integer; hToken: THandle; dwFlags: DWord; pszPath: PWideChar): HRESULT; stdcall; external 'SHFolder.dll' name 'SHGetFolderPathW';

var
  path: array[0..MAX_PATH] of Char;
begin
  SHGetFolderPath(0, $001A, 0, 0, path);
  MessageBox(0, path,'a', 0);
end.

BTW,XE2已经为您导入了SHGetFolderPath()的Ansi和Unicode版本,并且定义了CSIDL值,因此您不需要手动执行:

uses
  Windows, ShlObj, SHFolder;

var
  path: array[0..MAX_PATH] of Char;
begin
  SHGetFolderPath(0, CSIDL_APPDATA, 0, 0, path);
  MessageBox(0, path, 'a', 0);
end.

答案 2 :(得分:0)

在你的代码中我看到两个错误一个错误:

- “Path”被声明为局部变量(即在堆栈上),因此它包含“随机”/陈旧数据。建议用零初始化它:fillChar(path [0],sizeOf(path),#0)

  • SHGetFolderPath是一个函数。它返回一个值。你永远不会测试函数的结果,看看它是否已被删除 - 你只需输出“path”变量的内容。但是如果SHGetFolderPath由于某种原因失败了,内容是否有意义?