欢迎讨论,调用函数的问题(50分)

  • 主题发起人 主题发起人 qiubole
  • 开始时间 开始时间
Q

qiubole

Unregistered / Unconfirmed
GUEST, unregistred user!
现有一个dll文件,提供若干函数<br>比如<br>&nbsp; &nbsp; procedure proc1;<br>&nbsp; &nbsp; procedure proc2(count:integer);<br>&nbsp; &nbsp;........<br>现在在主程序中调用,但我想通过ini文件作为一个中间件<br><br>&nbsp; &nbsp; 即我在ini文件里这样写<br>&nbsp; &nbsp; proc1;<br>&nbsp; &nbsp; proc2(12);<br><br>最后我在主程序中通过调用ini文件里的内容来决定调用dll里的函数<br><br>我初期的构想如下,用一个解释器,分解ini文件里的内容,最后在解释器里调用;但我发现异常的烦琐<br>因为有参数,所以通过 getprocaddress(name,inistring);也不好用<br><br>最后我想,能不能利用方法名重载,于是这样,定义一个类,原型如下;<br>SelectProcedure=class<br>&nbsp; public<br>&nbsp; &nbsp; procedure proc1;overload;virtual;<br>&nbsp; &nbsp; procedure proc1(count:integer);overload;virtual;<br>&nbsp; &nbsp; procedure proc1(str:string);overload;virtual;<br>&nbsp; &nbsp; 。。。。。。。。。。。。<br>&nbsp; end;<br><br>在使用的时候]<br>var<br>&nbsp; myclass:SelectProcedure;<br>&nbsp; t:thandle;<br>begin<br>&nbsp; try<br>&nbsp; &nbsp; t:=loadlibrary('my.dll');<br>&nbsp; &nbsp; myclass:=SelectProcedure.Create;<br>&nbsp; &nbsp; @(myclass.proc1):=getprocaddress(t,从ini里读的函数名);//但在此句出错,呵呵,看样子是行不通<br>&nbsp; &nbsp; myclass.proc1(从ini里读的参数);<br>&nbsp; finally <br>&nbsp; &nbsp; freelibrary(t);<br>&nbsp; &nbsp; myclass.Free;<br>&nbsp; end;<br>end;<br><br>请问各位,难道除了用解释器,还有没有别的好办法
 
&gt;&gt;getprocaddress(t,从ini里读的函数名);<br>这里的函数名后不能包含参数哦
 
to lha;不包含参数的东东太简单了<br><br>&nbsp; &nbsp;现在就是说要包含参数;
 
如果参数类型是简单类型即string, Integer, Float等都好办<br>若是其他就没招了吧?<br>我想可以这样:<br>统一参数入口为: TFunc = function(ArgType, Arg: Longint): LongInt;<br>ArgType表示传入的参数的类型,Arg表示参数的地址,在函数中你就可以根据类型来<br>用不同的方法取得参数的值。你调用的时候就统一了。<br>我也是随便想的,没实践过,你可以参考一下API: SendMessage,PostMessge等的做法。
 
大哥方法是好,但是,我的参数是从ini文件里面读的,何来地址?<br><br>最好是用一个@proc=getprocaddress就好了,但这个proc的类型很关键呀
 
我的意思就是:<br>var<br>&nbsp; proc: TFunc;<br>&nbsp; FuncName: string;<br>&nbsp; ArgType, Arg: string;<br>begin<br>&nbsp; FuncName := GetFuncNameFromIni;<br>&nbsp; @proc := GetProcAddress(H, FuncName);<br>&nbsp; ArgType := GetArgTypeByFuncName(FuncName);<br>&nbsp; Arg := GetArgByFuncName(FuncName);<br>&nbsp; if ArgType = 'STRING' then<br>&nbsp; &nbsp; Proc(ArgType, LongInt(@Arg[1]));<br>&nbsp; if ArgType = 'INT' then<br>&nbsp; &nbsp; Proc(ArgType, LongInt(StrToInt(Arg)));<br>&nbsp; ....<br>end;
 
to xianjun<br>如果是这样,你的TFunc为什么类型<br><br>你的GetArgTypeByFuncName 这个函数是自定义的?<br>如果有多个参数该怎么办?
 
另外,我有个想法,如果在dll中用variant类型,将多个参数封装,但我调试发现不行
 
TFunc = function(ArgType, Arg: Longint): LongInt;<br>我这就设了一个参数,当然你也可以加多一个,至于说多个参数,这完全没有问题<br>因为你可以把几个参数封装成一个再传进去的,这就是ArgType的作用,相当于两者<br>间交流的协议吧。我是从SendMessage函数想到的。<br>GetFuncNameFromIni, GetArgTypeByFuncName,GetArgByFuncName都是自定义的<br>目的是从INI文件中取出相应的东西。<br>这些都是我顺手写下来的,没有经过试验,但想来问题不大。
 
to xianjun<br>&nbsp; &nbsp; 你的意思我还是没有明白<br>&nbsp;在你的getargtypebyfuncname里,你的返回值为一种单一的类型,如果我将'123',123封装,那成什么类型了<br><br>何况调用@proc的时候,本身就是根据实际参数,也就是你所定义的参数的个数而定的,它并不是读取某一个缓冲区的内容<br>呵呵<br>我得好好想想,理会一下你的意思
 
to qiubole:<br>&gt;&gt;不包含参数的东东太简单了<br>你的意思我还是不太明白, 是我不懂DLL 还是没有看懂需求!?<br>调用过程当然可以包含参数啦!
 
晚上我试试能不能写个DEMO出来。
 
to lha;<br>&nbsp; &nbsp;呵呵,没有参数,就可以用你那种方法啦,所以我说简单。<br><br>to xianjun<br>&nbsp; &nbsp;真是麻烦你了;先谢过
 
简单例子如下:<br>[blue]DLL中:[/blue]<br>type<br>&nbsp; TTestRec = record<br>&nbsp; &nbsp; A, B: Word;<br>&nbsp; end;<br><br>function TestProc(AArgType, AArg: Longint): Longint; stdcall;<br><br>implementation<br>{$R *.DFM}<br><br>function TestProc(AArgType, AArg: Longint): Longint;<br>var<br>&nbsp; S: string;<br>&nbsp; F: Single;<br>begin<br>&nbsp; Result := 0;<br>&nbsp; case AArgType of<br>&nbsp; &nbsp; 0:<br>&nbsp; &nbsp; &nbsp; Result := TTestRec(AArg).A * TTestRec(AArg).B;<br>&nbsp; &nbsp; 1:<br>&nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; S := 'OH! my god! ' + PChar(AArg);<br>&nbsp; &nbsp; &nbsp; &nbsp; Result := Longint(@S[1]);<br>&nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; 2:<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; F := Single(Pointer(AArg)^) * 0.5;<br>&nbsp; &nbsp; &nbsp; Result := LongInt(@F);<br>&nbsp; &nbsp; end;<br>&nbsp; end;<br>end;<br>导出:<br>exports<br>&nbsp; TestProc;<br><br>[blue]调用程序:[/blue]<br>&nbsp; TTestRec = record<br>&nbsp; &nbsp; A, B: Word;<br>&nbsp; end;<br>&nbsp; TTestProc = function(AArgType, AArg: Longint): Longint; stdcall;<br><br>var<br>&nbsp; LibHandle: THandle;<br>&nbsp; Proc: TTestProc;<br>&nbsp; A: TTestRec;<br>&nbsp; S: string;<br>&nbsp; F: Single;<br>&nbsp; R: LongInt;<br>&nbsp; ArgType, FuncName: string;<br>begin<br>&nbsp; LibHandle := LoadLibrary('TESTDLL.DLL');<br>&nbsp; if LibHandle = 0 then<br>&nbsp; &nbsp; raise Exception.Create('Unable to Load DLL');<br>&nbsp; try<br>&nbsp; &nbsp; ArgType := Edit1.Text; //输入参数类型,调用者与DLL编写者约定<br>&nbsp; &nbsp; FuncName := 'TestProc';<br>&nbsp; &nbsp; @Proc := GetProcAddress(LibHandle, PChar(FuncName));<br>&nbsp; &nbsp; if not (@Proc = nil) then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; if ArgType = '0' then //0时传入的是TTestRec的记录类型<br>&nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; A.A := 10;<br>&nbsp; &nbsp; &nbsp; &nbsp; A.B := 20;<br>&nbsp; &nbsp; &nbsp; &nbsp; Edit2.Text := IntToStr(Proc(0, Longint(A)));<br>&nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; if ArgType = '1' then //1为字符串类型<br>&nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; S := 'This is Test string';<br>&nbsp; &nbsp; &nbsp; &nbsp; R := Proc(1, LongInt(@S[1]));<br>&nbsp; &nbsp; &nbsp; &nbsp; Edit2.Text := PChar(R);<br>&nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; if ArgType = '2' then //2为Single<br>&nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; F := 3.14;<br>&nbsp; &nbsp; &nbsp; &nbsp; R := Proc(2, LongInt(@F));<br>&nbsp; &nbsp; &nbsp; &nbsp; Edit2.Text := FloatToStr(Single(Pointer(R)^));<br>&nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; end;<br>&nbsp; finally<br>&nbsp; &nbsp; FreeLibrary(LibHandle);<br>&nbsp; end;<br><br>D6 + Win2K 测试通过。
 
自定义类型 &nbsp;<br>TTestRec = record<br>&nbsp; &nbsp; A, B: Word;<br>&nbsp; end;<br>在两边都要声明,因此你可以把它写在一个INC文件内,然后两边引用就行了:<br>{$I MyTypes.inc}<br>
 
谢谢了,老大
 
接受答案了.
 
to qiubole:<br>&gt;&gt; 呵呵,没有参数,就可以用你那种方法啦,所以我说简单。<br>当然可以有参数呀! 如你还这样认为 我无话可说! <br>
 
to lha<br><br>&nbsp; &nbsp; 你做个参数不确定,而且类型不同的试试看
 
呵呵 那就用COM了
 
后退
顶部