microsoft / CsWin32

A source generator to add a user-defined set of Win32 P/Invoke methods and supporting types to a C# project.
MIT License
2.07k stars 87 forks source link

GetApplicationUserModelId - wrong function signature #1106

Closed DerMagereStudent closed 8 months ago

DerMagereStudent commented 9 months ago

I want to read out the AUMID of a process. But this is not possible because the created Pinvoke takes in the PWSTR by value.

Actual behavior

This is the created method:

/// <summary>Gets the application user model ID for the specified process.</summary>
/// <param name="hProcess">A handle to the process. This handle must have the <b>PROCESS_QUERY_LIMITED_INFORMATION</b> access right. For more info, see <a href="https://docs.microsoft.com/windows/desktop/ProcThread/process-security-and-access-rights">Process Security and Access Rights</a>.</param>
/// <param name="applicationUserModelIdLength">On input, the size of the  <i>applicationUserModelId</i> buffer, in wide characters. On success, the size of the buffer used, including the null terminator.</param>
/// <param name="applicationUserModelId">A pointer to a buffer that receives the application user model ID.</param>
/// <returns>
/// <para>If the function succeeds it returns <b>ERROR_SUCCESS</b>. Otherwise, the function returns an error code. The possible error codes include the following. </para>
/// <para>This doc was truncated.</para>
/// </returns>
/// <remarks>For info about string size limits, see <a href="https://docs.microsoft.com/windows/desktop/appxpkg/identity-constants">Identity constants</a>.</remarks>
[DllImport("KERNEL32.dll", ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern unsafe winmdroot.Foundation.WIN32_ERROR GetApplicationUserModelId(winmdroot.Foundation.HANDLE hProcess, uint* applicationUserModelIdLength, winmdroot.Foundation.PWSTR applicationUserModelId);

Expected behavior

I would expect the method to take in

  1. winmdroot.Foundation.PWSTR* applicationUserModelId
  2. ref winmdroot.Foundation.PWSTR applicationUserModelId
  3. out winmdroot.Foundation.PWSTR applicationUserModelId

Repro steps

  1. NativeMethods.txt content:
    
    // Classes

// Interfaces

// Functions OpenProcess GetApplicationUserModelId CloseHandle


4. `NativeMethods.json` content (if present):
no json

5. Any of your own code that should be shared?

This code tries to read out the AUMID of `Microsoft Films & TV` currently running with `Process-Id 8552U` (hardcoded). I would expect `Microsoft.ZuneVideo_8wekyb3d8bbwe!Microsoft.ZuneVideo` to be read out but after execution pAumid is still a nullptr

using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.System.Threading;

public static class Program { public static async Task Main(string[] args) { var processHandle = PInvoke.OpenProcess(PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_LIMITED_INFORMATION, false, 8552U);

    string aumid;
    unsafe {
        var size = 256U;
        var pAumid = new PWSTR();
        PInvoke.GetApplicationUserModelId(processHandle, &size, pAumid);
        aumid = pAumid.ToString();
    }

    PInvoke.CloseHandle(processHandle);
    Console.WriteLine(aumid);
}

}



### Context

- CsWin32 version: `0.3.49-beta`
- Win32Metadata version (if explicitly set by project): /
- Target Framework: `net6.0-windows` or `net6.0-windows10.0.20348.0`
- `LangVersion`: /
AArnott commented 8 months ago

This is what I see CsWin32 generating:

static extern unsafe winmdroot.Foundation.WIN32_ERROR GetApplicationUserModelId(
  winmdroot.Foundation.HANDLE hProcess,
  uint* applicationUserModelIdLength,
  winmdroot.Foundation.PWSTR applicationUserModelId);

And this is the C header:

LONG GetApplicationUserModelId(
  [in]      HANDLE hProcess,
  [in, out] UINT32 *applicationUserModelIdLength,
  [out]     PWSTR  applicationUserModelId
);

Those look equivalent to me.

From what you describe to have expected, I think you misunderstand the PWSTR type, which is a struct that contains a pointer -- equivalant to PWSTR in C. It is not like the string type in C#.

The reason your code is failing is because you haven't initialized the 3rd argument (the PWSTR) to point to a buffer. The docs for the function describe this parameter to be:

A pointer to a buffer that receives the application user model ID.

But you haven't pointed at a buffer. You just new'd it up and passed it in (with the implied null pointer inside). Just like in C, you should allocate a buffer, initialize your PWSTR to point at it, and then pass it in.