在Delphi中正确实现Windows API SHQueryUserNotificationState()函数

时间:2015-08-24 01:47:26

标签: delphi winapi

在我的旧shellapi.pas(32位)中未指定MSDN中指定的SHQueryUserNotificationState函数。此功能在Vista中引入。在网上搜索找到Pascal实现但是找不到它。

在C ++(MSDN)中:

HRESULT SHQueryUserNotificationState(
  _Out_ QUERY_USER_NOTIFICATION_STATE *pquns
);

typedef enum  { 
  QUNS_NOT_PRESENT              = 1,
  QUNS_BUSY                     = 2,
  QUNS_RUNNING_D3D_FULL_SCREEN  = 3,
  QUNS_PRESENTATION_MODE        = 4,
  QUNS_ACCEPTS_NOTIFICATIONS    = 5,
  QUNS_QUIET_TIME               = 6,
  QUNS_APP                      = 7
} QUERY_USER_NOTIFICATION_STATE;

我已经拥有的东西(pascal 32bit):

function SHQueryUserNotificationState( p : Pointer ) : HRESULT; stdcall; external shell32 name 'SHQueryUserNotificationState';

代码来调用它:

var
 i : LongInt;

begin
 if( SHQueryUserNotificationState( @i ) = S_OK ) then
 begin
  writeln( i );
 end;

end;

这是完美的工作(返回预期的值),但我想知道指针的类型。它似乎是一个32位变量的指针,但想知道这是否正确(签名/未签名),以避免其他Windows操作系统/系统(现在在Windows 7 64位上运行)的问题,我想知道它是当然。有人能告诉我这个函数的正确实现吗?

MSDN上的功能说明: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762242%28v=vs.85%29.aspx

编辑:指向DWORD的指针?

//////////////////以下不是问题的一部分///////////////

EDIT2 :(示例)我制作的代码

因为它要求应用程序可以在低于Vista的操作系统上运行(并且并不总是需要),所以我使该功能可选(动态分配)。根据接受的答案,这是最终结果:

........
type
  // See also: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762533%28v=vs.85%29.aspx
 TUserNotifcationState = (unsError,           // -. Cannot not obtain info, mostly error running on Windows lower than Vista
                          unsUnknown,         // -. Working, but unknown future feature value returned by WinAPI func.
                          unsNotPresent,      // 1. User not present, screensave active or fast user switch in progress
                          unsFullScreen,      // 2. Windows run an application in full screen mode
                          unsDirectX,         // 3. A full screen Direct3D/DirectX is running
                          unsPresentation,    // 4. Activated presentation and blocks notification and popup messages
                          unsNormal,          // 5. User runs Windows normally, accept messages and popup messages
                          unsPresentLocked,   // 6. Windows 7 and higher, present but logging in
                          unsWindowsStoreApp  // 7. Windows 8 and higher, user runs Windows Store app (metro app)
                         );
TUserNotificationStateFunc = function( var iResult : Integer ) : HRESULT; stdcall;

.............

const
  FShell32Handle : THandle = 0;


.............

function shellGetUserNoticationState() : TUserNotifcationState;
const
 fFunc   : TUserNotificationStateFunc = nil;
 bErr    : Boolean = FALSE;

var
 cResult : Integer;

begin
 Result:=unsError;
 if( bErr ) then
  Exit;

 if( NOT Assigned( fFunc )) then
 begin
  if( FShell32Handle < 0 ) then
   Exit;

  if( FShell32Handle = 0 ) then
   begin
    FShell32Handle:=LoadLibrary( shell32 );
    bErr:=( FShell32Handle <= 0 );
    if( bErr ) then
     Exit;
   end;

   try 
    fFunc:=getProcAddress( FShell32Handle, 'SHQueryUserNotificationState' );
   except
    bErr:=TRUE;
   end;

   bErr:=(( bErr ) or ( NOT Assigned( fFunc )));
 end;

 if( NOT bErr ) then
  begin
   cResult:=high( Cardinal ); // set to abnormal range
   try
    bErr:=( fFunc( cResult ) <> S_OK );
   except
    bErr:=TRUE;
   end;
 end; 

 if( bErr ) or ( cResult < 1 ) or ( cResult >= 50 {50 = future options, but not supported in this compile} ) then
  Exit;

 // Future options higher than latest Win8 additions not supported
 // in this compile. 
 if( cResult > 7 ) then
  begin
   Result:=unsUnknown;
   Exit;
  end;

 Result:=TUserNotifcationState( Byte( cResult )+1 );
end;

.............

initialization
finalization
 if( FShell32Handle > 0 ) then
   FreeLibrary( FShell32Handle );
end.

由于动态调用Windows API函数,因此当DLL中不存在API函数时,应用程序将始终运行并且不会中断。 在低于Vista的OS上运行代码时,该函数始终返回unsError。在高于Windows 8或更新版本的操作系统上运行代码并添加操作系统中的新枚举值时,它将返回unsUnknown。

1 个答案:

答案 0 :(得分:4)

Delphi XE4中此API的声明声明该参数是指向整数的指针(实际上,整数> 整数 >,这相同的事情。)

声明不直接使用整数,但声明为所涉及的枚举命名的类型别名:

type
  QUERY_USER_NOTIFICATION_STATE = Integer; 

function SHQueryUserNotificationState(var pquns: QUERY_USER_NOTIFICATION_STATE): HResult; stdcall;

枚举(在C / C ++中)的实际大小就我所知,并且依赖于实现&#39;在这种情况下,相关的实现是Windows API。据我所知,这意味着整数,这与Delphi XE4声明一致。这是否意味着Windows API中的所有枚举保证大小为整数或不...我想是的。

无论如何,在这种特定情况下,Delphi XE4 API头是在参数是对 Integer (32位有符号整数)的引用的基础上声明的。

您使用 LongInt 与使用整数完全相同。但是,根据Delphi XE4声明,我将消除使用无类型指针并使用正确键入的 out var 参数。

RE:DWORD?

DWORD 类型相当于 Cardinal (无符号32位整数)。

由于这正式是一个 out 参数(表示API不会使用通过此参数传递给它的任何值),这是API的重要内容。我们的观点是你提供了一个指向正确大小的变量的指针供它写入(这就是为什么无类型指针是个坏主意)。在这种情况下,32位。那么你如何解释那些32位的API在你的位置。

在这种情况下,由于枚举没有签名值且所有涉及的值(轻松地)在整数的正范围内,您可以使用整数 Cardinal 与您的应用程序代码的角度没有任何明显的区别。

然而,对于我希望的显而易见的原因,我会坚持正式的类型。 :)

警告开发者: Delphi API翻译并不总是100%可靠,但除非并且直到证明其他方式,它们至少是一个良好的起点,我没有理由认为这是错误的