首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在TThread中创建窗口

在TThread中创建窗口
EN

Stack Overflow用户
提问于 2010-09-04 02:38:37
回答 4查看 3.4K关注 0票数 6

我试图在两个不同的项目之间发送消息,但我的问题是,我试图让接收器在TThread对象中运行,但WndProc不能从对象内部工作,必须是一个函数,有没有办法在TThread内创建一个窗口,可以在线程内处理消息?

这就是我的意思

代码语言:javascript
复制
function TDataThread.WindowProc(hwnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
 Result := 0;
 case uMsg of
   WM_DATA_AVA: MessageBox(0, 'Data Avaibale', 'Test', 0);
  else Result := DefWindowProc(hwnd, uMsg, wParam, lParam);
 end;
end;

Procedure TDataThread.Create(const Title:String);
begin
 HAppInstance := HInstance;
 with WndClass do
 begin
  Style := 0;
  lpfnWndProc := @WindowProc;          //The Error Lies here (Variable Required)
  cbClsExtra := 0;
  cbWndExtra := 0;
  hInstance := HAppInstance;
  hIcon := 0;
  hCursor := LoadCursor(0, IDC_ARROW);
  hbrBackground := COLOR_WINDOW;
  lpszMenuName := nil;
  lpszClassName := 'TDataForm';
 end;
 Windows.RegisterClass(WndClass);
 MainForm := CreateWindow('TDataForm', PAnsiChar(Title), WS_DLGFRAME , XPos, YPos, 698, 517, 0, 0, hInstance, nil);
end;

我需要一个表单,这样如果需要,我可以使用FindWindow和FindWindowEx从另一个应用程序获得它的句柄

EN

回答 4

Stack Overflow用户

发布于 2010-09-04 03:03:32

在后台线程中运行wndproc可以在Win32中完成,但人们普遍认为这不是一个好主意。

为此,必须确保后台线程包含消息分派循环: GetMessage/TranslateMessage/DispatchMessage。必须确保要在后台线程中处理消息的窗口句柄是在后台线程(在后台线程的上下文中调用CreateWindow)及其所有子窗口上创建的。此外,您还必须确保您的后台线程除了执行其他操作外,还要频繁地调用其消息循环(这有点违背了使用后台线程的目的!)

如果您的后台线程没有消息循环,则在后台线程上创建的窗口句柄将永远不会接收任何消息,因此不会发生任何事情。

现在,为什么你不应该这样做: Windows是消息驱动的,这意味着它们本质上是一个协作的多任务调度系统。每个GUI windows应用程序都必须在主线程中有一个消息循环,才能完成任何工作。该消息循环实际上将支持任意数量的窗口,所有窗口都在主线程上。正确实现的UI不会在主线程中执行任何阻塞执行的操作,因此消息循环将始终处于就绪和响应状态。

因此,如果主线程上的现有消息循环可以处理所有窗口消息传递需求,而不会阻塞或冻结,那么为什么要通过尝试在后台线程中运行第二个消息循环来使您的工作变得更加复杂呢?使用后台线程没有任何优势。

票数 11
EN

Stack Overflow用户

发布于 2010-09-08 04:35:08

只要TThread实现了消息循环,并且CreateWindow()在与消息循环相同的线程上下文中调用,那么在TThread中创建窗口就可以很好地工作。换句话说,您必须从TThread()方法内部调用CreateWindow(),而不是从其构造函数内部调用,例如:

代码语言:javascript
复制
type
  TDataThread = class(TThread)
  private
    FTitle: String;
    FWnd: HWND;
    FWndClass: WNDCLASS;
    FRegistered: boolean;
    class function WindowProc(hwnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; static;
  protected
    procedure Execute; override;
    procedure DoTerminate; override;
  public
    constructor Create(const Title:String); reintroduce;
  end;

constructor TDataThread.Create(const Title: String); 
begin 
  inherited Create(False);
  FTitle := Title;
  with FWndClass do 
  begin 
    Style := 0; 
    lpfnWndProc := @WindowProc;
    cbClsExtra := 0; 
    cbWndExtra := 0; 
    hInstance := HInstance; 
    hIcon := 0; 
    hCursor := LoadCursor(0, IDC_ARROW); 
    hbrBackground := COLOR_WINDOW; 
    lpszMenuName := nil; 
    lpszClassName := 'TDataForm'; 
  end; 
end; 

procedure TDataThread.Execute; 
var
  Msg: TMsg;
begin
  FRegistered := Windows.RegisterClass(FWndClass) <> 0;
  if not FRegistered then Exit;
  FWnd := CreateWindow(FWndClass.lpszClassName, PChar(FTitle), WS_DLGFRAME, XPos, YPos, 698, 517, 0, 0, HInstance, nil); 
  if FWnd = 0 then Exit;
  while GetMessage(Msg, FWnd, 0, 0) > 0 do
  begin
    TranslateMessage(msg);
    DispatchMessage(msg)
  end;
end;

procedure TDataThread.DoTerminate;
begin
  if FWnd <> 0 then DestroyWindow(FWnd);
  if FRegistered then Windows.UnregisterClass(FWndClass.lpszClassName, HInstance);
  inherited;
end;

function TDataThread.WindowProc(hwnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
  Result := 0;
  case uMsg of
    WM_DATA_AVA:
      MessageBox(0, 'Data Available', 'Test', 0);
  else
    Result := DefWindowProc(hwnd, uMsg, wParam, lParam);
  end;
end; 
票数 7
EN

Stack Overflow用户

发布于 2010-09-04 04:22:55

您不需要窗口来接收消息,请尝试以下方法。在线程中(一次)调用PeekMessage以强制创建消息队列,例如:

代码语言:javascript
复制
  // Force Message Queue Creation
  PeekMessage(Msg, 0, WM_USER, WM_USER, PM_NOREMOVE);

然后设置一个消息循环/泵,例如:

代码语言:javascript
复制
  // Run until terminated
  while not Terminated do
  begin

    if GetMessage(@Msg, 0, 0, 0) then
    begin
      case Msg.message of
        WM_DATA_AV: MessageBox(0, 'Data Avaibale', 'Test', 0); 
      else begin
        TranslateMessage(@Msg);
        DispatchMessage(@Msg);
      end;
    end;
  end;
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3638631

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档