The problem
When running an application written in C, that uses some dll's written in Delphi XE7, I run into an access violation in the following code, which is in the vcl.forms.pas of the vcl library.
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;
The access violation occurs on the line with SendAppMessage, and seems to be caused by the fact that the Message.LParam is 0. The message is a WM_SYSCOMMAND message. Is there a way to track where this message originated? In the call stack, all functions are part of the VCL or system files.
This answer suggest that in general it is hard to trace the sender of a windows message. However, since in my case everything is within the same application, I hope that might make it easier.
What have I tried?
Overruling the vcl source
Previously, this same bug appeared in the forms.pas and was fixed by adding a copy of that file to the project and then checking that LParam <> 0 in this function. I have tried doing the same thing with the vcl.forms.pas that is now used, but this leads to compilation errors. Even with answers as here I was not able to build it. However, many google hits also suggested that it is in general a bad idea to change things in the vcl, so I try to avoid that option.
Other questions on StackOverFlow
This article gave me good information about the underlying system and how it might have occured that the Message.LParam is 0. However, I did not know how to find the source of the message or what class I should be looking for that generated it.
The solution
As described in Remy's accepted answer below, the immediate problem could be solved by having the class provide a CMAppSysCommand function to guard against LParam = 0.