在Delphi XE中,我使用的是包含此功能的BASS audio library:
function BASS_StreamCreateURL(url: PAnsiChar; offset: DWORD; flags: DWORD;
proc: DOWNLOADPROC; user: Pointer):HSTREAM; stdcall; external bassdll;
'url'参数的类型为PAnsiChar,所以在我的代码中我做了一个演员:
FStreamHandle := BASS_StreamCreateURL(PAnsiChar( url ) [...]
编译器在此行上发出警告:“对PAnsiChar的字符串的可疑类型转换”。在尝试消除警告时,我found that推荐的方法是使用双重投射:
FStreamHandle := BASS_StreamCreateURL(PAnsiChar( AnsiString( url )) [...]
这确实消除了警告,但是BASS函数现在返回错误代码2(“无法打开文件”),这告诉我它收到的URL字符串以某种方式被破坏。我无法看到低音DLL实际接收到的内容,但在调试器中使用断点时字符串看起来很好:
var
s : PAnsiChar;
begin
s := PAnsiChar( AnsiString( url ));
此时字符串s显示正常,但是当我通过它时BASS功能失败。我的初始代码:PAnsiChar(url)适用于BASS,但会发出警告。
那么在没有警告的情况下从UnicodeString到PAnsiChar的正确方法是什么?
答案 0 :(得分:15)
我很惊讶
BASS_StreamCreateURL(PAnsiChar( url ) [...]
的工作原理。如果url
是unicode字符串,则每个字符将占用两个字节。例如,如果字符串是test
,则会读取
7400 6500 7300 7400 0000 t e s t #0 (Unicode)
在记忆中。请注意,字符串以空字符结尾(0000
)当您执行
PAnsiChar(url)
你会告诉编译器这个地址的内存应该被认为是AnsiString
。但是如果考虑上面的字节序列,在这种情况下你只会发现“t”。实际上,作为AnsiString
,序列应该被解释为
74 00 65 00 73 00 74 00 00 00 t #0 e #0 s #0 t #0 #0 #0 (Ansi)
这是字符串“t”,以空字符(00
)结尾。
PAnsiChar(AnsiString(url))
另一方面,会首先将unicode字符串转换为ansi字符串,也就是说,你将获得
74 65 73 74 00 t e s t #0 (Ansi)
这是以空字符(00
)结尾的字符串“test”。
我不是通灵者(但是),但也许Bass库实际上确实需要指向UnicodeString
的指针作为此函数的第一个参数?这可以解释为什么看似奇怪的
PAnsiChar(url)
的工作原理。库可能会说“嘿,只要给我指向unicode字符串的指针,我就用它做一些手动处理”,上面的代码就是这样(指针只是一个指针(也就是说,一个无符号的32位)整数)...)。但是编译器会抱怨,当然,因为库明确告诉编译器它需要PAnsiChar
,而且通常PAnsiChar(SomeUnicodeString)
是坏的。如果是这种情况,那么,
PAnsiChar(AnsiChar(url))
不起作用。库需要/一个unicode字符串的地址,但是得到/一个ansi字符串的地址。
如果我在 Update 1 中的假设是正确的,则声明
function BASS_StreamCreateURL(url: PWideChar; offset: DWORD; flags: DWORD;
proc: DOWNLOADPROC; user: Pointer):HSTREAM; stdcall; external bassdll;
会再次使天空变蓝。
来自文档:
注意:Delphi 2009用户应尽可能使用BASS_UNICODE标志
我敢打赌,如果您在拨打BASS_StreamCreateURL
时指定此标志,问题就会消失!
来自样本单元Main.pas
:
Channel := BASS_StreamCreateFile(FALSE, PChar(OpenDialog.FileName), 0, 0,
0 {$IFDEF UNICODE} or BASS_UNICODE {$ENDIF});
答案 1 :(得分:1)
以下代码段在我的经验中非常有用。
{$IFDEF UNICODE}
或BASS_UNICODE {$ENDIF}