我有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.Handle或Form1.Handle作为函数参数C ++库。 他们没有工作,甚至没有说有关,同时通过改变参数值(我想这应该是另外一个问题)。 此外,我一直在使用:: FindWindow函数()和:: PostMessage的()试图代替FindWindow函数()和PostMessage的()(它们之间有什么区别呢?),这并没有任何帮助。 我想已经提高了整整一天situtuation但不知道如何解决它。 帮助我的任何想法,请。
除了别人怎么说,一个更好的设计是有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;
从结果FindWindow
可以是零或非零。 句柄值不躺在号线。 他们只是不同的值,所以它是没有意义的不平等运营商适用于他们。 换句话说,办理值可以显示为负数,因此不要以为有效的句柄将始终大于零。
如果窗口句柄值不匹配,那么这也难怪没有其他作品。 你在任何位置,以便调试信息的功能,因为你甚至不知道你将它们发送到正确的窗口。 专注于固定,第一。
仅使用FindWindow
作为最后的手段。 它提供了当有适合你的搜索条件的多个窗口没有检测到设备。 它总是正好返回一个结果。 如果可能的话,避免在所有搜索。 相反,转告寄件人正是窗口消息发送到。 你说你尝试这样做,失败了,但我劝你去追求那个途径更多一些。 你有问题,可能是一个不匹配的调用约定。 确保DLL和主机应用程序使用STDCALL。
一旦你确定你将消息发送到右边的窗口, 那么你可以不用担心,为什么你的消息是不正常的进度条。 我可以看到至少有两个方面的原因:
当DLL函数运行过程中,你的主要程序,该程序名为DLL,是不是。 它等待DLL的代码返回。 这意味着你的主程序不处理任何消息。 该DLL被张贴了一堆的消息,但他们没有得到尚未处理。 他们不会得到处理,直到程序回来到它的消息循环。
Windows的消息队列的默认大小为10000。 您发布的10倍,许多消息队列,不处理任何你停止过,所以,即使队列是完全空的,你开始前(这是不可能的,因为你可能会触发从键盘或鼠标输入此功能) ,你只拿到十分之一的消息。 当队列已满, PostMessage
只是放弃该消息。 而且,由于你与消息发送的值是0和100之间的整数,这是毫无意义给他们10万只时,他们中的101将举行有意义的信息。
如果以相同的FindWindow函数调用返回不同的窗口,那么你必须有一个名为Form1的多个窗口。 尝试给这些不同的窗口不同的名称,以便它们可以被唯一标识。
未使用的问题有点不清楚。 也许你的意思是,编译器已经注意到,分配给tHWND值从未使用过,因此是毫无意义的。
我会做最后的评论,这个问题是不准确的,这可能是你的问题的一部分。 比如你说所有的变量是未使用的,但我们有你的意思没有明确的想法。 你将有更多的调试成功,如果你是更精确,有条不紊。
好吧,看来我已经解决了问题...我试过雷米的建议,声明导出函数
function MyFunction (fHWND: HWND): Integer; cdecl; external 'My.dll'
与cdecl调用约定大卫劝。 我以前的函数的声明看起来像这样
TMyFunction = function (fHWND: HWND): Integer;
我想这就是问题所在。 谢谢大家的帮助!
现在PS,我怎么可以关闭的问题?