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

dll 如何傳回多筆資料?

答題得分者是:jimmy_wei
wenjung
一般會員


發表:21
回覆:61
積分:21
註冊:2002-04-29

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-09-03 12:03:15 IP:210.71.xxx.xxx 未訂閱
因最近系統要模組化,故被要求要將某些常用程式改成dll ,以利系統開發, 但是在轉寫的過程中,遇到需要一次傳回多筆資料,我就把傳回的資料型態設為 TStrings ,但在執行時卻產生錯誤,請問個位大大,是否有其他方式可以解決 ??
william
版主


發表:66
回覆:2535
積分:3048
註冊:2002-07-11

發送簡訊給我
#2 引用回覆 回覆 發表時間:2003-09-03 12:19:24 IP:147.8.xxx.xxx 未訂閱
error message? Try to use ShareMem as the very first unit in both your host application and dll.
wenjung
一般會員


發表:21
回覆:61
積分:21
註冊:2002-04-29

發送簡訊給我
#3 引用回覆 回覆 發表時間:2003-09-03 12:58:34 IP:210.71.xxx.xxx 未訂閱
How to use ShareMem ??
william
版主


發表:66
回覆:2535
積分:3048
註冊:2002-07-11

發送簡訊給我
#4 引用回覆 回覆 發表時間:2003-09-03 13:33:20 IP:147.8.xxx.xxx 未訂閱
program Project1;    uses   ShareMem, {....}
wenjung
一般會員


發表:21
回覆:61
積分:21
註冊:2002-04-29

發送簡訊給我
#5 引用回覆 回覆 發表時間:2003-09-03 14:15:13 IP:210.71.xxx.xxx 未訂閱
could you give me some case ..
william
版主


發表:66
回覆:2535
積分:3048
註冊:2002-07-11

發送簡訊給我
#6 引用回覆 回覆 發表時間:2003-09-03 14:26:17 IP:147.8.xxx.xxx 未訂閱
Quoted from Delphi help: Shared-memory manager (Windows only) On Windows, if a DLL exports routines that pass long strings or dynamic arrays as parameters or function results (whether directly or nested in records or objects), then the DLL and its client applications (or DLLs) must all use the ShareMem unit. The same is true if one application or DLL allocates memory with New or GetMem which is deallocated by a call to Dispose or FreeMem in another module. ShareMem should always be the first unit listed in any program or library uses clause where it occurs. ShareMem is the interface unit for the BORLANDMM.DLL memory manager, which allows modules to share dynamically allocated memory. BORLANDMM.DLL must be deployed with applications and DLLs that use ShareMem. When an application or DLL uses ShareMem, its memory manager is replaced by the memory manager in BORLANDMM.DLL. Note Linux uses glibc's malloc to manage shared memory. ============================ Just use the unit, no need for extra code.
jimmy_wei
高階會員


發表:9
回覆:176
積分:147
註冊:2003-08-28

發送簡訊給我
#7 引用回覆 回覆 發表時間:2003-09-03 18:36:26 IP:61.220.xxx.xxx 未訂閱
宣告成var 就可以了呀.... 測試ok 這是測試程式裡的程式碼 procedure ResultSList(var sList: TStringList); stdcall; external 'DllTest.dll'; procedure TForm1.Button2Click(Sender: TObject); var ssList: TStringList; begin ssList:= TStringList.Create; try ResultSList(ssList); Memo1.Lines.Text:= ssList.Text; finally ssList.Free; end; end; 這是dll裡的程式碼 procedure ResultSList(var sList: TStringList); stdcall; procedure ResultSList(var sList: TStringList); stdcall; begin sList.Add('aaa'); sList.Add('bbb'); sList.Add('ccc'); end; 這樣應該可以解你的問題吧....我想
wenjung
一般會員


發表:21
回覆:61
積分:21
註冊:2002-04-29

發送簡訊給我
#8 引用回覆 回覆 發表時間:2003-09-04 13:20:33 IP:210.71.xxx.xxx 未訂閱
我連續按下Button兩次,卻會產生錯誤訊息如下    Access violation at address 004021BE in module 'Project1.exe'. Write of address 0000002A    不知該如何處理啊 
jimmy_wei
高階會員


發表:9
回覆:176
積分:147
註冊:2003-08-28

發送簡訊給我
#9 引用回覆 回覆 發表時間:2003-09-04 16:04:52 IP:61.220.xxx.xxx 未訂閱
引敍... 我連續按下Button兩次,卻會產生錯誤訊息如下 =========================================== 你是說的給你的範例嗎??
wenjung
一般會員


發表:21
回覆:61
積分:21
註冊:2002-04-29

發送簡訊給我
#10 引用回覆 回覆 發表時間:2003-09-05 08:34:33 IP:210.71.xxx.xxx 未訂閱
抱歉我所指的是我的程式,如下: // dll Procedure Getcode(Var sList:TStringList;sTablename,sFieldList,sWhere:String);export; Procedure Getcode(Var sList:TStringList;sTablename,sFieldList,sWhere:String); Var Qry : TQuery ; db : TDatabase; temp_sql : String; begin getini ; IF Trim(wsini.databasename) = '' Then Showmessage('DataBase Name 尚未設定 !!') Else Begin db := TDatabase.Create(nil); db.AliasName := wsini.aliasname ; db.DatabaseName := wsini.databasename ; db.Params.Add('USER NAME=' wsini.user ); db.Params.Add('PASSWORD=' wsini.passwd ); db.LoginPrompt := False; db.Connected := True; Qry := TQuery.Create(nil); Qry.DatabaseName := wsini.databasename; temp_sql := 'Select ' sFieldList ' From ' sTablename ' ' sWhere; TComboBox(Sender).Items.Clear; With Qry Do Begin Try SQL.Clear ; Close; SQL.Add(temp_sql); Open ; While Not Eof Do Begin sList.Add(Fields[0].AsString '-' Fields[1].AsString ); Next; End; Except On E: Exception Do Begin Clipboard.AsText := temp_sql; Showmessage(E.Message); End; End; Free; db.Free; End; End; end; // procedure Getcode(Var sList:TStringList;sTablename,sFieldList,sWhere:String); external 'DllTest.dll'; procedure TForm1.Button2Click(Sender: TObject); var ssList: TStringList; begin ssList:= TStringList.Create; try Getcode(ssList,'seccod','code,codedsc',''); Memo1.Lines.Text:= ssList.Text; finally ssList.Free; end; end;
jimmy_wei
高階會員


發表:9
回覆:176
積分:147
註冊:2003-08-28

發送簡訊給我
#11 引用回覆 回覆 發表時間:2003-09-05 12:04:05 IP:61.220.xxx.xxx 未訂閱
你的程式我有實際去測,真的會出錯耶,我將它改寫成一般的function 當然程式做了少部份的修改(db,qry只create一次),就不會錯了,但 是我又改寫成dll時又出現令一個錯,我直接改成由外部傳入query 不動態create錯誤依然存在,這個部份可能我有時間再幫你try,先看看 別人有沒有解吧,不過dll傳多筆的問題,應該是ok的對吧!!
william
版主


發表:66
回覆:2535
積分:3048
註冊:2002-07-11

發送簡訊給我
#12 引用回覆 回覆 發表時間:2003-09-05 12:25:33 IP:147.8.xxx.xxx 未訂閱
引言: 你的程式我有實際去測,真的會出錯耶,我將它改寫成一般的function 當然程式做了少部份的修改(db,qry只create一次),就不會錯了,但 是我又改寫成dll時又出現令一個錯,我直接改成由外部傳入query 不動態create錯誤依然存在,這個部份可能我有時間再幫你try,先看看 別人有沒有解吧,不過dll傳多筆的問題,應該是ok的對吧!!
Need to use ShareMem or other memory manager in the dll and your host application...
wenjung
一般會員


發表:21
回覆:61
積分:21
註冊:2002-04-29

發送簡訊給我
#13 引用回覆 回覆 發表時間:2003-09-05 13:53:49 IP:210.71.xxx.xxx 未訂閱
i am use ShareMem but have error message:    Access violation at address 00401D94 in module 'Project1.exe'. Write of address 00000008    
william
版主


發表:66
回覆:2535
積分:3048
註冊:2002-07-11

發送簡訊給我
#14 引用回覆 回覆 發表時間:2003-09-05 14:02:11 IP:147.8.xxx.xxx 未訂閱
In your dll code.. TComboBox(Sender).Items.Clear; Sender? It may be the problem.
wenjung
一般會員


發表:21
回覆:61
積分:21
註冊:2002-04-29

發送簡訊給我
#15 引用回覆 回覆 發表時間:2003-09-05 14:17:13 IP:210.71.xxx.xxx 未訂閱
sorry ! i am try sender TComboBox to dll is ok!  but use TstringList have error message 
william
版主


發表:66
回覆:2535
積分:3048
註冊:2002-07-11

發送簡訊給我
#16 引用回覆 回覆 發表時間:2003-09-05 14:27:22 IP:147.8.xxx.xxx 未訂閱
引言: sorry ! i am try sender TComboBox to dll is ok! but use TstringList have error message < face="Verdana, Arial, Helvetica"> Sender in dll set elsewhere? Anyway I think it would help if you could debug your dll: 1) open your dll project 2) set Project Options|Compiler properly for debug (e.g. Stack frames, no Optimization, check all Debugging except Use Debug DCUs) 3) In Run|Parameters|Local|Host Application set it to your Project1.exe 4) rebuild the project and run BTW, usually stdcall would be used in dll applications.
wenjung
一般會員


發表:21
回覆:61
積分:21
註冊:2002-04-29

發送簡訊給我
#17 引用回覆 回覆 發表時間:2003-09-05 15:16:37 IP:210.71.xxx.xxx 未訂閱
// dll Procedure Getcode(Var sList:TStringList;sTablename,sFieldList,sWhere:String);export; Procedure Getcode(Var sList:TStringList;sTablename,sFieldList,sWhere:String); Var Qry : TQuery ; db : TDatabase; temp_sql : String; begin getini ; IF Trim(wsini.databasename) = '' Then Showmessage('DataBase Name 尚未設定 !!') Else Begin db := TDatabase.Create(nil); db.AliasName := wsini.aliasname ; db.DatabaseName := wsini.databasename ; db.Params.Add('USER NAME=' wsini.user ); db.Params.Add('PASSWORD=' wsini.passwd ); db.LoginPrompt := False; db.Connected := True; Qry := TQuery.Create(nil); Qry.DatabaseName := wsini.databasename; temp_sql := 'Select ' sFieldList ' From ' sTablename ' ' sWhere; With Qry Do Begin Try SQL.Clear ; Close; SQL.Add(temp_sql); Open ; While Not Eof Do Begin sList.Add(Fields[0].AsString '-' Fields[1].AsString ); // error message raise from this . Next; End; Except On E: Exception Do Begin Clipboard.AsText := temp_sql; Showmessage(E.Message); End; End; Free; db.Free; End; End; end;
jimmy_wei
高階會員


發表:9
回覆:176
積分:147
註冊:2003-08-28

發送簡訊給我
#18 引用回覆 回覆 發表時間:2003-09-05 15:36:55 IP:61.220.xxx.xxx 未訂閱
解了 你要把ShareMem 宣告在.dpr裡的第一個喔..... 不是在unit ex:在exe裡 program Project2; uses ShareMem, Forms, Unit1 in 'Unit1.pas' {Form1}, UJimmyCode in 'UJimmyCode.pas', Trans in 'Trans.pas', UTrans_KID in 'UTrans_KID.pas', Unit4 in 'Unit4.pas'; {$R *.RES} begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end. 在.dll裡 library DllTest; { 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. } uses ShareMem, SysUtils, Classes, Unit3 in 'Unit3.pas', UJimmyCode in 'UJimmyCode.pas', Unit4 in 'Unit4.pas'; {$R *.RES} begin end.
jimmy_wei
高階會員


發表:9
回覆:176
積分:147
註冊:2003-08-28

發送簡訊給我
#19 引用回覆 回覆 發表時間:2003-09-05 15:45:09 IP:61.220.xxx.xxx 未訂閱
其實在深度論壇裡已經有很多人討論過DLL回傳TStringList這個問題了 你可以去看看喔那裡面之前也是非常熱列的討論過喔,你可以去看看 以下是網址:(參考看看吧,那裡也很詳細喔,help裡也有說) http://forum.vclxx.org/topic.php?TOPIC_ID=18391&FORUM_ID=5&CAT_ID=2&Topic_Title=DLL¥i§_¶Ǧ^ TStringList©ÎTStringSªº¸ê®Æ&Forum_Title=Database
wenjung
一般會員


發表:21
回覆:61
積分:21
註冊:2002-04-29

發送簡訊給我
#20 引用回覆 回覆 發表時間:2003-09-05 16:49:25 IP:210.71.xxx.xxx 未訂閱
我試過了,執行第三次錯誤訊息就會產生了 
jimmy_wei
高階會員


發表:9
回覆:176
積分:147
註冊:2003-08-28

發送簡訊給我
#21 引用回覆 回覆 發表時間:2003-09-05 17:10:02 IP:61.220.xxx.xxx 未訂閱
程式給你好了.... 怎麼測都是ok的喔....沒有錯誤訊息 你有沒有把sharemem放在第一個use呀?? 這樣應該可以了吧,特地還寫了跟你function一樣名字的範例溜 exe: program Project2; uses ShareMem, Forms, Unit1 in 'Unit1.pas' {Form1}; {$R *.RES} begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end. unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Grids, DBGrids, Db, DBTables; procedure GetCode(sList: TStringList ;sTablename,sFieldList,sWhere:String); stdcall; external 'DllTest.dll'; type TForm1 = class(TForm) Button3: TButton; Memo1: TMemo; Button4: TButton; Query1: TQuery; Database1: TDatabase; procedure Button3Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} { TForm1 } procedure TForm1.Button3Click(Sender: TObject); var sList: TStringList; iLib: Integer; begin sList:= TStringList.Create; try GetCode(sList, 'ANIMALS', 'NAME, AREA', 'WHERE AREA LIKE ''S%'''); Memo1.Lines.Text:= sList.Text; finally sList.Free; end; end; end. dll: library DllTest; { 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. } uses ShareMem, SysUtils, Classes, Unit4 in 'Unit4.pas'; {$R *.RES} begin end. unit Unit4; interface uses Dialogs, Sysutils, Windows, Classes, Dbtables; procedure GetCode(sList: TStringList; sTablename,sFieldList,sWhere:String); stdcall; procedure ConnectDB; stdcall; procedure DisConnectDB; stdcall; exports GetCode, ConnectDB, DisConnectDB; implementation var Qry : TQuery ; db : TDatabase; procedure DisConnectDB; begin Qry.Close; Qry.Free; db.Connected:= False; db.Destroy; db:= nil; end; procedure ConnectDB; begin db := TDatabase.Create(nil); Qry := TQuery.Create(nil); try db.AliasName := 'DBDEMOS' ; db.DatabaseName := 'aDBDEMOS'; // db.Params.Add('USER NAME=' wsini.user ); // db.Params.Add('PASSWORD=' wsini.passwd ); // db.LoginPrompt := False; db.Connected := True; Qry.DatabaseName := 'aDBDEMOS'; finally // if db.Connected then // ShowMessage('連線成功'); end; end; procedure GetCode(sList: TStringList; sTablename,sFieldList,sWhere:String); var temp_sql : String; begin //getini ; // if Trim(wsini.databasename) = '' Then //Showmessage('DataBase Name 尚未設定 !!') //Else Begin if db = nil then ConnectDB; temp_sql := 'Select ' sFieldList ' From ' sTablename ' ' sWhere; try With Qry Do Begin Try SQL.Clear ; Close; SQL.Text:= temp_sql; Open ; While Not Eof Do Begin sList.Add(Fields[0].AsString '-' Fields[1].AsString ); Next; End; Close; Except On E: Exception Do Begin // Clipboard.AsText := temp_sql; Showmessage(E.Message); End; End; end; finally DisConnectDB; end; end; end.
wenjung
一般會員


發表:21
回覆:61
積分:21
註冊:2002-04-29

發送簡訊給我
#22 引用回覆 回覆 發表時間:2003-09-05 17:23:25 IP:210.71.xxx.xxx 未訂閱
漂亮 !  ok 溜 小弟在此感謝william 版主及jimmy_wei兄的鼎力幫忙 
系統時間:2024-05-08 14:10:26
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!