1. 程式人生 > >Delphi XE7呼叫C++動態庫出現亂碼問題

Delphi XE7呼叫C++動態庫出現亂碼問題

  事情源於有個客戶需使用我們C++的中介軟體動態庫來跟裝置連線通訊,但是傳入以及傳出的字串指標格式都不正確(出現亂碼或是被截斷),估計是字元編碼的問題導致。以下是解決問題的過程:
  我們C++中介軟體動態庫的介面函式宣告:

extern "C" bool __stdcall ExecuteTaskInFile(const char *szTaskID, const char *szInputFile, const char *szOutputFile, bool bSynch);

傳入的字串指標要求是Ansi編碼。
  我們給客戶提供的Delphi例子是用Delphi7寫的:
宣告:

function ExecuteTaskInFile(szTaskID : Pchar; szInputFile:Pchar; szOutputFile:PChar; bSynch :boolean):boolean;stdcall;external 'XXXX.dll';

呼叫:

function ExecuteFileTask():boolean;

var

strTaskID:string;

begin

	//略去若干註釋
	
	strTaskID := '20160222111817081';
	
	Result := ExecuteTaskInFile(pchar(strTaskID), pchar('C:\Data\TestData\Input\Task.xml'),pchar('C:\Data\TestData\Output\TaskResult.xml'), true);

end;

  但是該程式拿到客戶處編譯執行後出現一些莫名錯誤,據客戶反饋,他們也是使用Delphi,因此懷疑方向一度轉到傳入的資料檔案內容是否有錯誤上,但從客戶處取回資料檔案後測試也無問題。不得已,只能上門拜訪了下客戶,幸好不是很遠。到了現場才得知使用者使用的Delphi是Delphi XE7,已經是Borland將Delphi拋棄很多年以後的事情了,距離我使用過的Delphi7也已經是12年後了。
  在客戶現場檢視動態庫介面的日誌,發現瞭如下的記錄:
2018-10-15 13:28:14,318 [0x000012c0] INFO RUNNING 0 XXXX.XXXX Enter XXXX::ExecuteTaskInFile(TaskId:2

)
而我們傳入的TaskId其實是’20160222111817081’,只取到了第一個字元,那麼很有可能是傳入的指標指向的字串是使用Unicode編碼的,其第二個位元組是0x00被當作字串結束符而截斷了。
  很多年沒有關注Delphi,又回顧了下Delphi的歷史,Delphi7還是Ansi編碼的IDE,因此上面的程式碼呼叫C++動態庫傳入Ansi字串沒有問題, 而Delphi從2009開始完整正式支援Unicode,之後的XE7是2014年釋出的。 Delphi在2009以後對應char*的型別為PWideChar,因此預設使用了Unicode編碼,如果要用Ansi編碼,必須是PAnsiChar。
  這樣看來,問題就簡單明瞭了,將Delphi程式碼改成如下後測試通過:
宣告:

function ExecuteTaskInFile(szTaskID : PAnsichar; szInputFile:PAnsichar; szOutputFile:PAnsiChar; bSynch :boolean):boolean;stdcall;external 'XXXX.dll';

呼叫:

function ExecuteFileTask():boolean;

var

  strTaskID:string;

begin

    strTaskID := '20160222111817081';

    Result := ExecuteTaskInFile(pAnsichar(AnsiString(strTaskID)), pAnsichar('C:\Data\TestData\Input\Task.xml'), pAnsichar('C:\Data\TestData\Output\TaskResult.xml'), true);

end;

  值得注意的是,當使用字串變數傳遞時,必須加以AnsiString轉換,而常量字串引數則可不用,後面再仔細研究了。
  總結:其實事情本不復雜,可以通過簡單的溝通就瞭解到客戶的使用場景以及動態庫的呼叫日誌然後做針對性的分析,但是我們常常會忽略一些細節從而做出一些片面的判斷導致問題複雜化,遇到問題時按部就班,不放過一個細節,針對性的分析解決才是正確的做法。
  忌 一葉蔽目,管中窺豹。
  宜 審問慎思,明辨篤行。