全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1577
推到 Plurk!
推到 Facebook!

呼叫DLL時發生記憶體錯誤,一個很怪的問題

答題得分者是:jow
cliffdean
一般會員


發表:9
回覆:14
積分:4
註冊:2004-12-07

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-12-17 16:23:56 IP:61.222.xxx.xxx 未訂閱
1.DLL裡面是這樣: ---------------------------------------------------------- function GetRegValue(regName: String):PChar; stdcall; var reg : TRegistry; begin reg := TRegistry.Create; try result := PChar(''); reg.RootKey:=HKEY_CURRENT_USER; if reg.OpenKey('\Software\msoft',True) then begin result := PChar(reg.ReadString(regName)); end; finally reg.CloseKey; reg.Free; end; end; ----------------------------------------------------------- 宣告的時候是 ----------------------------------------------------------- function GetRegValue(regName:string):PChar;stdcall; external 'functions.dll'; ----------------------------------------------------------- 結果假設我的註冊檔中某個變數的值是mylove結果每次呼叫GetRegValue的結果都不太一樣,有的時候會正常,有的時候會變成mylo後面的ve不見了。 另一個問題也是在呼叫DLL的時候發生的...... 在DLL裡面是這樣 ------------------------------------------------------------- function GetInsertTime(conn : TADOConnection ) : Pchar ;stdcall;export; var qryGetTime : TADOQuery; var strTmp : string; begin qryGetTime := TADOQUERY.Create(Application); qryGetTime.Connection := conn; qryGetTime.SQL.Clear(); qryGetTime.SQL.Add('SELECT NOW()'); qryGetTime.Open(); strTmp:= FormatDateTime('yyyy-mm-dd hh:nn:ss',qryGetTime.Fields[0].AsDateTime); result := Pchar(strTmp); qryGetTime.Free(); end; ---------------------------------------------------------- 因為呼叫這支程式的時候是同一個DLL裡面的不同unit所以引用時是這樣寫的 implementation uses Undllsystem,Undllreg; 而我在下面呼叫GetInsertTime的時候,如果再呼叫前先隨便ShowMessage一個訊息再呼叫就會正常,而一把Showmessage拿掉,程式就會出錯,錯誤訊息是access violation as address ..... 但是上面兩個函數在別的地方呼叫又都正常,應該不是函數的問題,我猜想應該是記憶體的問題,請高手指導一下,謝謝!
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-12-17 16:45:24 IP:220.130.xxx.xxx 未訂閱
引言: 1.DLL裡面是這樣: ---------------------------------------------------------- function GetRegValue(regName: String):PChar; stdcall; var reg : TRegistry; begin reg := TRegistry.Create; try result := PChar('');//多的 reg.RootKey:=HKEY_CURRENT_USER; if reg.OpenKey('\Software\msoft',True) then begin result := PChar(reg.ReadString(regName)); end; finally reg.CloseKey; reg.Free; end; end; ----------------------------------------------------------- 宣告的時候是 ----------------------------------------------------------- function GetRegValue(regName:string):PChar;stdcall; external 'functions.dll'; ----------------------------------------------------------- 結果假設我的註冊檔中某個變數的值是mylove結果每次呼叫GetRegValue的結果都不太一樣,有的時候會正常,有的時候會變成mylo後面的ve不見了。 另一個問題也是在呼叫DLL的時候發生的...... 在DLL裡面是這樣 ------------------------------------------------------------- function GetInsertTime(conn : TADOConnection ) : Pchar ;stdcall;export; var qryGetTime : TADOQuery; var strTmp : string; begin qryGetTime := TADOQUERY.Create(Application); qryGetTime.Connection := conn; qryGetTime.SQL.Clear(); qryGetTime.SQL.Add('SELECT NOW()'); qryGetTime.Open(); strTmp:= FormatDateTime('yyyy-mm-dd hh:nn:ss',qryGetTime.Fields[0].AsDateTime); result := Pchar(strTmp); qryGetTime.Free(); end; ---------------------------------------------------------- 因為呼叫這支程式的時候是同一個DLL裡面的不同unit所以引用時是這樣寫的 implementation uses Undllsystem,Undllreg; 而我在下面呼叫GetInsertTime的時候,如果再呼叫前先隨便ShowMessage一個訊息再呼叫就會正常,而一把Showmessage拿掉,程式就會出錯,錯誤訊息是access violation as address ..... 但是上面兩個函數在別的地方呼叫又都正常,應該不是函數的問題,我猜想應該是記憶體的問題,請高手指導一下,謝謝!
------------------- 幫忙重貼程式碼. 我覺得你在DLL中用的資料型態應多斟酌.除非你用的式BPL. 引言上標記紅色部分,我認為用在DLL中並不適當.
cliffdean
一般會員


發表:9
回覆:14
積分:4
註冊:2004-12-07

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-12-17 17:00:50 IP:61.222.xxx.xxx 未訂閱
jow大大感謝您的回覆, 因為我是delphi的新手,是不是可以請您說明一下何謂BPL 另外您紅色部分我也不知道該怎麼改....... string改用Pchar那Application要用?? 唉...書上都沒教說......
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-12-17 17:38:02 IP:220.130.xxx.xxx 未訂閱
你好,因為一般的DLL檔來說,你不能預期它是使用 Delphi來做為開發工具,所以如果你是開發通用性 質的DLL,那麼在使用資料型別上就要考慮到相容 性的問題,Delphi中特有的資料型別以及VCL類別, 基本上是不具相容性的.    而bpl檔則是Delphi特定格式的Library檔案,你可 以用下方式開啟一個新的Borland Package 專案     File->New->Other->(New Page)下選擇 Package項目 之後你可以將你的檔案Add到這裡來,程式的寫法如同 一般專案的開發,並且其中也可以包含元件的開發. Package 專案經過編譯連結後產生 *.bpl形式的檔案, 其實它就是DLL檔了. 在這裡任何Delphi資料型態都可使用,基本上是沒有限制的. 至於 Global Application Object寫入DLL檔案中, 基本上你要先確定,它真的存在,例如非Application的專 案Call到你的Function 時會有何狀況? 最後語法上的邏輯有些盲點:
function GetInsertTime(conn : TADOConnection ) : Pchar ;stdcall;export;
    var qryGetTime : TADOQuery;
    var strTmp : string;
begin
    (1)qryGetTime := TADOQUERY.Create(Application);
    (2)qryGetTime.Connection := conn;        [red]///// Application 有沒有可能不存在?
    [red]///// 步驟(1)產生的物件會造成記憶體遺漏.        ...
end;
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#5 引用回覆 回覆 發表時間:2004-12-17 17:45:39 IP:220.130.xxx.xxx 未訂閱
漏掉一點!    qryGetTime.Free();    傳入的物件被你Free掉了,如果呼叫端再次引用它, 或者它原本就是預置在Form或DataModule上的元件, 事情就有點麻煩了.    個人觀點,有錯純屬意外....
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#6 引用回覆 回覆 發表時間:2004-12-17 17:57:58 IP:220.130.xxx.xxx 未訂閱
糟糕!我看錯了,最後所指的語法邏輯上的問題, 原來的語法應該是對的. Sorry.
cliffdean
一般會員


發表:9
回覆:14
積分:4
註冊:2004-12-07

發送簡訊給我
#7 引用回覆 回覆 發表時間:2004-12-20 10:18:43 IP:61.222.xxx.xxx 未訂閱
感謝JOW大大回覆: 但是實際上這些DLL我確定呼叫的都會是DELPHI,因為實際上 我並不打算讓其他的程式呼叫這些DLL,主要會做成DLL只是為了, 把程式切成好幾個部分來設計,到時候可以拆開使用, 但是呼叫的一定都是我自己寫的程式。 另外您提及的會不會沒有Application其實我不知道什麼情況下會沒有Application, 原則上我是主程式呼叫一個DLL來執行,當然也有可能在DLL中呼叫另一個DLL, 所以您所謂的沒有Application是不是就是這種情況。
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-12-20 11:04:45 IP:220.130.xxx.xxx 未訂閱
我就是考慮這樣的狀況,如果Application在程式碼中, 並不是那麼必要,其實可以用nil來代換掉,畢竟Free的 動作還是得要自己做的.
cliffdean
一般會員


發表:9
回覆:14
積分:4
註冊:2004-12-07

發送簡訊給我
#9 引用回覆 回覆 發表時間:2004-12-20 17:40:47 IP:61.218.xxx.xxx 未訂閱
感謝Jow大大: 我已經全部改完了,但是仍然有一樣的問題。 不知道還有哪邊得要注意的。
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#10 引用回覆 回覆 發表時間:2004-12-20 18:32:41 IP:220.130.xxx.xxx 未訂閱
測試看看,是否因為Connection尚未完成;    
function GetInsertTime(conn : TADOConnection ) : Pchar ;stdcall;export;
var 
  qryGetTime : TADOQuery;
  strTmp : string;
  Timeout: Cardinal;
begin
  qryGetTime := TADOQUERY.Create(Application);
  try
    qryGetTime.Connection := conn;
    qryGetTime.SQL.Clear();
    qryGetTime.SQL.Add('SELECT NOW()');    
    Timeout := GetTickCount   10000; //設定Timeout = 10秒
    qryGetTime.Open(); 
    while not qryGetTime.Active and (GetTickCount
cliffdean
一般會員


發表:9
回覆:14
積分:4
註冊:2004-12-07

發送簡訊給我
#11 引用回覆 回覆 發表時間:2004-12-21 11:03:07 IP:61.218.xxx.xxx 未訂閱
感謝JOW大大.. 總結一下現在的情況,我把Application改成nil之後,mylove變成mylo的問題解決了,但是呼叫GetInsertTime的時候,如果在呼叫前先隨便ShowMessage一個訊息再呼叫就會正常,而一把Showmessage拿掉,程式就會出錯,錯誤訊息是access violation as address .....,這個問題還是沒解決,我後來試了JOW大大寫的結果來是一樣,有ShowMessage才會正常...
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#12 引用回覆 回覆 發表時間:2004-12-21 11:40:50 IP:220.130.xxx.xxx 未訂閱
一般來說出現access violation as address .....訊息的情況, 都是發生在記憶體存取上的錯誤,你可以將function GetInsertTime()先實作 在你的主程式裡,然後設定中斷點,step by step的去檢查看看.
cliffdean
一般會員


發表:9
回覆:14
積分:4
註冊:2004-12-07

發送簡訊給我
#13 引用回覆 回覆 發表時間:2004-12-21 15:40:22 IP:61.222.xxx.xxx 未訂閱
最後發現在我的functions.dll裡的不同unit互相呼叫,就會發生問題, 我把會互相呼叫的unit切開成不同的DLL就解決了..
系統時間:2024-05-21 22:41:11
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!