与PostMessage的问题从C ++ .DLL德尔福窗体应用程序(Problems with P

2019-09-17 21:11发布

我有Windows窗体上写的Delphi 7和C ++使用MFC .dll文件书面申请。

我目前正试图从.DLL实现基本消息张贴到主执行文件上显示进度用户的计算过程,但面临一些问题。

让我先介绍我的做法。 我在德尔福申请注册简单的信息,如:

WM_MSG := RegisterWindowMessage('WM_MSG');

做同样在图书馆的一部分:

UINT nMsgID = RegisterWindowMessage(_T("WM_MSG"));

这是OK:调试时,我可以看到两边相同的值。

我的图书馆功能看起来像这样(只是一个虚拟的例子来测试进度条):

extern "C" __declspec(dllexport) int MyFunction() {  
  UINT nMsgID = RegisterWindowMessage(_T("WM_MSG"));
  HWND hWnd = FindWindow(NULL, "Form1");
  if (hWnd > 0)
    for (int i = 0; i < 100000; i++) {
      int param = ceil(100 * (double) i / (double) 100000);
      PostMessage(hWnd, nMsgID, param, NULL);
    }
  return 1;
}

可执行的onMessage事件:

procedure TForm1.OnMessageEvent(var Msg: tagMSG; var Handled: Boolean);
begin
  Handled := True;
  if Msg.message = WM_MSG then
    ProgressBar1.Position := Msg.wParam
  else Handled := False;
end;

C ++从可执行的函数调用:

procedure TMyFunctionDLL.Execute;
var
  i: Integer;
  tHWND: HWND;
begin
  tHWND := FindWindow(nil, 'mainF');
  i := Func;
end;

第一个问题是tHWND的hWnd变量的值是莫名其妙地不同。 经过一番研究,我发现了3种情况:1正负巨大的hWnd 2.零的hWnd 3.未定义(“???”)

在所有情况下可变的hWnd被标记为未使用的 ,我不知道这是什么意思。 最有趣的事情是,如果我测试它在非常简单的德尔福形式(只有一个单元)的代码不工作。 这个简单的德尔福形式与我真正的C ++在那里计算实际数据的.dll代码效果很好。 但是,当我用我一般Delphi应用程序(很多单位,但仍然一个形式)似乎主要应用的onMessage事件没有赶上从C ++的dll的任何事件。

因此,有2个问题:1。为什么是的hWnd值总是不同的,为什么他们“未使用”? 2.我怎么能强迫我的主要应用程序与进度正常工作?

我一直在使用不同的方法来解决这个问题。 如通过Application.HandleForm1.Handle作为函数参数C ++库。 他们没有工作,甚至没有说有关,同时通过改变参数值(我想这应该是另外一个问题)。 此外,我一直在使用:: FindWindow函数():: PostMessage的()试图代替FindWindow函数()PostMessage的()(它们之间有什么区别呢?),这并没有任何帮助。 我想已经提高了整整一天situtuation但不知道如何解决它。 帮助我的任何想法,请。

Answer 1:

除了别人怎么说,一个更好的设计是有EXE通过其HWND到DLL直接,那么DLL不必去打猎吧。 这具有额外的好处,即EXE可以决定HWND的DLL应该张贴的消息。 我会用AllocateHWnd()创建一个专用窗口。

尝试这个:

UINT nMsgID = RegisterWindowMessage(_T("WM_MSG")); 

extern "C" __declspec(dllexport) int __stdcall MyFunction(HWND hWnd) {   
    if ((nMsgID != 0) && (hWnd != NULL)) {
        for (int i = 0; i < 100000; i++) { 
            int param = ceil(100 * (double) i / (double) 100000); 
            PostMessage(hWnd, nMsgID, param, 0); 
        } 
    }
    return 1; 
} 

unit Unit1;

interface

...

var
  DllWnd: HWND = 0;

implementation

var
  WM_MSG: UINT = 0;

procedure TForm1.FormCreate(Sender: TObject); 
begin 
  DllWnd := AllocateHWnd(DllWndProc);
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
  if DllWnd <> 0 then
  begin
    DeallocateHWnd(DllWnd);
    DllWnd := 0;
  end;
end; 

procedure TForm1.DllWndProc(var Message: TMessage); 
begin 
  if (Message.Msg = WM_MSG) and (WM_MSG <> 0) then 
    ProgressBar1.Position := Message.WParam
  else
    Message.Result := DefWindowProc(DllWnd, Message.Msg, Message.WParam, Message.LParam); 
end; 

...

initialization
  WM_MSG := RegisterWindowMessage('WM_MSG');     

end.

uses
  Unit1;

function DllFunc(Wnd: HWND): Integer; stdcall; external 'My.dll' name 'MyFunction'; 

procedure TMyFunctionDLL.Execute;   
var   
  i: Integer;   
begin   
  i := DllFunc(DllWnd);   
end;   


Answer 2:

从结果FindWindow可以是零或非零。 句柄值不躺在号线。 他们只是不同的值,所以它是没有意义的不平等运营商适用于他们。 换句话说,办理值可以显示为负数,因此不要以为有效的句柄将始终大于零。

如果窗口句柄值不匹配,那么这也难怪没有其他作品。 你在任何位置,以便调试信息的功能,因为你甚至不知道你将它们发送到正确的窗口。 专注于固定,第一。

仅使用FindWindow作为最后的手段。 它提供了当有适合你的搜索条件的多个窗口没有检测到设备。 它总是正好返回一个结果。 如果可能的话,避免在所有搜索。 相反,转告寄件人正是窗口消息发送到。 你说你尝试这样做,失败了,但我劝你去追求那个途径更多一些。 你有问题,可能是一个不匹配的调用约定。 确保DLL和主机应用程序使用STDCALL。


一旦你确定你将消息发送到右边的窗口, 那么你可以不用担心,为什么你的消息是不正常的进度条。 我可以看到至少有两个方面的原因:

  1. 当DLL函数运行过程中,你的主要程序,该程序名为DLL,是不是。 它等待DLL的代码返回。 这意味着你的主程序不处理任何消息。 该DLL被张贴了一堆的消息,但他们没有得到尚未处理。 他们不会得到处理,直到程序回来到它的消息循环。

  2. Windows的消息队列的默认大小为10000。 您发布的10倍,许多消息队列,不处理任何你停止过,所以,即使队列是完全空的,你开始前(这是不可能的,因为你可能会触发从键盘或鼠标输入此功能) ,你只拿到十分之一的消息。 当队列已满, PostMessage只是放弃该消息。 而且,由于你与消息发送的值是0和100之间的整数,这是毫无意义给他们10万只时,他们中的101将举行有意义的信息。



Answer 3:

如果以相同的FindWindow函数调用返回不同的窗口,那么你必须有一个名为Form1的多个窗口。 尝试给这些不同的窗口不同的名称,以便它们可以被唯一标识。

未使用的问题有点不清楚。 也许你的意思是,编译器已经注意到,分配给tHWND值从未使用过,因此是毫无意义的。

我会做最后的评论,这个问题是不准确的,这可能是你的问题的一部分。 比如你说所有的变量是未使用的,但我们有你的意思没有明确的想法。 你将有更多的调试成功,如果你是更精确,有条不紊。



Answer 4:

好吧,看来我已经解决了问题...我试过雷米的建议,声明导出函数

function MyFunction (fHWND: HWND): Integer; cdecl; external 'My.dll'

与cdecl调用约定大卫劝。 我以前的函数的声明看起来像这样

TMyFunction = function (fHWND: HWND): Integer;

我想这就是问题所在。 谢谢大家的帮助!

现在PS,我怎么可以关闭的问题?



文章来源: Problems with PostMessage from C++ .dll to Delphi Forms application