显式调用与隐式调用的问题? ( 积分: 50 )

  • 主题发起人 主题发起人 jack2004
  • 开始时间 开始时间
J

jack2004

Unregistered / Unconfirmed
GUEST, unregistred user!
分别用两种方法调用一个DLL,显式调用会出错,参数传递错误,程序如下,<br>button1:隐式调用<br>button2:显式调用<br><br>那位能指名错误呢????<br><br>调用程序如下:<br>unit&nbsp;Unit1;<br><br>interface<br><br>uses<br>&nbsp;&nbsp;Windows,&nbsp;Messages,&nbsp;SysUtils,&nbsp;Variants,&nbsp;Classes,&nbsp;Graphics,&nbsp;Controls,&nbsp;Forms,<br>&nbsp;&nbsp;Dialogs,&nbsp;ExtCtrls,&nbsp;StdCtrls;<br><br>type<br>&nbsp;&nbsp;TForm1&nbsp;=&nbsp;class(TForm)<br>&nbsp;&nbsp;&nbsp;&nbsp;Image1:&nbsp;TImage;<br>&nbsp;&nbsp;&nbsp;&nbsp;Button1:&nbsp;TButton;<br>&nbsp;&nbsp;&nbsp;&nbsp;Button2:&nbsp;TButton;<br>&nbsp;&nbsp;&nbsp;&nbsp;procedure&nbsp;Button1Click(Sender:&nbsp;TObject);<br>&nbsp;&nbsp;&nbsp;&nbsp;procedure&nbsp;Button2Click(Sender:&nbsp;TObject);<br>&nbsp;&nbsp;private<br>&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;Private&nbsp;declarations&nbsp;}<br>&nbsp;&nbsp;public<br>&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;Public&nbsp;declarations&nbsp;}<br>&nbsp;&nbsp;end;<br><br>&nbsp;&nbsp;MySetImage=&nbsp;procedure(filename:pchar;var&nbsp;ABitmap:&nbsp;Pointer);&nbsp;stdcall;<br><br>var<br>&nbsp;&nbsp;Form1:&nbsp;TForm1;<br><br>&nbsp;&nbsp;procedure&nbsp;SetImage(filename:pchar;var&nbsp;ABitmap:&nbsp;Pointer);&nbsp;stdcall;external&nbsp;'MYDLL';<br><br>implementation<br><br>{$R&nbsp;*.dfm}<br><br>procedure&nbsp;TForm1.Button1Click(Sender:&nbsp;TObject);<br>var<br>&nbsp;&nbsp;B:&nbsp;TBitmap;<br>&nbsp;&nbsp;fff:pchar;<br>begin<br>&nbsp;&nbsp;B&nbsp;:=&nbsp;TBitmap.Create;<br>&nbsp;&nbsp;FFF:=PChar('ABCD');<br>&nbsp;&nbsp;try<br>&nbsp;&nbsp;&nbsp;&nbsp;SetImage(FFF,Pointer(B));<br>&nbsp;&nbsp;&nbsp;&nbsp;Image1.Canvas.CopyRect(Rect(0,0,200,200),b.Canvas,Rect(0,0,200,200));<br>&nbsp;&nbsp;finally<br>&nbsp;&nbsp;&nbsp;&nbsp;B.Free;<br>&nbsp;&nbsp;end;<br>end;<br><br>procedure&nbsp;TForm1.Button2Click(Sender:&nbsp;TObject);<br>var<br>&nbsp;&nbsp;B:&nbsp;TBitmap;<br>&nbsp;&nbsp;fff:pchar;<br>&nbsp;&nbsp;MyProc:&nbsp;Mysetimage;<br>&nbsp;&nbsp;MyHandle:&nbsp;THandle;<br>begin<br>&nbsp;&nbsp;B&nbsp;:=&nbsp;TBitmap.Create;<br>&nbsp;&nbsp;FFF:=PChar('ABCD');<br><br>&nbsp;&nbsp;MyHandle&nbsp;:=&nbsp;LoadLibrary(PChar('MYDLL.dll'));<br>&nbsp;&nbsp;try<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;MyHandle&nbsp;&gt;&nbsp;0&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@MyProc&nbsp;:=&nbsp;GetProcAddress(MyHandle,&nbsp;'SetImage');<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;Assigned(MyProc)&nbsp;then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyProc(FFF,&nbsp;Pointer(B));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Image1.Canvas.CopyRect(Rect(0,&nbsp;0,&nbsp;200,&nbsp;200),&nbsp;b.Canvas,&nbsp;Rect(0,&nbsp;0,&nbsp;200,&nbsp;200));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;<br>&nbsp;&nbsp;&nbsp;&nbsp;end;<br>&nbsp;&nbsp;finally<br>&nbsp;&nbsp;&nbsp;&nbsp;B.Free;<br>&nbsp;&nbsp;&nbsp;&nbsp;Freelibrary(Myhandle);<br>&nbsp;&nbsp;end;<br>end;<br><br>end.<br>DLL程序如下:<br>library&nbsp;MYDLL;<br><br>uses<br>&nbsp;&nbsp;Graphics;<br><br>{$R&nbsp;*.res}<br>{$R&nbsp;../skin/New.res}<br><br>procedure&nbsp;SetImage(ResName:&nbsp;PChar;&nbsp;var&nbsp;Value:&nbsp;Pointer);<br>begin<br>&nbsp;&nbsp;TBitmap(Value).LoadFromResourceName(Hinstance,&nbsp;ResName);<br>end;<br>exports<br>&nbsp;&nbsp;SetImage;<br>begin<br>end.
 
如果你的图片放在资源里面,那么这个&nbsp;DLL&nbsp;就不需要通过接口函数来获得图像了。<br>procedure&nbsp;TForm1.Button2Click(Sender:&nbsp;TObject);<br>var<br>&nbsp;&nbsp;B:&nbsp;TBitmap;<br>&nbsp;&nbsp;MyHandle:&nbsp;THandle;<br>begin<br>&nbsp;&nbsp;B&nbsp;:=&nbsp;TBitmap.Create;<br>&nbsp;&nbsp;MyHandle&nbsp;:=&nbsp;LoadLibrary('MyDLL.DLL');<br>&nbsp;&nbsp;try<br>&nbsp;&nbsp;&nbsp;&nbsp;B.LoadFromResourceName(MyHandle,'ABCD');<br>&nbsp;&nbsp;&nbsp;&nbsp;Image1.Canvas.CopyRect(Rect(0,&nbsp;0,&nbsp;200,&nbsp;200),&nbsp;b.Canvas,&nbsp;Rect(0,&nbsp;0,&nbsp;200,&nbsp;200));<br>&nbsp;&nbsp;finally<br>&nbsp;&nbsp;&nbsp;&nbsp;B.Free;<br>&nbsp;&nbsp;&nbsp;&nbsp;Freelibrary(Myhandle);<br>&nbsp;&nbsp;end;<br>end;
 
DLL函数中将会对图片资源进行处理,然后再返回给主程序<br>上面写的只是演示一下
 
显示调用时没错,&nbsp;只是声明有错误<br>MySetImage=&nbsp;procedure(filename:pchar;var&nbsp;ABitmap:&nbsp;Pointer);&nbsp;stdcall;<br>把&nbsp;stdcall&nbsp;去掉应该就可以了
 
如果你一定要通过接口来获得图片,那就如楼上&nbsp;wzca&nbsp;兄的去改吧。<br>stdcall&nbsp;关键字改变了参数传递的顺序,去掉吧。
 
MySetImage=&nbsp;procedure(filename:pchar;var&nbsp;ABitmap:&nbsp;Pointer);&nbsp;stdcall;<br>把&nbsp;stdcall&nbsp;去掉应该就可以了&nbsp;&nbsp;<br><br>这个stdcall到底有什么用呢?
 
Calling&nbsp;conventions(调用约定)<br>在声明过程或函数时,你可以使用下面的指示字之一来指明调用约定:register、pascal、cdecl、stdcall以及safecall。<br>比如,<br>function&nbsp;MyFunction(X,&nbsp;Y:&nbsp;Real):&nbsp;Real;&nbsp;cdecl;<br>...<br>调用约定决定了参数被传递给例程的顺序,它们也影响从堆栈中删除参数、传递参数时寄存器的使用,以及错误和异常处理。默认的调用约定是register。<br>&amp;#8226;&nbsp;register&nbsp;和pascal&nbsp;调用从左到右传递参数,也就是说,最左边的参数最早被计算并传递,最右边的参数最后被计算和传递;cdecl、stdcall&nbsp;和safecall&nbsp;调用从右到左传递参数;<br>&amp;#8226;&nbsp;除了cdecl&nbsp;调用,过程和函数在返回之前从堆栈中移除参数,而使用cdecl,当调用返回时,调用者从堆栈中移除参数;<br>&amp;#8226;&nbsp;register&nbsp;调用能使用多达3&nbsp;个CPU&nbsp;寄存器传递参数,而其它调用则全部使用堆栈传递参数;<br>&amp;#8226;&nbsp;safecall&nbsp;调用实现了异常“防火墙”,在Windows&nbsp;下,它实现了进程间COM&nbsp;错误通知。<br>下面的表格对调用约定进行了总结:<br>指示字 参数顺序 Clean-up 使用寄存器传递参数?<br>register Left-to-right Routine Yes<br>pascal Left-to-right Routine No<br>cdecl Right-to-left Caller No<br>stdcall Right-to-left Routine No<br>safecall Right-to-left Routine No<br>默认的register&nbsp;调用是最有效的,因为它通常避免了要创建堆栈结构(stack&nbsp;frame)(访问公布属性的方法必须使用register);当调用来自C/C++编写的共享库中的函数时,cdecl&nbsp;是有用的;通常,当调用外部代码时,推荐使用stdcall&nbsp;和safecall。在Windows&nbsp;中,系统API&nbsp;使用stdcall&nbsp;和safecall,其它操作系统通常使用cdecl(注意,stdcall&nbsp;比cdecl&nbsp;更有效)。<br>声明双重接口的方法必须使用safecall;保留pascal&nbsp;调用是为了向后兼容性。要了解更多的调用约定的信息,请参考Program&nbsp;control。<br>指示字near、far&nbsp;和export&nbsp;用在16&nbsp;位Windows&nbsp;编程中,它们对32&nbsp;位程序没有影响,保留它们是为了向后兼容性。
 
多人接受答案了。
 
后退
顶部