0
votes

The SHQueryUserNotificationState function specified at MSDN is not specified in my old shellapi.pas (32bit). This function is introduced in Vista. Searched on the net to find a Pascal implementation but doesn't find it.

In C++ (MSDN):

HRESULT SHQueryUserNotificationState(
  _Out_ QUERY_USER_NOTIFICATION_STATE *pquns
);

and:

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;

What I already have (pascal 32bit):

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

Code to call it:

var
 i : LongInt;

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

end;

This is working perfectly (returns the expected values) but I want to know the type of the pointer. It seems to be pointer to a 32bit variable but want to know if this is correct (signed/unsigned) to avoid problems on other windows OS-es/systems (now run it on Windows 7 64bit), I want to know it to be sure. Can somebody tell me the correct implementation to this function?

Description of the function on MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762242%28v=vs.85%29.aspx

EDIT: Pointer to a DWORD?

////////////////// BELOW NOT A PART OF QUESTION ///////////////

EDIT2: (Example) code I made

Because it's required that the app can be run on OS-es lower than Vista (and is not always required), I made the function optional (dynamicly assign it). Based on the accepted answer, this is the final result:

........
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.

Because the Windows API function is called dynamicly, the app will always run and do not break when the API function not exists in the DLL. When running the code on a OS lower than Vista, the function returns always unsError. When running the code on a OS higher than Windows 8 or a newer future version and a new enum value in the OS is added, it returns unsUnknown.

1

1 Answers

4
votes

The declaration of this API in Delphi XE4 states that the parameter is a pointer to an Integer (actually, a var parameter of type Integer, which amounts to the same thing).

The declaration does not use Integer directly, but declares a type alias named for the enum involved:

type
  QUERY_USER_NOTIFICATION_STATE = Integer; 

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

The actual size of an enum (in C/C++) is as far as I know 'implementation dependent' and the relevant implementation in this case is Windows API. As far as I know, this means Integer, which is consistent with the Delphi XE4 declaration. Whether this means all enum's in Windows APIs are guaranteed to be of size Integer or not.... I think so.

In any event, in this specific case the Delphi XE4 API header is declared on the basis that the parameter is a reference to an Integer (32-bit signed integer).

Your use of a LongInt is exactly equivalent to using Integer. However, I would eliminate the use of an untyped pointer and use a correctly typed out or var parameter, as per the Delphi XE4 declaration.

RE: DWORD ?

Th e DWORD type would be equivalent to a Cardinal (unsigned 32-bit integer).

Since this is formally an out parameter (indicating that the API does not use any value passed to it thru this parameter) the important thing from the API's point of view is that you provide a pointer to a variable of the right size for it to write to (which is why an untyped pointer is a bad idea). In this case, 32-bits. How you interpret what the API places in those 32-bits is then down to you.

In this case since the enum has no signed values and all values involved are (comfortably) within the positive range of an Integer you could use either Integer or Cardinal without any discernible difference from the perspective of your application code.

However, for what I hope are obvious reasons, I would stick to the formal type. :)

Caveat Developor: Delphi API translations are not always 100% reliable, but unless and until proven otherwise they are at least a good starting point and I have no reason to think it is wrong in this case.