5,379
社区成员
发帖
与我相关
我的任务
分享
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
可不可以給DLL也加上這們的代碼呢?procedure InitDLL; stdcall;
begin
Application.Initialize;
Application.CreateForm(TDLLForm, DLLForm);
Application.Run;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
InitDLL;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
TTimer(Sender).Enabled := False;
InitDLL;
end;
這下可以了. 但不能讓DLL裡的表單一開始就顯示出來吧. 得. 再改改InitDLL. 如下:procedure InitDLL; stdcall;
begin
Application.Initialize;
Application.ShowMainForm := False;
Application.CreateForm(TDLLForm, DLLForm);
Application.Run;
end;
主表單不顯示了, 得加上一個, 看看效果:)
再到DLL里加上一個Form( 命名為 DLLChildForm ), 在表單上放一個TSpeedButton控制項.
再給DLL匯出一個函數, 如下:
procedure CreateChildForm; stdcall;
begin
with TDLLChildForm.Create(Application) do
begin
Show;
end;
end;
再到主表單中添加一個按鈕. 點擊事件代碼如下.
procedure TForm1.Button1Click(Sender: TObject);
begin
CreateChildForm;
end;
procedure DestoryDLL; stdcall;
var
i: Integer;
begin
for i := Application.ComponentCount - 1 downto 0 do
begin
if Application.Components[i].ClassNameIs('TDLLChildForm') then
begin
TDLLChildForm(Application.Components[i]).Release;
end;
end;
if DLLForm = nil then
begin
Exit;
end;
DLLForm.Release;
DLLForm := nil;
end;
再給主程序主表單的OnCloseQuery添加代碼如下:procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
DestoryDLL;
end;
procedure DestoryDLL; stdcall;
var
i: Integer;
begin
for i := Application.ComponentCount - 1 downto 0 do
begin
if Application.Components[i].ClassNameIs('TDLLChildForm') then
begin
TDLLChildForm(Application.Components[i]).Release;
end;
end;
if DLLForm = nil then
begin
Exit;
end;
DLLForm.Release;
// Application.Terminate;
PostMessage(Application.Handle, WM_QUIT, 0, 0);
DLLForm := nil;
end;
procedure InitDLL(AHandle: Thandle); stdcall;
begin
Application.Initialize;
Application.ShowMainForm := False;
Application.CreateForm(TDLLForm, DLLForm);
// 保存原來的控制碼
DLLForm.Tag := Application.Handle;
// DLL 從屬的控制碼 ( 如果沒有此行, 執行緒的執行不能達到理想效果 )
// 並且這樣才能真正的讓消息迴圈處理它應處理的所有消息
Application.Handle := AHandle;
Application.Run;
Application.Handle := DLLForm.Tag;
end;
[2]過程:
type
TForm1 = class(TForm)
...............
...............
private
Msg: Cardinal;
protected
procedure WndProc(var Message: TMessage); override;
public
...............
...............
end;
var
Form1: TForm1;
MsgStrList: TStringList;
MsgStrLock : TCriticalSection;
implementation
uses ThreadCommunication_Unit;
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
Msg := RegisterWindowMessage('wm_threadmsg');
MsgStrList := TStringList.Create;
end;
procedure TForm1.WndProc(var Message: TMessage);
begin
if Message.Msg = Msg then begin
MsgStrLock.Enter;
if MsgStrList.Count > 0 then begin
Caption := MsgStrList.Strings[0];
MsgStrList.Delete(0);
end;
MsgStrLock.Leave;
ShowMessage('收到消息了'+ inttostr(Message.Msg));
end
else begin
inherited;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
TThreadCommunication.Create(Msg,Memo1);
end;
...............
...............
initialization
MsgStrLock := TCriticalSection.Create;
finalization
MsgStrLock.Free;
end.
一個子執行緒類的單元:
unit ThreadCommunication_Unit;
interface
uses
Classes,StdCtrls;
type
TThreadCommunicaiton = class(TThread)
private
FMsg : Cardinal;
FMemo: TMemo;
protected
procedure Execute; override;
procedure SendMsg;
public
constructor Create(aMsg:Cardinal;am:TMemo);virtual;
end;
implementation
uses Messages,Windows, Dialogs,SysUtils, ThreadMsg;
{ TThreadCommunicaiton }
constructor TThreadCommunicaiton.Create(aMsg: Cardinal; am:TMemo);
begin
inherited Create(True);
FMsg := aMsg;
FMemo:= am;
FreeOnTerminate :=True;
Resume;
end;
procedure TThreadCommunicaiton.Execute;
begin
Synchronize(SendMsg);
end;
procedure TThreadCommunicaiton.SendMsg;
var
M: TMessage;
B: DWord;
d: integer;
begin
{ Place thread code here }
sleep(50);
M.Msg := FMsg;
B := BSM_ALLCOMPONENTS;
MsgStrLock.Enter;
MsgStrList.Add('子執行緒子柄:'+inttostr(ThreadID)+ ' 用BroadcastSystemMessage發送');
d := MsgStrList.Count;
MsgStrLock.Leave;
BroadcastSystemMessage(BSF_POSTMESSAGE, @B , M.Msg, M.WParam, M.LParam );
FMemo.Lines.Add('子執行緒子柄:'+inttostr(ThreadID)+ ' 用BroadcastSystemMessage發送'+inttostr(d));
end;
end.
我在視窗上放有一Memo控制項,可以顯示一些資訊。
同時我定義了一個全域的TStringList的變數,用於存在要從子執行緒傳出的一些值。用BroadcaseSystemMessage發送消息,而消息號由創建子執行緒時傳入。而消息號在FormCreate中用RegisterWindowsMessage定義,並獲得一個消息號。
而消息觸發後的事件處理寫在WndProc中。
這裡將子執行緒傳出的字串寫入視窗的標題。
而TStringList的變數作為臨界區使用, 因為當兩個執行緒訪問全域量時,為防止它們同時執行,需要使用執行緒同步。
用TCriticalSection進行操作。
Enter,進入臨界區
Leave,離開臨界區
這樣可以正確的處理從子執行緒發來的消息。
如果是用SendNotifyMessage函數發送消息的話。
用法如下:
M.Msg := FMsg;
SendNotifyMessage(HWND_BROADCAST,M.Msg , M.WParam, M.LParam);
參數為HWND_BROADCAST,則消息將被發送到系統中所有頂層視窗,包括無效或不可見的非自身擁有的視窗、被覆蓋的視窗和彈出式視窗,但消息不被發送到子窗口。
由於是用SendNotifyMessage將消息發送到主視窗,而主視窗所在執行緒與調用執行緒是同一個執行緒,所以要等待視窗程式處理完消息後再返回。才會執行子執行緒中的:
FMemo.Lines.Add('子執行緒子柄:'+inttostr(ThreadID)+ ' 用SendNotifyMessage發送');