2010-12-28 5 views
2

В Delphi XE я использую BASS audio library, который содержит эту функцию:Преобразование UnicodeString в PAnsiChar в Delphi XE

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

Я только что использовал AnsiString AnsiString: myURL; myURL: = 'http: // ...' BASS_StreamCreateURL (PAnsiChar (myURL), 0, [...] и работал над Delphi XE2 – vhanla

ответ

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) 

который является строка «т», заканчивающийся нулевым символом (00).

PAnsiChar(AnsiString(url)) 

с другой стороны будет первым преобразовать строку Юникода в строку ANSI, то есть, вы получите

74 65 73 74 00       t e s t #0     (Ansi) 

который является строка «тест» заканчивается нулевым символом (00) ,

Update

Я не экстрасенс (пока), но, возможно, библиотека Bass на самом деле требуется указатель на UnicodeString в качестве первого аргумента этой функции? Это объясняет, почему кажущееся нечетным

PAnsiChar(url) 

работы.Библиотека может сказать: «Эй, просто дайте мне указатель на строку юникода, и я сделаю с ней ручную обработку», и приведенный выше код делает это (указатель - это просто указатель (то есть 32-значный 32-разрядный целое число) ...). Но компилятор, конечно, пожалуется, потому что библиотека объяснила компилятору, что для этого потребуется PAnsiChar, и обычно PAnsiChar(SomeUnicodeString) - это плохо. Если это так, то, конечно,

PAnsiChar(AnsiChar(url)) 

не работает. Библиотека ожидает/адрес строки/unicode, но получает/адрес/ansi-строки.

Update 2

Если моя гипотеза в Update 1 правильно, декларация

function BASS_StreamCreateURL(url: PWideChar; offset: DWORD; flags: DWORD; 
    proc: DOWNLOADPROC; user: Pointer):HSTREAM; stdcall; external bassdll; 

бы небо снова синий.

Update 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}); 
+0

Я полностью согласен с вашим анализом. И все же, тип «suspiciuos» работает, в то время как тот, который должен быть прав, вызывает ошибку от BASS. Такое же поведение в Delphi XE и 2009. (Одна из демонстраций, которые поставляются с BASS, также использует простое преобразование из строки в PAnsiChar.) –

+2

Re your Update 3: Флаг BASS_UNICODE действительно присутствует в моем коде. И вы, вероятно, правы в своей ранней догадке. Поскольку флаг * указан *, BASS ожидает PWideChar, хотя в декларации говорится иначе. Большое спасибо, Andreas! –

+0

+1 отличный ответ ! – jpfollenius

1

Следующие фрагменты кода отлично работает в моем опыте. {$IFDEF UNICODE} или BASS_UNICODE {$ENDIF}

 Смежные вопросы

  • Нет связанных вопросов^_^