在Delphi XE中将UnicodeString转换为PAnsiChar

Mar*_*ski 2 delphi pointers unicode-string ansistring delphi-xe

在Delphi XE中,我使用的是BASS音频库,它包含以下功能:

function BASS_StreamCreateURL(url: PAnsiChar; offset: DWORD; flags: DWORD; 
    proc: DOWNLOADPROC; user: Pointer):HSTREAM; stdcall; external bassdll;
Run Code Online (Sandbox Code Playgroud)

'url'参数的类型为PAnsiChar,所以在我的代码中我做了一个强制转换:

FStreamHandle := BASS_StreamCreateURL(PAnsiChar( url ) [...]
Run Code Online (Sandbox Code Playgroud)

编译器在此行上发出警告:"对PAnsiChar的字符串的可疑类型转换".在试图消除警告时,我发现推荐的方法是使用双重投射:

FStreamHandle := BASS_StreamCreateURL(PAnsiChar( AnsiString( url )) [...]
Run Code Online (Sandbox Code Playgroud)

这确实消除了警告,但是BASS函数现在返回错误代码2("无法打开文件"),这告诉我它收到的URL字符串以某种方式被破坏.我无法看到低音DLL实际接收到的内容,但在调试器中使用断点时字符串看起来很好:

var
  s : PAnsiChar;
begin
  s := PAnsiChar( AnsiString( url ));
Run Code Online (Sandbox Code Playgroud)

此时字符串s显示正常,但是当我通过它时BASS功能失败.我的初始代码:PAnsiChar(url)与BASS配合良好,但会发出警告.

那么在没有警告的情况下从UnicodeString到PAnsiChar的正确方法是什么?

And*_*and 15

我很惊讶

BASS_StreamCreateURL(PAnsiChar( url ) [...]
Run Code Online (Sandbox Code Playgroud)

作品.如果url是unicode字符串,则每个字符将占用两个字节.例如,如果字符串是test,则它将读取

7400 6500 7300 7400 0000                t e s t #0                     (Unicode)
Run Code Online (Sandbox Code Playgroud)

在记忆中.请注意,字符串以空字符结束(0000)

PAnsiChar(url)
Run Code Online (Sandbox Code Playgroud)

你会告诉编译器这个地址的内存应该被认为是一个AnsiString.但是如果考虑上面的字节序列,在这种情况下你只会发现"t".实际上,作为一个AnsiString,序列应该被解释为

74 00 65 00 73 00 74 00 00 00           t #0 e #0 s #0 t #0 #0 #0      (Ansi)
Run Code Online (Sandbox Code Playgroud)

这是字符串"t",以空字符(00)结尾.

PAnsiChar(AnsiString(url))
Run Code Online (Sandbox Code Playgroud)

另一方面,首先会将unicode字符串转换为ansi字符串,也就是说,您将获得

74 65 73 74 00                           t e s t #0                    (Ansi)
Run Code Online (Sandbox Code Playgroud)

这是以空字符(00)结尾的字符串"test" .

更新

我不是通灵的,但也许Bass库实际上确实需要指向a的指针UnicodeString作为这个函数的第一个参数?这可以解释为什么看似奇怪

PAnsiChar(url)
Run Code Online (Sandbox Code Playgroud)

作品.库可能会说"嘿,只要给我指向unicode字符串的指针,我就用它做一些手动处理",上面的代码就是这样(指针只是一个指针(也就是说,一个无符号的32位)整数)...).但编译器会抱怨,当然,因为库明确告诉编译器它需要一个PAnsiChar,而且通常PAnsiChar(SomeUnicodeString)是坏的.如果是这种情况,那么,当然,

PAnsiChar(AnsiChar(url))
Run Code Online (Sandbox Code Playgroud)

不起作用.库需要/一个unicode字符串的地址,但是得到/一个ansi字符串的地址.

更新2

如果我在Update 1中的假设是正确的,那么声明

function BASS_StreamCreateURL(url: PWideChar; offset: DWORD; flags: DWORD; 
    proc: DOWNLOADPROC; user: Pointer):HSTREAM; stdcall; external bassdll;
Run Code Online (Sandbox Code Playgroud)

会让天空变成蓝色.

更新3

从文档:

注意:Delphi 2009用户应尽可能使用BASS_UNICODE标志

我敢打赌,如果你在打电话时指定这个标志,问题就会消失BASS_StreamCreateURL!

来自样本单位Main.pas:

Channel := BASS_StreamCreateFile(FALSE, PChar(OpenDialog.FileName), 0, 0,
    0 {$IFDEF UNICODE} or BASS_UNICODE {$ENDIF});
Run Code Online (Sandbox Code Playgroud)

  • 重新更新3:我的代码中确实存在BASS_UNICODE标志.你可能在你早先的预感中正确.由于标志*是*指定的,BASS期望PWideChar,即使声明另有说明.非常感谢,安德烈亚斯! (2认同)