在 TWndMethod 中获取 WPARAM 返回 4 个字节
我在编写的类中使用 AllocateHWnd 来通过 TWndMethod 接收系统消息,并且我接收的消息需要处理 4 字节 WPARAM,它专门引用一个指针。但我只得到 2 个字节的回报。我该如何设置才能在课堂上正确接收这些消息?
编辑:具体代码。我正在根据我下载的 Microsoft 示例使用 SHChangeNotifyRegister 设置消息事件。该过程足以拉回我可以购买的事件(在 lEvent 中),但 Microsoft 使用的代码将 WParam 定义为 Thandle,将 LParam 定义为 DWord。我遇到的具体问题是,当函数 IsItemNotificationEvent 为 true 时,SHGetPathFromIDList 会 AVing 或拉回垃圾。我一直在查看这个问题,除了我在文档中指出的 WParam 是一个 Word(可能是旧的)以及我在代码中放入的 GetLastError 返回“句柄无效”之外,我并没有真正看到任何问题。
function IsItemNotificationevent(lEvent: Longint): boolean;
var
flagval: Longint;
begin
flagval := (lEvent and (SCHNE_UPDATEIMAGE or SHCNE_ASSOCCHANGED
or SHCNE_EXTENDED_EVENT or SHCNE_FREESPACE
or SHCNE_DRIVEADDGUI or SHCNE_SERVERDISCONNECT));
Result := (flagval > 0);
end;
procedure TShellNotifyHandler.WindowProc(Var msg: TMessage);
var
hNotifyLock: THandle;
lEvent: Longint;
pgpidl: PitemIDList;
psi1: array[1..MAX_PATH] of Char;
begin
if Msg.Msg = FShellMsg then
begin
hNotifyLock := SHChangeNotification_Lock(THandle(Msg.WParam),DWord(Msg.LParam),
pgpidl, lEvent);
writeln(SysErrorMessage(GetLastError));
if (hNotifyLock > 0) then
begin
if IsItemNotificationEvent(lEvent) then
// this limits events for this to what Microsoft defined in their example
begin
if (pgpidl <> nil) then
SHGetPathFromIDList(pgpidl, @psi1);
Writeln('Path #1: ', String(psi1));
end;
SHChangeNotification_Unlock(hNotifyLock);
end;
if Assigned(FOnShellNotify) then
FOnShellNotify(Self, LEvent);
end
else
FWndProc(Msg);
end;
I'm using AllocateHWnd in a class I'm writing to receive system messages with a TWndMethod and the messages I'm receiving need to handle a 4-byte WPARAM, which specifically references a pointer. But I'm only getting 2 bytes in return. How do I set up things so I can correctly receive these messages within the class?
Edit: Specific code. I'm setting a message event up using SHChangeNotifyRegister, based on a Microsoft sample I downloaded. The proc works enough to pull back events (in lEvent) that I can buy off on, but the code Microsoft used defines WParam to be Thandle and LParam to be DWord. The specific problem I have is that when the function IsItemNotificationEvent is true, SHGetPathFromIDList is AVing or pulling back garbage. I kept looking this over and am not really seeing a problem other than what the docs I have indicate in that WParam is a Word (probably old) and that GetLastError at the point I put in the code returns "The handle is invalid".
function IsItemNotificationevent(lEvent: Longint): boolean;
var
flagval: Longint;
begin
flagval := (lEvent and (SCHNE_UPDATEIMAGE or SHCNE_ASSOCCHANGED
or SHCNE_EXTENDED_EVENT or SHCNE_FREESPACE
or SHCNE_DRIVEADDGUI or SHCNE_SERVERDISCONNECT));
Result := (flagval > 0);
end;
procedure TShellNotifyHandler.WindowProc(Var msg: TMessage);
var
hNotifyLock: THandle;
lEvent: Longint;
pgpidl: PitemIDList;
psi1: array[1..MAX_PATH] of Char;
begin
if Msg.Msg = FShellMsg then
begin
hNotifyLock := SHChangeNotification_Lock(THandle(Msg.WParam),DWord(Msg.LParam),
pgpidl, lEvent);
writeln(SysErrorMessage(GetLastError));
if (hNotifyLock > 0) then
begin
if IsItemNotificationEvent(lEvent) then
// this limits events for this to what Microsoft defined in their example
begin
if (pgpidl <> nil) then
SHGetPathFromIDList(pgpidl, @psi1);
Writeln('Path #1: ', String(psi1));
end;
SHChangeNotification_Unlock(hNotifyLock);
end;
if Assigned(FOnShellNotify) then
FOnShellNotify(Self, LEvent);
end
else
FWndProc(Msg);
end;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为这段代码的主要错误是,我只真正研究了对 的调用
SHChangeNotification_Lock
,就是你无条件调用GetLastError
。该 API 函数的文档不充分,因为它没有指定如何发出错误信号。但是,我强烈希望返回 NULL 的函数能够发出错误信号。由于文档没有提及任何有关调用
GetLastError
的内容,因此 API 函数完全有可能没有设置最后一个错误值。无论如何,即使您可以确定可以调用GetLastError
,您也应该只在失败后才这样做,即。如果对SHChangeNotification_Lock
的调用返回NULL
。如果您在成功的 API 调用后调用GetLastError
,您将获得最近失败的 API 调用的错误代码,该错误代码与当前调用无关。最重要的是,我确信 WParam 携带了全部 4 个字节,并且您的问题不在于该过程的这一部分。
所有这一切的结果是我坚信
SHChangeNotification_Lock
会成功,但对SHGetPathFromIDList
的调用失败。您不检查返回值。我敢打赌它会返回FALSE
。查看这两个函数的 C++ 声明。
SHChangeNotification_Lock
返回这样输入的参数中的 ID 列表:SHGetPathFromIDList
在这样输入的参数中接收 ID 列表:我不知道您的
声明是什么SHChangeNotification_Lock 看起来像,但我的 Delphi (XE2) 版本中提供的看起来完全错误。它的参数声明如下:
老实说,我看不出 Windows API 函数如何返回 Delphi 开放数组作为输出参数。我认为应该这样声明:
并且您可能需要将
PPItemIDList
声明为^PItemIDList
。现在,pppidl 是一个数组。它指向
PItemIDList
数组的第一个元素。因此,您可以通过调用以下命令来获取第一个元素的路径:我相信,这是您遇到的真正问题。
最后我不明白为什么你要使用
hNotifyLock > 测试是否成功0 。正确的测试是
hNotifyLock <> 0 。现在,我知道一些 Delphi 类型在最近的版本中发生了变化,但是如果
THandle
是您的 Delphi 版本中的有符号值,那么您的代码将是错误的。无论如何,正确的逻辑测试是<>0
。The main thing that I see wrong with this code, and I've only really studied the call to
SHChangeNotification_Lock
, is that you are unconditionally callingGetLastError
.The documentation for that API function is inadequate because it does not specify how errors are signalled. However, I would strongly expect that errors to be signalled by the function returning
NULL
. Since the documentation does not say anything about callingGetLastError
it is entirely possible that the API function does not set the last error value. No matter, even if you can be sure thatGetLastError
can be called, you should only do so after a failure, ie. if the call toSHChangeNotification_Lock
returnsNULL
. If you callGetLastError
after a successful API call you will get the error code for the most recent failed API call, which is unrelated to the current call.The bottom line is that I'm sure
WParam
is carrying all 4 bytes and that your problem is not with that part of the process.The upshot of all this is the I strongly believe that
SHChangeNotification_Lock
is succeeding, but the call toSHGetPathFromIDList
is failing. You don't check the return value for that. I bet it returnsFALSE
.Take a look at the C++ declarations for the two functions.
SHChangeNotification_Lock
returns the ID list in a parameter typed liked this:SHGetPathFromIDList
receives the ID list in a parameter typed liked this:I don't know what your declaration of
SHChangeNotification_Lock
looks like, but the one supplied in my version of Delphi (XE2) looks plain wrong. It has this parameter declared like this:I honestly can't see how a Windows API function can return a Delphi open array as an out parameter. I think it should be declared so:
and you may need to declare
PPItemIDList
to be^PItemIDList
.Now,
pppidl
is an array. It points to the first element of an array ofPItemIDList
. So you would obtain the path of the first element by calling:This, I believe, is the real problem you have.
Finally I can't understand why you would test for success with
hNotifyLock > 0
. The correct test ishNotifyLock <> 0
. Now, I know that some of the Delphi types have changed in recent versions, but ifTHandle
was a signed value in your version of Delphi then you code would be wrong. No matter what, the correct logical test is<>0
.好的,我得到了这个答案。实际上,整个板上有很多问题:
1)当涉及到 IsItemNotificationEvent 时,我出了问题。为了拥有有效的 PIDL,我需要确保该事件不是其中之一,因为没有 PIDL 可以有效地处理这些事件。
2) 在 SHChangeNotification_Lock 的定义中需要“out”,而不是“var”或简单的指针引用。我没有任何内容表明“out”具体的作用,所以如果有人可以提供帮助,请帮忙。固定定义如下。
3)在我的文档(包括源示例)中,它表明某些事件类型可能有多个pidl。这使得质量控制报告中建议的更正无效。使用原始定义的问题可能是如建议的那样。这不太正确。参考上面的定义,您会看到不同的类型。该定义如下。没有事件有超过两个参数,所以这就足够了。
现在它按照我的预期工作了。我只需要找到两个 parm 事件的有效列表并编写代码以使其更清晰(即,如果已知无效,则不引用第二个pitemid)。下面是我的测试程序的一些输出示例来说明:
感谢大家的帮助!
Okay, I got this answered. A number of problems all over the board, actually:
1) I had things wrong when it comes to IsItemNotificationEvent. To have valid PIDLs, I needed to make sure that the event WASN'T one of those, because no PIDL is valid to process against those.
2) "out" was necessary in the definition to SHChangeNotification_Lock and not "var" or a simple pointer reference. I don't have anything that indicates what "out" does specifically, so if anyone can help, please do. The fixed definition is below.
3) In my documentation (including the source samples), it indicates that multiple pidls are possible for some event types. Which makes the suggested correction invalid in the QC report. The problem with using the original definition is probably as suggested. It's not quite right. Reference the definition above, and you'll see a different type. That definition is below. No events have more than two parms, so it would suffice.
Got it working as I expect it to now. I just need to find a valid list of two parm events and code in to make it a little cleaner (i.e. not reference the second pitemid if known to be invalid). Some samples of output from my test program are below to illustrate:
Thanks all for your help!