因項目需要,我用Delphi寫了一個連接數據庫把數據導出到Sql文件的dll,其中使用了TADOQuery組件。
其中只有一個導出方法:
function DataExport(path,ini_path:PChar):integer;
寫完之後,用delphi寫了一個test.exe進行測試,發現可以正常使用。
之後便把這個dll交給了同事,讓他在PowerBuilder中調用。同事拿過去之後發現,一旦調用DataExportPB就報告無法打開目標Dll。我想可能是因為兩邊運行的環境不一樣,隨後就把test.exe拷過去試試看。奇怪的是,test.exe運行正常。
為了確定問題到底出現在哪裡,我又使用Python和C#測試了一下,C#下面沒有問題,但是Python報告錯誤:
沒有調用CoInitialize()
查閱資料之後發現,如果在Delphi的Dll裡面使用了ADO組件,那麼需要在使用之前調用ActiveX的CoInitialize方法。知道了問題之後就好辦多了,在源代碼中創建TADOQuery之前調用CoInitialize(),Python調用成功。
本以為PowerBuilder也應該沒問題,可誰知還是一樣的問題。這下子我想不通了。 Python中的ctypes模塊使用的C中的調用方法,參數傳遞方式應該和PowerBuilder一樣,可是為什麼PB裡面還是不行呢?同事讓我在Dll裡面多寫一個輸出方法試試看,那好,我又寫了下面這樣一個方法:
function test:PChar;
begin
result := 'Test string from test';
end;
PB裡面調用test方法成功, 接著同事又嘗試調用DataExport,成功了! ! ? ?為什麼?這個test方法僅僅只是輸出一段固定的字符串而已,為什麼DataExport就調用成功了呢?我真是百思不得其解。
但是這時又出現一個問題,一旦退出PB應用程序則發生一個內存操作錯誤。
我仔細檢查了Delphi代碼,以圖發現是不是哪一個對像沒有釋放,我的代碼如下:
function DataExport(path,ini_path:PChar):integer;
var
query : TADOQuery;
begin
.........
CoInitialize();
query := TADOQuery.Create(nil);
.........
query.Close;
query.Free;
CoUnInitialize();
.........
end;
沒有什麼問題啊!無奈之下我把CoInitialize()和CoUnInitialize()分成兩個獨立方法。
function init:integer;
begin
try
CoInitialize();
result := 1;
except
on Exception:
result := 0;
end;
end;
function uninit:integer;
begin
try
CoUnInitialize();
result := 1;
except
on Exception:
result := 0;
end;
end;
然後讓同事在窗體初始化事件中先調用init,然後再關閉事件中調用uninit。問題解決。什麼都正常了。
雖然問題得到解決,但是我還是不明白為什麼要這樣做。