我现在做的一个工程要求这样:主界面左侧是一个列表,这个列表内容可以中数据库读出来,鼠标单击列表内容,显示对应的设置窗体。但是领导要求:设置以后会逐步增加,所以这些设置的窗体要做活的,而且主程序以后就不修改了,要动态加载这些设置窗体。
我像这样解决:创建一些窗体放在dll中,然后主程序有一个配置文件,然后根据配置文件调用不同的dll中的窗体,一个dll放一个窗体。
但是问题出现了:我尝试建立ActivexForm工程,默认为ocx,我修改编译生成dll,我用regsver32进行注册,然后我再主界面加了一个TOLEContainer控件,想把这个ActivexForm放在这个上面,我的activeXForm类名是‘TMyAF’,然后在主程序中调用OleContainer1.CreateObject('TMyAF',false);运行到这一句出错,说是无效的类别字串,这是为什么?
还有activexForm和dll中的Form有什么区别?
大家看看我的这个做法是否可行?或者有可行的方案?
在线等
我像这样解决:创建一些窗体放在dll中,然后主程序有一个配置文件,然后根据配置文件调用不同的dll中的窗体,一个dll放一个窗体。
但是问题出现了:我尝试建立ActivexForm工程,默认为ocx,我修改编译生成dll,我用regsver32进行注册,然后我再主界面加了一个TOLEContainer控件,想把这个ActivexForm放在这个上面,我的activeXForm类名是‘TMyAF’,然后在主程序中调用OleContainer1.CreateObject('TMyAF',false);运行到这一句出错,说是无效的类别字串,这是为什么?
还有activexForm和dll中的Form有什么区别?
大家看看我的这个做法是否可行?或者有可行的方案?
在线等
我刚才的那个例子在主程序中还是引用了TLB文件,也就是说以后还是要修改主程序的,
配置文件可以用数据库呀不要一个窗体放一个 dll ,dll 中可以放好多的窗体呀数据库中保存 dll 的导出函数就行了
1、建个表定义DLL文件名及DLL功能入口函数名
2、主程序统一定义DLL的接口参数,以后新加的DLL按定好的格式调用就行了,
要么你就作成原始的DLL只输出函数的 在函数中调用你的窗口 一般不会出错
但是在DLL中怎么定义界面和如何调用?我定义一个个Frame然后显示在我的主程序Panel上是否可以?
还有DLL中的参数我是不是只能传递主程序的Handle?在dll中根据handle我怎么得到Panel?
但是在DLL中怎么定义界面和如何调用?我定义一个个Frame然后显示在我的主程序Panel上是否可以?
还有DLL中的参数我是不是只能传递主程序的Handle?在dll中根据handle我怎么得到Panel?
DLL代码:
library Project1;uses
ShareMem,
SysUtils,
Classes,
ExtCtrls,
Forms,
System,
Dialogs,
Unit1 in 'Unit1.pas' {Form1};{$R *.res}
var
{ 用于初始化:保存DLL本身的Application,然后设置DLL的Application指向Host的Application }
DllApp:TApplication; procedure InitDll(MainApp:TAppLication);stdcall;
begin
DllApp:=Application;
Application:=MainApp;
end; procedure FreeDll;stdcall;
begin
Application:=DllApp;
end; function GetForm(AParentControl:TComponent):TForm1;stdcall;
begin
result:=TForm1.Create(AParentControl);
end;exports
GetForm,InitDll,FreeDll;begin
end.主程序代码:
unit Unit1;interfaceuses
ShareMem,Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;type
TfrmMain = class(TForm)
Button1: TButton;
Panel1: TPanel;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
frmMain: TfrmMain;implementation
{$R *.dfm}
function GetForm(AparentControl:TComponent):TForm;stdcall; External 'project1.dll ';
procedure InitDll(MainApp:TApplication);stdcall; External 'project1.dll ';
procedure FreeDll;stdcall; External 'project1.dll ';procedure TfrmMain.Button1Click(Sender: TObject);
begin
with GetForm(self) do
begin
//ShowModal;
Parent:=self.Panel1;
Visible:=true;
end;
end;procedure TfrmMain.FormCreate(Sender: TObject);
begin
initdll(Application);
end;procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
freeDll;
end;procedure TfrmMain.Button2Click(Sender: TObject);
begin
//这段是主程序里面建立的和DLL中一样的Form,就可以正常显示
if asd<>nil then
begin
asd.Free;
asd:=nil;
end;
asd:=TForm3.Create(self);
asd.Parent:=self.Panel1;
asd.Visible:=true;
end;end.
建議使用API: SetParent(Dllform.Handle,mainform.Panel.Handle);
另外,建議你把整個程序的架構要分清,建議寫一個主呼叫的dll,在這個dll裡面,根據參數來判斷要呼叫哪一個dll,主程序只需要調用這個dll所exports出來的函數,傳進不同的參數,比如可以通過tag來區分不同的form。這樣就不用修改主程序了,也比較安全。
建議application的切換,寫在dll裡面,可以這樣:
procedure DLLEntryPoint(dwReason: DWord);
begin
case dwReason of
DLL_PROCESS_ATTACH:;//在這裡記錄原來的application
DLL_PROCESS_DETACH:;//在這裡還原原來的application
DLL_THREAD_ATTACH: ;
DLL_THREAD_DETACH: ;
end;
end;begin
DllProc :=@DLLEntryPoint;
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
1,DLLEntryPoint的这个方法怎么使用?那个主程序的Application怎么传进来的?
2,如果采用你说的有一DLL专门负责提供调用那个DLL文件和哪个方法,是不是就要使用动态加载DLL的方法了?那我加载几个DLL中的Form,我什么时候释放?怎么释放?我加载一个DLL,在显示一个窗体到Panel上,然后就释放DLL?如果我再调用这个DLL中的另一个窗体,我是不是还要加载一次?
还有经过这两天的尝试,发现两个主要的问题:
1,DLL中的Form不能用传进来的Panel来Create,要使用传进来的Application来创建;
2,设置Parent确实不能用dllform.parent:=mainform.panel,只能使用API的SetParent方法
3,如果要显示在Panel上的是无标题框的form,不能将form放入类型设置为None,也不要将Align设置为alClient,做法是设置windowstate为Max,然后去掉标题栏窗口,如我使用如下:
windows.SetParent(test.Handle,self.Panel1.Handle);
windows.SetWindowLong(test.Handle,GWL_STYLE,GetWindowLong(test.Handle,GWL_STYLE) and not(WS_CAPTION or WS_THICKFRAME));
test.WindowState := wsMaximized;
1,直接寫在工程文件裡面.主程序的application可以在getform時傳入,在這裡進行切換;
2,是的,用動態加載的方法。關於釋放的問題,你可以在主呼叫dll裡面再寫一個函數來管理這些加載進來的dll,export出去,在主程序裡,你可以選擇釋放的時機(個人認為,顯示完就釋放,方便管理,避免內存洩漏)
1,动态调用DLL显示之后,使用的是SetParent方法,但是Panel的ControlCount属性为什么还是0呢?
2,如果DLL中的窗体在CloseQuery方法里有阻止窗体关闭的代码,主程序怎么才能知道我调用Close之后是关闭还是阻止关闭了呢?因为我要显示下一个窗体了?
1、由於是采用API強制嵌入,而不是設置parent屬性,因此panel並沒有收到notify,controlcount也就為0了;
2、在主程序裡面,可以設定一個變量IsClose來標識dllform是否關閉,自定一個消息(比如WM_IsClose),寫一個相應處理過程;
在dll裡也定義這樣的消息類型,你可以在closequery裡面發送消息給主程序,如SendMessage(mainform.handle,WM_IsClose,0,1)或者(mainform.handle,WM_IsClose,0,0)通過判斷lparam來判斷是否關閉