C#引用DLEPHI 的DLL檔,傳回字串結果不同 |
答題得分者是:aftcast
|
superrakce
一般會員 發表:24 回覆:35 積分:11 註冊:2006-10-09 發送簡訊給我 |
|
aftcast
站務副站長 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
不知你的dll是怎麼寫的,但理論上僅可傳入PChar這類的參數,且記憶體的配置要使用win32 api 裡的,如GlobalAlloc之類的來配,如此配出來的記憶區塊才可以在不同的語言間正常運作。
當然,我個人覺得用bcb寫的dll來給c#用可能更方便一點。不過原理還是一樣同上就是。 以上是我初步的看法,請參考! ===================引 用 superrakce 文 章=================== 使用DELPHI 寫了一個DLL檔(加解密字串功能), 使用DLEPHI測試可以加密及反解回來。 但用C# 引用時,同樣的文字去加密, 加密後得到的字串卻不相同, 且反解時只能解到前三分之一,其它都為亂碼。 交叉使用(用DELPHI 加密一文字後得到的密文去C#反解) 一樣不行。 是開發環境的問題嗎? DELPHI 7 VISUAL STUDIO 2008
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan |
rick060
高階會員 發表:2 回覆:112 積分:217 註冊:2009-11-17 發送簡訊給我 |
[code c#] public partial class Form1 : Form {[DllImport("Project1.dll")] public static extern String func_EncryptKey([MarshalAs(UnmanagedType.LPStr)]String src, [MarshalAs(UnmanagedType.LPStr)]String key); [DllImport("Project1.dll")] public static extern String func_DecryptKey([MarshalAs(UnmanagedType.LPStr)]String src, [MarshalAs(UnmanagedType.LPStr)]String key); public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { String retString; retString = func_EncryptKey("This is it", ""); MessageBox.Show(retString); retString = func_DecryptKey(retString,""); MessageBox.Show(retString); } } [/code] [code delphi] function func_EncryptKey(Src: PAnsiChar; Key: PAnsiChar) : PAnsiChar;stdcall; begin ShowMessage(Src); ShowMessage(Key); Result := PAnsiChar('ReturnString'); end; function func_DecryptKey(Src: PAnsiChar; Key: PAnsiChar): PAnsiChar;stdcall; begin ShowMessage(Src); ShowMessage(Key); Result := PAnsiChar('ReturnString'); end; exports func_EncryptKey; exports func_DecryptKey; [/code] 除錯第一要務,單純化,再求問題點 先確定 C# call dll 可以正常傳進傳出 正確的字串,再研究是哪部份的問題 |
superrakce
一般會員 發表:24 回覆:35 積分:11 註冊:2006-10-09 發送簡訊給我 |
您給的範例很有用,但我套入程式碼後便不行
因為要作字串加解碼 function Encrypt(st: PAnsiChar):PAnsiChar; var a: array[1..n] of TStrings; i,j,k,d,ra: integer; s,temp:string; begin s:= st; 然後作一些運算,如:t:= t inttostr(Xmod(Ord(s[i]))); 最後result :=PAnsiChar(t); 在c# 調用時發生「嘗試讀取或寫入受保護的記憶體。這通常表示其他記憶體已損毀。」這項錯誤 但如果在result := PAnsiChar(t); 前面先加上showmessage(t); 就不會有問題。 而且不是每次都管用,有時會彈出訊息框完了會正確執行,有時候還是一樣跑出記憶體已損毀的錯誤 這樣是那邊出了問題? ===================引 用 rick060 文 章=================== [code c#] public partial class Form1 : Form {[DllImport("Project1.dll")] public static extern String func_EncryptKey([MarshalAs(UnmanagedType.LPStr)]String src, [MarshalAs(UnmanagedType.LPStr)]String key); [DllImport("Project1.dll")] public static extern String func_DecryptKey([MarshalAs(UnmanagedType.LPStr)]String src, [MarshalAs(UnmanagedType.LPStr)]String key); public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { String retString; retString = func_EncryptKey("This is it", ""); MessageBox.Show(retString); retString = func_DecryptKey(retString,""); MessageBox.Show(retString); } } [/code] [code delphi] function func_EncryptKey(Src: PAnsiChar; Key: PAnsiChar) : PAnsiChar;stdcall; begin ShowMessage(Src); ShowMessage(Key); Result := PAnsiChar('ReturnString'); end; function func_DecryptKey(Src: PAnsiChar; Key: PAnsiChar): PAnsiChar;stdcall; begin ShowMessage(Src); ShowMessage(Key); Result := PAnsiChar('ReturnString'); end; exports func_EncryptKey; exports func_DecryptKey; [/code] 除錯第一要務,單純化,再求問題點 先確定 C# call dll 可以正常傳進傳出 正確的字串,再研究是哪部份的問題
編輯記錄
|
rick060
高階會員 發表:2 回覆:112 積分:217 註冊:2009-11-17 發送簡訊給我 |
function 後有 stdcall; 嗎
或在 DllImport 指定 Call Convention 配合 delphi 裡的宣告 [DllImport("Project1.dll",CallingConvention = CallingConvention.StdCall]
編輯記錄
rick060 重新編輯於 2011-07-14 18:45:57, 註解 無‧
|
superrakce
一般會員 發表:24 回覆:35 積分:11 註冊:2006-10-09 發送簡訊給我 |
CallingConvention = CallingConvention.StdCall
最新測試結果,字串長度為12以上,執行第一次會成功, 第二次之後全都失敗(測試的都是同樣的字串), 都是同樣的錯誤 (在delphi 的dll 程式裡,在回傳前都會showmessage 要回傳的值,showmessage 都是正常的,只要回傳回來就出錯) 九點十五分測試結果: 修改 dll 檔: //showmessage(s); //result := PAnsiChar(s); showmessage(s ' ' inttostr(length(s))); result := PAnsiChar(s inttostr(length(s))); 這樣就不會出錯…真是太神奇了,不過這不是我要的功能,依舊看不出來問題在那? ===================引 用 rick060 文 章=================== function 後有 stdcall; 嗎 或在 DllImport 指定 Call Convention 配合 delphi 裡的宣告 [DllImport("Project1.dll",CallingConvention = CallingConvention.StdCall]
編輯記錄
superrakce 重新編輯於 2011-07-14 19:12:38, 註解 無‧
superrakce 重新編輯於 2011-07-14 19:13:19, 註解 無‧ superrakce 重新編輯於 2011-07-14 19:20:04, 註解 無‧ |
rick060
高階會員 發表:2 回覆:112 積分:217 註冊:2009-11-17 發送簡訊給我 |
|
superrakce
一般會員 發表:24 回覆:35 積分:11 註冊:2006-10-09 發送簡訊給我 |
1.ebp/esp?指的是堆疊嗎?DLL 裡面只用到一些字串處理函數,應該不會造成問題才是
2.裡面只有宣告INTGER 、 STRING 跟陣列 array[1..n] of TStrings; 而陣列在回傳前有把他 Free 3.不至於是 stack overflow ,因為回傳值加上一個字就不會出問題了。 最後測試結果: 加密的字串尾巴加上隨便一個字,回傳正常; 解密碼字串刪除最後一個字,解密成功,回傳正常。 附上「部份」程式碼; 這樣子雖然功能完成了,但我很想知道發生了什麼事, 在DELPHI 內 呼叫都沒這個問題,為何到了C#去呼叫就有這個毛病,怪哉 [code delphi] function Encrypt(st: PAnsiChar):PAnsiChar; var a: array[1..n] of TStrings; i,j,k,d,ra: integer; t,ErrMsg,s:string; begin s:= st; ErrMsg := Check(s); if ErrMsg='' then begin k := Length(s); for i:=1 to n do a[i] := TStringList.Create; ra := Ord(t[1])*1000 Ord(t[2])*100 Ord(t[3]); for i:=1 to k do if Ord(s[i]) in [33..126] then t := t Chr(StrToInt(a[i][Ord(s[i]) - 33])) else t := t s[i]; for i:=1 to n do a[i].Free; result := PAnsiChar(t ':.:'); end else result := PAnsiChar(ErrMsg); end; function Decrypt(ts:PAnsiChar):PAnsiChar; var a: array[1..n] of TStrings; ra,i,k: integer; s,ErrMsg,t:string; function FindNo(b,c: byte): char; begin FindNo := Chr(a[b].IndexOf(IntToStr(c)) 33); end; begin t:= ts; t:= leftstr(t,length(t)-3); s := ''; ErrMsg := Check(t); if ErrMsg='' then begin k := Length(t); for i:=1 to n do a[i] := TStringList.Create; ra := Ord(t[1])*1000 Ord(t[2])*100 Ord(t[3]); Delete(t,1,3); k := k - 3; for i:=1 to k do uniNO(ra i, a[i]); for i:=1 to k do if Ord(t[i]) in [33..126] then s := s FindNo(i, Ord(t[i])) else s := s t[i]; for i:=1 to n do a[i].Free; result := PAnsiChar(s ' '); end else result := PAnsiChar(ErrMsg); end; [/code] ===================引 用 rick060 文 章=================== 我想你也不方更 po出你 dll 的 source
但可以給你一個方向 1.dll "BEGIN" 前 的 ebp/esp 與 "END"完 ret 前 的 ebp/esp要一樣。 (CPU View) 2.function 內檢查是否有應釋放而未釋放的記憶體 3.function 內是否有 stack overflow 的可能 |
aftcast
站務副站長 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
以組合語言的觀點來看,你那樣寫dll的方式感覺不太正確,僅管我對delphi的語法已不熟。
以加密來說,裡面的t 字串,是局部變數,當你把它的指標傳出去後,理論上t的內容已不是正確的那個,它變垃圾了,當然運氣好一點可能只有小破壞到,於是你以為是正確的。 你細想一些win32 api,是不是很少傳 char* 出來,都是要你把你想要的東西放到參數中,這時候這個參數是你事先配好的記憶區塊,所以不會出事,當然會配套要你傳入長度,以免放過頭… 請試一下把 加密裡的 t 移至 function 外面,讓它變成全域的。解密的 s 也變成全域的。 這時候t 與 s 不會因為function結束而被釋放。理論上才會是正常的。 然後再試一下,若從此沒問題,那就很肯定是我上面講的問題! ps 全域後的名稱要換一下,不好又是s與t的,以免"打架" 以上是我另一種觀點 : ) ===================引 用 superrakce 文 章=================== 最後測試結果: 加密的字串尾巴加上隨便一個字,回傳正常; 解密碼字串刪除最後一個字,解密成功,回傳正常。 附上「部份」程式碼; 這樣子雖然功能完成了,但我很想知道發生了什麼事, 在DELPHI 內 呼叫都沒這個問題,為何到了C#去呼叫就有這個毛病,怪哉
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan |
superrakce
一般會員 發表:24 回覆:35 積分:11 註冊:2006-10-09 發送簡訊給我 |
|
superrakce
一般會員 發表:24 回覆:35 積分:11 註冊:2006-10-09 發送簡訊給我 |
大大,很抱歉在結案後測試發現新問題
在加密後存到資料庫讀出後會無法解密。 delphi 內測試過程 : 1. 加密Edit1 字串> 傳至edit2>解密edit2字串>還原正常 2.加密Edit1 字串> 寫入資料庫>讀出解密字串>還原異常(有部份字體亂碼) c# 的測試則完全呈現 delphi 測試的第2種結果 小弟猜測是字元編碼的問題? ===================引 用 aftcast 文 章=================== 以組合語言的觀點來看,你那樣寫dll的方式感覺不太正確,僅管我對delphi的語法已不熟。 以加密來說,裡面的t 字串,是局部變數,當你把它的指標傳出去後,理論上t的內容已不是正確的那個,它變垃圾了,當然運氣好一點可能只有小破壞到,於是你以為是正確的。 你細想一些win32 api,是不是很少傳 char* 出來,都是要你把你想要的東西放到參數中,這時候這個參數是你事先配好的記憶區塊,所以不會出事,當然會配套要你傳入長度,以免放過頭… 請試一下把 加密裡的 t 移至 function 外面,讓它變成全域的。解密的 s 也變成全域的。 這時候t 與 s 不會因為function結束而被釋放。理論上才會是正常的。 然後再試一下,若從此沒問題,那就很肯定是我上面講的問題! ps 全域後的名稱要換一下,不好又是s與t的,以免"打架" 以上是我另一種觀點 : ) ===================引 用 superrakce 文 章=================== 最後測試結果: 加密的字串尾巴加上隨便一個字,回傳正常; 解密碼字串刪除最後一個字,解密成功,回傳正常。 附上「部份」程式碼; 這樣子雖然功能完成了,但我很想知道發生了什麼事, 在DELPHI 內 呼叫都沒這個問題,為何到了C#去呼叫就有這個毛病,怪哉 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |