Search code examples
c#delphikernel32desktop-bridge

How to detect Universal Windows Platform (UWP) in Delphi


To get an application written in Delphi to the Windows Store, I have to disable internal update mechanisms. For example things like "Check for updates" and such things are forbidden via Store policies 10.2.5

So, I found the C# helper function IsRunningAsUwp() in the DesktopBridgeHelpers project code. My plan is to convert that helper to Delphi code, but the packageFullName string is always empty here, even if I run the app through a DesktopBridge converted project:

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName);

public bool IsRunningAsUwp()
{
    if (IsWindows7OrLower)
    {
        return false;
    }
    else
    {
        int length = 0;
        StringBuilder sb = new StringBuilder(0);
        int result = GetCurrentPackageFullName(ref length, sb);
        sb = new StringBuilder(length);
        result = GetCurrentPackageFullName(ref length, sb);

        return result != APPMODEL_ERROR_NO_PACKAGE;
    }
}

My current (not working) Delphi conversion looks like this:

function GetCurrentPackageFullName(out Length: DWORD; out fullName: String): DWORD; stdcall; external kernel32 delayed;

function RunningAsUwp: Boolean;
const
  APPMODEL_ERROR_NO_PACKAGE = 15700;
var
  PackageName: String;
  PackageLen, PackageResult: DWORD;
begin
  if (Win32MajorVersion < 6) or ((Win32MajorVersion = 6) and (Win32MinorVersion <= 1)) then begin
    // Windows 7 or older
    Result := False;
  end else begin
    // Windows 10, but not necessarily a Store App
    PackageLen := 0;
    SetLength(PackageName, 1024);
    PackageResult := GetCurrentPackageFullName(PackageLen, PackageName);
    showmessage(PackageName); // <= always empty
    if PackageResult = APPMODEL_ERROR_NO_PACKAGE then begin
      Result := False;
    end else if not String(PackageName).IsEmpty then begin
      Result := True;
    end else begin
      Result := False;
    end;
  end;
end;

I get no other errors, just that empty PackageName, when running through an installed appx package.


Solution

  • The function import is incorrect. It should be

    function GetCurrentPackageFullName(
        out Len: Cardinal; 
        Name: PWideChar
    ): Integer; stdcall; external kernel32 delayed;
    

    And then to call it you do this:

    var
      Len: Cardinal;
      Name: string;
      ErrorCode: Integer;
    ....
    Len := 0;
    ErrorCode := GetCurrentPackageFullName(Len, nil);
    if ErrorCode <> ERROR_INSUFFICIENT_BUFFER then
      RaiseLastOSError(ErrorCode);
    SetLength(Name, Len-1);
    ErrorCode := GetCurrentPackageFullName(Len, PChar(Name));
    if ErrorCode <> ERROR_SUCCESS then
      RaiseLastOSError(ErrorCode);
    

    You might want to handle errors differently, but I'm sure you can work it out.

    Note that the C# code has some errors which I have not reproduced.