2

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

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 的可疑类型转换”。在尝试消除警告时,我发现推荐的方法是使用双重转换:

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

4

2 回答 2

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)

即以空字符 ( ) 结尾的字符串“test” 00

更新

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

PAnsiChar(url)

作品。库可能会说“嘿,给我指向 unicode 字符串的指针,我会用它做一些手动处理”,上面的代码就是这样做的(指针只是一个指针(即,一个无符号的 32 位整数)...)。但是编译器当然会抱怨,因为库明确告诉编译器它需要 a 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

从文档中:

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

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

从样本单位Main.pas

Channel := BASS_StreamCreateFile(FALSE, PChar(OpenDialog.FileName), 0, 0,
    0 {$IFDEF UNICODE} or BASS_UNICODE {$ENDIF});
于 2010-12-28T01:43:32.180 回答
1

以下代码片段在我的经验中非常有用。 {$IFDEF UNICODE}或者BASS_UNICODE {$ENDIF}

于 2011-10-10T14:02:55.717 回答