delphi - 在 Delphi XE 中将 UnicodeString 转换为 PAnsiChar

标签 delphi pointers delphi-xe unicode-string ansistring

在 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 的正确方法是什么?

最佳答案

我很惊讶

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 字符串。

更新 2

如果我在 中的假设更新 1 是正确的,声明
function BASS_StreamCreateURL(url: PWideChar; offset: DWORD; flags: DWORD; 
    proc: DOWNLOADPROC; user: Pointer):HSTREAM; stdcall; external bassdll;

会让天空再次变蓝。

更新 3

从文档中:

NOTE: Delphi 2009 users should use the BASS_UNICODE flag where possible



我敢打赌,如果您在调用 BASS_StreamCreateURL 时指定此标志,问题就会消失。 !

来自样本单位Main.pas :
Channel := BASS_StreamCreateFile(FALSE, PChar(OpenDialog.FileName), 0, 0,
    0 {$IFDEF UNICODE} or BASS_UNICODE {$ENDIF});

关于delphi - 在 Delphi XE 中将 UnicodeString 转换为 PAnsiChar,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4543098/

相关文章:

delphi - 如何在Delphi中处理项目特定组件?

delphi - 如何将所有者分配给克隆的 TMenuItem?

delphi - 如何销毁运行时定义的 TClientDataSet TFields?

delphi - 文件格式转换为 TIFF。有些问题?

c - 使用 out params 查找 float 组中的最小和最大元素

delphi - TLabel 和 TGroupbox 标题在调整大小时闪烁

c++ - 如何在 InitializeObjectAttributes() 中使用 SECURITY_DESCRIPTOR

c - 在 C 中取消引用字符指针

c - 打印已从堆中释放的变量地址的正确方法是什么?

delphi - 将旧的 Delphi 7 代码迁移到 Delphi XE - 未找到 QForms.dcu