- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
当运行一个用 C 编写的应用程序时,该应用程序使用一些用 Delphi XE7 编写的 dll,我在以下代码中遇到了访问冲突,该代码位于 vcl 库的 vcl.forms.pas 中。
procedure TCustomForm.CMAppSysCommand(var Message: TMessage);
{$IF NOT DEFINED(CLR)}
type
PWMSysCommand = ^TWMSysCommand;
{$ENDIF}
begin
Message.Result := 0;
if (csDesigning in ComponentState) or (FormStyle = fsMDIChild) or
(Menu = nil) or Menu.AutoMerge then
{$IF DEFINED(CLR)}
with TWMSysCommand.Create(Message) do
{$ELSE}
with PWMSysCommand(Message.lParam)^ do
{$ENDIF}
begin
SendCancelMode(nil);
if SendAppMessage(CM_APPSYSCOMMAND, CmdType, Key) <> 0 then //Here the debugger shows the access violation
Message.Result := 1;
end;
end;
访问冲突发生在SendAppMessage 线上,似乎是由Message.LParam 为0 引起的。该消息是WM_SYSCOMMAND 消息。有没有办法追踪这条消息的来源?在调用堆栈中,所有函数都是VCL或系统文件的一部分。
This answer表明一般来说追踪 Windows 消息的发件人是困难的。但是,由于就我而言,所有内容都在同一个应用程序中,因此我希望这会让事情变得更容易。
以前,同样的错误也出现在 forms.pas 中,并通过将该文件的副本添加到项目中然后检查此函数中的 LParam <> 0 来修复。我尝试对现在使用的 vcl.forms.pas 执行相同的操作,但这会导致编译错误。即使答案为 here我无法构建它。然而,许多谷歌点击也表明,改变 vcl 中的内容通常是一个坏主意,所以我尽量避免这个选项。
This article为我提供了有关底层系统以及如何发生 Message.LParam 为 0 的良好信息。但是,我不知道如何查找消息的来源,也不知道应该查找生成该消息的类。
正如下面 Remy 接受的答案中所述,可以通过让该类提供 CMAppSysCommand 函数来防止 LParam = 0 来解决眼前的问题。
最佳答案
您所描述的情况在正常情况下应该是不可能的。
整个VCL中只有两个地方CM_APPSYSCOMMAND
发送自:
TWinControl.WMSysCommand()
,当 UI 控件收到 WM_SYSCOMMAND
时调用它信息。 LParam
CM_APPSYSCOMMAND
的message 永远不会设置为 0,它被设置为指向 TMessage
的指针。原记录WM_SYSCOMMAND
消息:
Form := GetParentForm(Self);
if (Form <> nil) and
(Form.Perform(CM_APPSYSCOMMAND, 0, Winapi.Windows.LPARAM(@Message)) <> 0) then
Exit;
TCustomForm.CMAppSysCommand()
,当表单收到 CM_APPSYSCOMMAND
时调用它信息。它将消息转发到 TApplication
窗口(使用 SendAppMessage()
,它只是使用提供的参数调用 SendMessage(Application.Handle, ...)
):
with PWMSysCommand(Message.lParam)^ do
begin
...
if SendAppMessage(CM_APPSYSCOMMAND, CmdType, Key) <> 0 then
Message.Result := 1;
end;
other question你提到解释如何CM_APPSYSCOMMAND
由 VCL 使用,但没有说明任何内容 LParam
TCustomForm.CMAppSysCommand()
中可能为 0 ,因为在正常情况下它不可能为 0。 TApplication.WndProc()
中可以为 0 ,但这完全没问题。
我能想到的唯一可能性是,如果有人手动发送假的 CM_APPSYSCOMMAND
消息(即 CM_BASE + 23 = $B017
,又名 WM_APP + $3017
)直接发送到您的 TForm
window 。仅TWinControl
应该永远这样做。自从 TWinControl
使用Perform()
而不是SendMessage()
对于该发送,您应该看到 TWinControl.WMSysCommand()
在 TCustomForm.CMAppSysCommand()
的调用堆栈上。如果您不这样做,则该消息是假的。如果使用SendMessage()
发送而不是Perform()
,无法知道消息来自哪里。
但是,无论如何,这很容易防范,无需更改任何 VCL 源代码。只需拥有您的 DLL TForm
类为 CM_APPSYSCOMMAND
提供自己的消息处理程序,或者使用 message
指令,或通过覆盖虚拟 WndProc()
方法。无论哪种方式,如果LParam
,您都可以丢弃该消息。为0,例如:
type
TMyForm = class(TForm)
...
private
procedure CMAppSysCommand(var Message: TMessage); message CM_APPSYSCOMMAND;
...
end;
procedure TMyForm.CMAppSysCommand(var Message: TMessage);
begin
if Message.LParam = 0 then
Message.Result := 0
else
inherited;
end;
type
TMyForm = class(TForm)
...
protected
procedure WndProc(var Message: TMessage); override;
...
end;
procedure TMyForm.WndProc(var Message: TMessage);
begin
if (Message.Msg = CM_APPSYSCOMMAND) and (Message.LParam = 0) then
Message.Result := 0
else
inherited;
end;
关于delphi - 在 Delphi VCL 表单中使用 LParam 0 确定 WM_SYSCOMMAND 的发送者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43396221/
在我的工作线程中,我创建了一条发送到主对话框的消息。一旦主对话框收到消息并进入我的 OnStatusUpdate() 函数,我想从 LPARAM lParam 中提取消息并将其显示在对话框编辑框中。我
我的应用程序有一个工作线程,我使用 PostMessage 将字符串发送到主线程。对于 1 条消息,当字符串到达主线程中的消息处理程序时,该字符串将被截断。 该字符串是在工作线程中根据如下所示的原
我在here中看到了下面这段代码。我测试了一下,一切正常。 // g_hLink is the handle of the SysLink control. case WM_NOTIFY: s
我使用的是 Visual C++/MFC,我发送的消息为 SendMessage(GetParent(hDlg) ,MY_MESSAGE , 0 , LPARAM(x) ); 如何在 hDlg 父回调
我想检测计算机中任何 USB 驱动器的插入和移除。我没有Windows GUI编程的经验,通常使用Qt,但这次我不得不使用Win32 API。 问题是 lParam 总是空的。 我读到我需要使用 Re
我有一个树状 View ,列出了拖放到它上面的文件。 当我创建一个新的 treeview 项目时,我想将文件的地址作为字符串存储在该项目中,并在以后的某个时间点出于各种恶意目的检索它。 查看 Micr
我知道当我收到 WM_KEYDOWN 事件时,LPARAM 变量设置了某些位(在其内部)以识别长按键等信息。 所以我试图分解一个 LPARAM 变量并查看各个位值组和位组以及该值(例如查看第 16 到
我想创建自己的 LPARAM 以传递给 win32 函数 GetKeyNameText(),(第一个参数采用 LPARAM var)。 这可能看起来像是在用困难的方式做事,但它是一种解决方法,因为没有
我已经设置了一个 WH_MOUSE 钩子(Hook),一切正常,除了我无法获得传递给我的 HOOKPROC 函数在 C# 中正确翻译。 我的项目由两部分组成,C++ 中的非托管部分执行 Hook 和过
我正在构建一个非常简单的 win32 控制台应用程序,该应用程序用 C 编码并使用 Visual Studio 2010/2013 编译。它将有一个消息队列在与主线程不同的线程中运行。控制台将从 VB
我正在尝试使用 TreeView_SetItem 设置 lParam 但它不起作用。下面的测试代码使用TreeView_GetItem 来显示lParam 在用TreeView_SetItem 设置后
我在 View 中有 2 个 CEdit 控件,它们都有相同的 ID。 在父窗口中,我创建了 ON_EN_CHANGE 句柄来捕获他们的编辑消息。由于编辑其中任何一个编辑框都会向 handle 函数发
我正在尝试将其包含到我的对话框窗口过程中,当收到消息 WM_CTLCOLORSTATIC 时,我将获得发送消息的控件的 ID。 case WM_CTLCOLORSTATIC: UINT
首先,这个函数被调用了很多次。需要注意的是 wString[] 确实包含字符常量 '\n'。 void D2DResources::PutToLog(WCHAR wString[]) { in
我知道 wParam 和 lParam 是(我相信是 32 位)特定于当时正在传递的消息的信息位,但是有什么方法可以分辨每条消息放入这两个消息中的内容吗? 我在某处读到 wParam 是 16 位而
我编写了下面的代码。我在我的程序中使用过它,它似乎有效。无论如何,我在问它是否正确。 int SendMessageWMSIZE(HWND hwnd) { RECT rc; GetCl
public class sendKeys { [DllImport("user32.dll")] public static extern IntPtr FindWindow(str
在 MSDN 上,对于 WM_KEYDOWN 定义,它表示 lparam 的位包含: Bits Meaning 0-15 The repeat count for the current
一个标准的窗口过程函数采用这个原型(prototype): LRESULT CALLBACK WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM l
无论从文件中检索到什么数据,我都需要在文本框中显示文本。 在 Windows 应用程序中按下特定按钮 (IDB_SHOW_BUTTON) 时,我正在执行以下操作:- case IDB_SHOW_BUT
我是一名优秀的程序员,十分优秀!