線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:2421
推到 Plurk!
推到 Facebook!

dll 函式中宣告 string 本地變數,是否會產生問題?

尚未結案
cancer
高階會員


發表:58
回覆:319
積分:190
註冊:2004-07-31

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-08-29 15:08:52 IP:210.201.xxx.xxx 未訂閱
各位大大,    我寫了一個 Dll 檔,裡面有一個函式,是給 InstallShield 在安裝 時驗證使用者輸入的序號用的。下面第一個函式是我經多次修改後才 能正確使用的函式,執行無誤,安裝過程很順利,就算使用者輸入錯 誤序號,安裝程式就給最多三次的機會,三次全錯,就停止安裝。    第二個函式是修改前的函式,當使用者輸入正確的序號,則安裝順利完成, 但如果輸入錯誤的序號,安裝程式立即報告 "The Called DLL was crashed" 的錯誤,並忽略剩下的重試機會,安裝過程就結束了。    在 InstallShield 裡面已設定六個輸入格,而且只能輸入數字。    正確執行的函式如下:
function ValidateSerial
( h : THandle ; a,b,c,d : PChar) : Integer; stdcall;
begin                               // 序號為 543210
   if (c[0] = '5') and (c[1] = '4') and 
      (c[2] = '3') and (c[3] = '2') and 
      (c[4] = '1') and (c[5] = '0') and (c[6] = #0)
   then result := 1         // 通過驗證
   else result := -1;
end
不能正確執行的函式如下:
function ValidateSerial
( h : THandle ; a,b,c,d : PChar) : Integer; stdcall;
var s : string;
begin
   s := c;
   if StrToInt(s) = 543210                              
   then result := 1   
   else result := 0;
end
第二個函式宣告了一個 string 型態的變數,是不是這種 Delphi 專用的變數型態使得函式被其他 C/C 程式碼呼叫時會產生問題? 奇怪的是,函式若傳回 true 就沒問題,傳回 false 就連累整個 Dll 都 Crash 掉。 謝謝
leajean
一般會員


發表:1
回覆:3
積分:0
註冊:2005-01-24

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-08-29 16:08:54 IP:219.148.xxx.xxx 未訂閱
我注意到:傳回 false,第二個函式是 0, 第一個函式是 -1 :-P
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-08-29 16:14:32 IP:203.69.xxx.xxx 未訂閱
上例失敗傳回 -1 ? 為何下例傳回 0? http://delphi.ktop.com.tw/topic.php?TOPIC_ID=76298 參考一下
cancer
高階會員


發表:58
回覆:319
積分:190
註冊:2004-07-31

發送簡訊給我
#4 引用回覆 回覆 發表時間:2005-08-29 23:09:37 IP:210.201.xxx.xxx 未訂閱
不好意思,打錯字啦。因為我一開始設計時,傳回值以 1 為成功, 2 為失敗,為了讓各位不會多想我為甚麼會選擇傳回 2,於是我想把它 改成-1,結果一時弄錯,變成 0。 所以,第二個函式失敗時是傳回 2,不是 0。    失敗的函式應是如此:
function ValidateSerial
( h : THandle ; a,b,c,d : PChar) : Integer; stdcall;
var s : string;
begin
   s := c;
   if StrToInt(s) = 543210                              
   then result := 1   
   else result := 2;
end
但其實傳回 0 跟傳回 2 都不應該使整個 dll crash 掉。但反而是傳回 1 的話,一切就正常。 另外最重要最重要的是,為了找出真正原因,我在第一個函式中宣告一個 string變數,但我沒有使用它,於是同樣的問題又出現了,亦即只要傳回 值不是 1,dll就 crash 掉。再把 var s : string 拿掉,不傳回 1 , 也能正常運作。我又試過宣告一個整數,同樣不使用它,卻又不會有這個 問題,所以,這個問題跟那個 var s : string; 應該關係重大,因為 InstallShield 所提供的範例是用 C ,而且肯定一點是,InstallShield 用 C 程式碼來呼叫我的 dll 函式。
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#5 引用回覆 回覆 發表時間:2005-08-29 23:58:38 IP:61.219.xxx.xxx 未訂閱
改用 ShortString 試試, 或者在 DLL 的 uses 區 加入ShareMem, 而且要放第一個哦...
adonis
高階會員


發表:140
回覆:258
積分:159
註冊:2002-04-15

發送簡訊給我
#6 引用回覆 回覆 發表時間:2005-09-01 09:51:38 IP:61.62.xxx.xxx 未訂閱
cancer, 您好    s:=c; <-- 建議改成 s:=strpas(c);    Help - StrPas: Converts null-terminated string to a Pascal string.    至於~
引言: 另外最重要最重要的是,為了找出真正原因,我在第一個函式中宣告一個 string變數,但我沒有使用它,於是同樣的問題又出現了,亦即只要傳回 值不是 1,dll就 crash 掉。再把 var s : string 拿掉,不傳回 1 , 也能正常運作。我又試過宣告一個整數,同樣不使用它,卻又不會有這個 問題,所以,這個問題跟那個 var s : string; 應該關係重大
這個問題我之前也有碰過,情形和你一樣,但唯一的不同是我的函數還有去調用其他函數,是在後段因 String 形態的相關問題所致。但後來發現只要有正確的調用 String & PChar 之間的轉換大致上是沒有問題的。 我也在學習中,若回應不當請見諒 ~ 發表人 - adonis 於 2005/09/01 09:59:32
------
我也在努力學習中,若有錯謬請見諒。
cancer
高階會員


發表:58
回覆:319
積分:190
註冊:2004-07-31

發送簡訊給我
#7 引用回覆 回覆 發表時間:2005-09-09 16:34:13 IP:210.201.xxx.xxx 未訂閱
adonis 大大您好, 不好意思了,我以為沒有人會再回應,所以沒回來看。 S := c; 在 delphi 中是合法的,能通過編譯,也能正確執行, 因為 Delphi 會自動進行轉換。 我想是 Delphi 在處理這種轉換是會按照 Application 或 dll 而有所不同,也就是說,在 dll 中, delphi 不會自動把 string 轉為 C 的 null-terminated string,必須由我們手動轉換。
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#8 引用回覆 回覆 發表時間:2005-09-10 00:00:15 IP:61.219.xxx.xxx 未訂閱
Dll 中使用 String 不光是參數傳遞的問題, 而是只要你有使用 在 Dll 中使用 String 變數, 就有可能造成 crash... http://delphi.ktop.com.tw/topic.php?TOPIC_ID=76298 http://delphi.ktop.com.tw/topic.php?topic_id=76060 這兩篇都在討論這個問題....
adonis
高階會員


發表:140
回覆:258
積分:159
註冊:2002-04-15

發送簡訊給我
#9 引用回覆 回覆 發表時間:2005-09-10 09:12:10 IP:61.62.xxx.xxx 未訂閱
Dear All    基本上應該是在 export 出來的介面窗口盡可能不要去使用String型態而改用PChar應該就沒問題才是(就String資料型態而言) Help-  
引言: { Important note about DLL memory management: ShareMem must be the first unit in your library's USES clause AND your project's (select Project-View Source) USES clause if your DLL exports any procedures or functions that pass strings as parameters or function results. This applies to all strings passed to and from your DLL--even those that are nested in records and classes. ShareMem is the interface unit to the BORLNDMM.DLL shared memory manager, which must be deployed along with your DLL. To avoid using BORLNDMM.DLL, pass string information using PChar or ShortString parameters. }
雖然S := c; 在 delphi 中是合法的,能通過編譯,也能正確執行,因為 Delphi 會自動進行轉換。但我還是建議在DLL中使用 StrPas 來StrPas: Converts null-terminated string to a Pascal string.會比較安全一點。 以上是我的一些看法,如有錯謬請見諒 ~ 因為我也正在學習中。
------
我也在努力學習中,若有錯謬請見諒。
cancer
高階會員


發表:58
回覆:319
積分:190
註冊:2004-07-31

發送簡訊給我
#10 引用回覆 回覆 發表時間:2005-09-10 12:46:38 IP:210.201.xxx.xxx 未訂閱
謝謝 malanlk 和 adonis 兩位的回應, 雖然使用 Delphi 的 string 可以善用內建的字串處理函式, 我想最保險的方法還是直接使用 C 的 null-terminated string 比較直接了當,省去一切的麻煩,雖然會辛苦一點,但程式的穩定性 才是軟體的重要考量。
系統時間:2024-04-20 1:01:09
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!