Recent

Author Topic: Call Windows Subsystem Linux API  (Read 2296 times)

bubulemaster

  • New Member
  • *
  • Posts: 46
Call Windows Subsystem Linux API
« on: June 11, 2021, 01:42:37 pm »
Hi,

I try call WSL API WslGetDistributionConfiguration (https://docs.microsoft.com/en-us/windows/win32/api/wslapi/nf-wslapi-wslgetdistributionconfiguration).
If I understand right, I need call CoInitializeSecurity before (https://github.com/microsoft/WSL/issues/5824).

I call first InitWsl(), then WslGet(). The WslGetDistributionConfiguration() return value $80040302. I don't find what this code means.

Someone know how to know what $80040302 means ?

Thanks

Code: Pascal  [Select][+][-]
  1. var
  2.   // Creates a suitable variable (data field) for the DLL subroutine
  3.   WslGetDistributionConfiguration : TFunctionWslGetDistributionConfiguration;
  4.   // Creates a handle for the DLL
  5.   LibHandle : THandle;
  6.  
  7. function InitWsl(): boolean;
  8. var
  9.   wslOutput : ansistring;
  10. begin
  11.   Result := false;
  12.  
  13.     // Get the handle of the library to be used
  14.     LibHandle := LoadLibrary(PChar('Api-ms-win-wsl-api-l1-1-0.dll'));
  15.  
  16.     // Checks whether loading the DLL was successful
  17.     if LibHandle <> 0
  18.     then begin
  19.       Pointer(WslGetDistributionConfiguration) := GetProcAddress(LibHandle, 'WslGetDistributionConfiguration');
  20.  
  21.       // Checks whether a valid address has been returned
  22.       if @WslGetDistributionConfiguration <> nil
  23.       then begin
  24.          Result := Succeeded(CoInitializeSecurity(
  25.            nil,
  26.            -1,
  27.            nil,
  28.            nil,
  29.            RPC_C_AUTHN_LEVEL_DEFAULT,
  30.            RPC_C_IMP_LEVEL_IMPERSONATE,
  31.            nil,
  32.            EOAC_STATIC_CLOAKING,
  33.            nil))
  34.       end;
  35.     end;
  36. end;
  37.  
  38. procedure WslGet();
  39. var
  40.     DistributionVersion: LongWord;
  41.     DefaultUID: LongWord;
  42.     WslDistributionFlags: LongWord;
  43.     DefaultEnvironmentVariables: Pointer;
  44.     DefaultEnvironmentVariableCount: LongWord;
  45.     ret: HRESULT;
  46.     s: string;
  47. begin
  48.   ret := WslGetDistributionConfiguration(
  49.       Pchar('Ubuntu-20.04'),
  50.       @DistributionVersion,
  51.       @DefaultUID,
  52.       @WslDistributionFlags,
  53.       @DefaultEnvironmentVariables,
  54.       @DefaultEnvironmentVariableCount);
  55.  
  56.   // ret -> $80040302
  57.  
  58.   s := HexStr(Pointer(ret));
  59. end;
  60.  
  61. initialization
  62.   CoInitialize(nil);
  63.  
  64. finalization
  65.    CoUninitialize();
  66. end.  
  67.  

PascalDragon

  • Hero Member
  • *****
  • Posts: 3191
  • Compiler Developer
Re: Call Windows Subsystem Linux API
« Reply #1 on: June 11, 2021, 03:48:05 pm »
A pity that you didn't also include the declaration of TFunctionWslGetDistributionConfiguration. But if I had to guess I'd say that you declared the distributionName parameter as PChar. However according to the MSDN entry you linked it's declared as PCWSTR, so PWideChar (or simply use PCWSTR as FPC declares that as well). Then you need to use PWideChar('Ubuntu-20.04') (though just 'Ubuntu-20.04' will work just as well).

When using PCWSTR the HRESULT value you mentioned only occurred when I used a distribution that does not exist. With PChar (or PCSTR) the error occurred even with the distribution that works otherwise.

bubulemaster

  • New Member
  • *
  • Posts: 46
Re: Call Windows Subsystem Linux API
« Reply #2 on: June 12, 2021, 03:13:10 pm »
My bad!

You right!

Sorry for missing declaration, I fix like you say:
Code: Pascal  [Select][+][-]
  1.   TFunctionWslGetDistributionConfiguration = function(
  2.     DistributionName: PWideChar;
  3.     DistributionVersion: PLongWord;
  4.     DefaultUID: PLongWord;
  5.     WslDistributionFlags: PLongWord;
  6.     DefaultEnvironmentVariables: PPChar;
  7.     DefaultEnvironmentVariableCount: PLongWord
  8.     ) : HRESULT;  stdcall;
  9.  

Now:
Code: Pascal  [Select][+][-]
  1. function WslGetConfigurationOfDistribution(DistributionName: String): TWslDistribution;
  2. var
  3.     DistributionVersion: LongWord;
  4.     DefaultUID: LongWord;
  5.     WslDistributionFlags: LongWord;
  6.     DefaultEnvironmentVariables: Pointer;
  7.     DefaultEnvironmentVariableCount: LongWord;
  8.     ret: HRESULT;
  9.     s: string;
  10.     DistribName: array of WideChar;
  11. begin
  12.   SetLength(DistribName, Length(DistributionName) + 1);
  13.   StringToWideChar(DistributionName, @DistribName, Length(DistribName));
  14.  
  15.   ret := WslGetDistributionConfiguration(
  16.       @DistribName,
  17.       @DistributionVersion,
  18.       @DefaultUID,
  19.       @WslDistributionFlags,
  20.       @DefaultEnvironmentVariables,
  21.       @DefaultEnvironmentVariableCount);
  22.  
  23.   s := HexStr(Pointer(ret));
  24.  
  25.   Result := TWslDistribution.Create();
  26. end;

Many thanks!

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 9453
  • FPC developer.
Re: Call Windows Subsystem Linux API
« Reply #3 on: June 12, 2021, 03:17:46 pm »
If you have to pass a pointer to an element, don't pass @dynamic_array, because that is the location of the pointer to the dynamic_array.

At least @DistribName suffers from this. To correct it, make sure distribname has non-zero length (should be ok here) and then pass @distribname[0]

PascalDragon

  • Hero Member
  • *****
  • Posts: 3191
  • Compiler Developer
Re: Call Windows Subsystem Linux API
« Reply #4 on: June 13, 2021, 12:42:54 pm »
Now:
Code: Pascal  [Select][+][-]
  1. function WslGetConfigurationOfDistribution(DistributionName: String): TWslDistribution;
  2. var
  3.     DistributionVersion: LongWord;
  4.     DefaultUID: LongWord;
  5.     WslDistributionFlags: LongWord;
  6.     DefaultEnvironmentVariables: Pointer;
  7.     DefaultEnvironmentVariableCount: LongWord;
  8.     ret: HRESULT;
  9.     s: string;
  10.     DistribName: array of WideChar;
  11. begin
  12.   SetLength(DistribName, Length(DistributionName) + 1);
  13.   StringToWideChar(DistributionName, @DistribName, Length(DistribName));
  14.  
  15.   ret := WslGetDistributionConfiguration(
  16.       @DistribName,
  17.       @DistributionVersion,
  18.       @DefaultUID,
  19.       @WslDistributionFlags,
  20.       @DefaultEnvironmentVariables,
  21.       @DefaultEnvironmentVariableCount);
  22.  
  23.   s := HexStr(Pointer(ret));
  24.  
  25.   Result := TWslDistribution.Create();
  26. end;

As marcov said, array of PWideChar is not the same as PWideChar. Don't make your life harder than necessary and simply use PWideChar(UnicodeString(DistributionName)) instead of @DistribName when calling WslGetDistributionConfiguration. The compiler will make sure that it's converted and also cleanup up correctly.

 

TinyPortal © 2005-2018