突发奇想 不知delphi能否做到(100分)

  • 主题发起人 主题发起人 52253831
  • 开始时间 开始时间
5

52253831

Unregistered / Unconfirmed
GUEST, unregistred user!
[red]一个EXE调用一个DLL。如何让这个DLL在EXE的窗体上创建一些对象(比如edit,button)等。而这些对象的事件要在DLL内启动。[/red]
 
这有什么难处呢,没用是真的
 
试了一下,直接传对象肯定是不行的,
传指针好象不行哦。

下面是传指针的代码,不知那里有问题。

DLL单元如下
procedure cButton(xPanel:pointer);
Var
rButton : TPanel;
begin
rButton :=TPanel.Create(xPanel);
rButton.top :=1;
rButton.Left :=1;
rButton.Height :=20;
rButton.Width :=20;
rButton.Parent :=xPanel;
end;
end;
EXE单元
Moudle:=loadlibrary(pchar('demo.dll'));
xButton :=GetProcAddress(Moudle,'cButton');
xButton(panel1);
 
呵呵,自己搞清楚了。
思路很正确。就是用传指针就行了。现在可以在DLL中动态在EXE的表单里添加控件罗。
 
又有问题了。没法响应事件啊。
DLL单元加了
rButton.OnClick:=ButtonRClick;

procedure ButtonRClick(Sender: TObject);
begin
TPanel(Sender).Caption :='OK';
end;

怎么不行哦?
 
忽然发现你这想法确实实是很有创意
creattion-zy对绑定控件的事件和代码肯定能给你答案
关注你的研究
 
我在主窗体中动态创建的按钮,按钮的单击事件是BtnClick(Sender: TObject)如下:
procedure fmain.BtnClick(Sender: TObject);
begin
if fmain.suiBtnFlag.Caption='销售'+#13+'管理' then
OpenForm(MDIChildForm1);//打开窗体的一个方法
else if fmain.suiBtnFlag.Caption='客户'+#13+'管理' then
OpenForm(MDIChildForm2);
//(注意:问题就出在这里MDIChildForm1和MDIChildForm2是两个不同dll里的两个窗体。fmain是主窗体,它是exe文件里的主窗体。我在exe的主窗体里调用dll里的MDIChildForm1,这时候就要uses单元文件,而我的单元文件是在dll程序里,我不可能uses它。反过来,我要在dll里使用exe里的文件也要uses。这个问题怎么解决?)
end;
 
我现在正想解决这问题呢,大哥,你太有才了,把我正遇到的问题都说出来了。
 
找到该窗口的句柄就可以了
以QQ登录窗口为例

implementation
var
OldBtnProc: Pointer;
QQWindow,BtnExit: HWND;
{$R *.dfm}
function ButtonProc(hwnd: HWND; Msg: UINT;wparam: WPARAM;lparam:
LPARAM):LRESULT;Stdcall;
begin
if Msg = WM_LBUTTONDOWN then
begin
SendMessage(QQWindow,WM_SYSCOMMAND,SC_CLOSE,0);
Result:= 0;
end
else
Result:= CallWindowProc(OldBtnProc,hwnd,Msg,wparam,lparam);
end;
procedure TForm1.Button1Click(Sender: TObject);

begin
QQWindow:= FindWindow(nil,'QQ用户登录');
if QQWindow = 0 then exit;
BtnExit:= CreateWindow('Button','退出',WS_VISIBLE or WS_CHILD or
BS_PUSHBUTTON,10,10,80,50,
QQWindow,1,GetWindowLong(QQWindow,GWL_HINSTANCE),nil);
Windows.SetParent(BtnExit,QQWindow);
OldBtnProc:=
Pointer(SetWindowLong(BtnExit,GWL_WNDPROC,Longint(@ButtonProc)));
end;
 
两种方法,转型,接口
使用转型,参数类型定义为TForm,或TFormClass,运行时它是子类没关系,我们只用它的公有方法
使用接口,就是做一个公用单元,从IInterface或其派生接口继承得到一个新接口,DLL和EXE中同时引用
 
可以的,你可以传入form给dll里的owner
 
我不知道这个想法有什么用。

起初只是因原来写了个程序,后来想加个功能上去,懒得看代码了。这段时间正研究DLL所以想能否用DLL做个补丁loadlibrary进去省事。

xxhadsg 大大用API是可以的。并且兼容性也好。是一种办法,但可控性可能不太好。


但我现在不明白的是定义事件时候
rButton.OnClick:=ButtonRClick;

procedure ButtonRClick(Sender: TObject);
begin
TPanel(Sender).Caption :='OK';
end;
这里为什么不行呢?
如果在FORM里就可以,但在DLL里就不行,两者有什么不同吗?
DLL中动态创建了对象他的事件入口该如何定义呢?
继续研究

呵呵,我只是一个DELPHI小菜鸟。不耻下问是我的学习风格。
 
可以将DLL里的FORM调用后到EXE的MDI里工作,从而感觉与主程序完整性。
对大型的系统可以采用这一方法,因为需要有统一标准规划才行。
 
你要在现有的项目上加的话可以在Dll中创建没有边框的窗体,然后把Handle传递出来,主窗体把这个窗体的Parent设为主程序中一个Panel,然后最大化。

不过改变大小的时候要注意一下dll中的窗体,设置其大小...
 
rButton.OnClick:=ButtonRClick; [red]//////////这里这样写有何不对吗?为何编译不能通过。[/red] end;

OnClick需要一个 tobject 对象方法.
 
delphi天堂交流群:4654765
 
Alucard 的办法也是可行的,但得解决输入焦点问题。切换输入焦点时还得处理一下。
比如用TAB键应该DLL的对象应该是没法得到焦点的。
 
关于此问题增加难度
请到http://www.delphibbs.com/delphibbs/dispq.asp?lid=3893760
做进一步深入探讨,回答正确我再加分
*****************以下是深入探讨的问题**********************
主窗体main.pas:
function SetModualRight(MainForm:TForm;const UserNO,ADept: string;ARow,ACol: Integer;AParent: TWincontrol;suiFileTheme1:TsuiFileTheme;adoBtn,temp: TADOQuery):Integer;stdcall;
external 'D:/MyDoc/Sell/system/SysUnit.dll';

主窗体按钮单击事件(调用SysUnit.dll动态的创建好多按钮)
SetModualRight(Fmain,g_UserNO,'XS',3,5,pnl1,suiFileTheme1,fDM.adoBtn,fDM.temp);
——————————————————————————————————————————
所有动态库里的公用单元文件Base_Base.pas:
function SetModualRight(MainForm:TForm;const UserNO,ADept: string;ARow,ACol: Integer;
AParent: TWincontrol;suiFileTheme1:TsuiFileTheme;adoBtn,temp: TADOQuery):Integer;stdcall;
begin
......此处省略代码(这部分代码就是用循环语句创建的很多按钮)...........................
btn[i,j]:= TButton.Create(TPanel(AParent));
btn[i,j].parent:= AParent;
{注意:所有的按钮都在主窗体(main.pas)的不同的Panel上(每个模块一个小Panel,所有的小Panel都在同一个大Panel上)}
btn[i,j].OnClick:=fBase_Base.BtnClick; //注意:问题就在这里
......此处省略代码(这部分代码就是用循环语句创建的很多按钮)...........................
end;

procedure fBase_Base.BtnClick(Sender: TObject这里还要一些这样参数,才能识别是哪个模块,但是参数怎么传递呢?还要和动态创建的按钮的OnClick兼容);
begin
showmessag('你好')
end;
——————————————————————————————————
sys模块的SysUnit.dll里的一个单元文件sysunit.pas
procedure sysdll(这里的参数怎么写,怎么去传递呢?);
begin
if 动态创建的按钮.Caption='AA' then
打开窗体AA
else if 动态创建的按钮.Caption='BB' then
打开窗体BB;
end;
-----------------------------
xt模块xtUnit.dll里的一个单元文件xtUnit.pas
procedure xtdll(这里的参数怎么写,怎么去传递呢?);
begin
if 动态创建的按钮.Caption='CC' then
打开窗体CC
else if 动态创建的按钮.Caption='DD' then
打开窗体DD;
end;
-------------------------------------------------------------

procedure TfrmMain.OnCustomMenuCall(Sender: TObject);
var
aCMI : TCustomMenuItem;
cfa : TfrmDynaCustomQuery;
fci : TFormClassItem;
begin
aCMI := GBaseSysSetting.CustomMenuMgr.GetItem(Sender);
fci := FormClassMgrUnit.GFormClassMgr.GetItemByAliasName(aCMI.FormType);
if fci = nil then exit;
cfa := TfrmDynaCustomQuery(CallChildForm(Sender, fci.FormClass.ClassName));
cfa.CallAfterShow;
end;

----------------------------------------------------------------
总结:
现在按钮是能看到了,按道理说我在主窗体里单击我动态创建的按钮时,应该会有不同的窗体被打开才对,
但是现在什么都没有弹出来啊。为什么?不知道是我的思路不对还是缺少什么东西?应该怎么写才好?
 
上面的写错了,应该是这样的
************************************************
主窗体main.pas:
function SetModualRight(MainForm:TForm;const UserNO,ADept: string;ARow,ACol: Integer;AParent: TWincontrol;suiFileTheme1:TsuiFileTheme;adoBtn,temp: TADOQuery):Integer;stdcall;
external 'D:/MyDoc/Sell/system/SysUnit.dll';

主窗体按钮单击事件(调用SysUnit.dll动态的创建好多按钮)
SetModualRight(Fmain,g_UserNO,'XS',3,5,pnl1,suiFileTheme1,fDM.adoBtn,fDM.temp);
——————————————————————————————————————————
所有动态库里的公用单元文件Base_Base.pas:
function SetModualRight(MainForm:TForm;const UserNO,ADept: string;ARow,ACol: Integer;
AParent: TWincontrol;suiFileTheme1:TsuiFileTheme;adoBtn,temp: TADOQuery):Integer;stdcall;
begin
......此处省略代码(这部分代码就是用循环语句创建的很多按钮)...........................
btn[i,j]:= TButton.Create(TPanel(AParent));
btn[i,j].parent:= AParent;
{注意:所有的按钮都在主窗体(main.pas)的不同的Panel上(每个模块一个小Panel,所有的小Panel都在同一个大Panel上)}
btn[i,j].OnClick:=fBase_Base.BtnClick; //注意:问题就在这里
......此处省略代码(这部分代码就是用循环语句创建的很多按钮)...........................
end;

procedure fBase_Base.BtnClick(Sender: TObject这里还要一些这样参数,才能识别是哪个模块,但是参数怎么传递呢?还要和动态创建的按钮的OnClick兼容);
begin
if sys模块 then
sysdll()//在sysUnit.dll单元文件里的一个方法
else if xt模块 then
xtdll();//在xtUnit.dll单元文件里的一个方法
end;
——————————————————————————————————
sys模块的SysUnit.dll里的一个单元文件sysunit.pas
procedure sysdll(这里的参数怎么写,怎么去传递呢?);
begin
if 动态创建的按钮.Caption='AA' then
打开窗体AA
else if 动态创建的按钮.Caption='BB' then
打开窗体BB;
end;
-----------------------------
xt模块xtUnit.dll里的一个单元文件xtUnit.pas
procedure xtdll(这里的参数怎么写,怎么去传递呢?);
begin
if 动态创建的按钮.Caption='CC' then
打开窗体CC
else if 动态创建的按钮.Caption='DD' then
打开窗体DD;
end;
-------------------------------------------------------------
总结:
现在按钮是能看到了,按道理说我在主窗体里单击我动态创建的按钮时,应该会有不同的窗体被打开才对,
但是现在什么都没有弹出来啊。为什么?不知道是我的思路不对还是缺少什么东西?应该怎么写才好?
 
后退
顶部