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
2k stars 84 forks source link

IGroupPolicyObject is missing return values #995

Closed Nuklon closed 1 year ago

Nuklon commented 1 year ago

Actual behavior

For example, OpenLocalMachineGPO returns void, but this should return one of the COM error codes defined in the Platform SDK header file WinError.h. It's correct in metadata.

Expected behavior

Generate correctly.

Repro steps

  1. NativeMethods.txt content:
    IGroupPolicyObject

Context

AArnott commented 1 year ago

CsWin32 defaults to non-preserve sig for COM methods. A failing HRESULT will result in a thrown COMException with a property retaining the original error code. If you prefer to check a return value instead, see https://github.com/microsoft/CsWin32#customizing-generated-code for the preserveSig setting where in your NativeMethods.json file you can set specific methods or COM interfaces to use preserveSig instead.

Nuklon commented 1 year ago

Thanks, that seems to work. Now to find out how to create an instance of IGroupPolicyObject ☀️

Nuklon commented 1 year ago

Thanks, that seems to work. Now to find out how to create an instance of IGroupPolicyObject ☀️

Ah, that doesn't work right now due to allowMarshaling being set to false.

AArnott commented 1 year ago

Why are you setting allowMarshaling to false? (there are legit reasons, but preservesig isn't one of them). I don't know why preserveSig false would prevent you from getting an instance of that interface. I don't know how to get an instance of that interface anyway (win32 is a big API and I certainly don't know all of it), but generally allowMarshaling:false shouldn't make anything impossible -- though maybe less convenient.

Nuklon commented 1 year ago

Because of this: https://github.com/microsoft/CsWin32/issues/992 With allowMarshaling on false you cannot cast it to another type. I'll give it a think on how do get around it.

AArnott commented 12 months ago

With allowMarshaling on false you cannot cast it to another type.

Can you elaborate on this? I'm not aware of such a limitation, although the syntax may be slightly different.

Nuklon commented 12 months ago

Continuing with IGroupPolicyObject.


    [ComImport, Guid("EA502722-A23D-11d1-A7D3-0000F87571E3")]
    public class GroupPolicyObject
    {

    }
IGroupPolicyObject a = (IGroupPolicyObject)new GroupPolicyObject();

This would be the normal route. That works if you have allowMarshaling set to true (the default). But when you set it to false, you cannot cast it anymore as IGroupPolicyObject is not an interface. You can create a new instance of IGroupPolicyObject as it's a struct, but that created type doesn't do anything. It probably needs some kind of activation but I don't know what to activate.

Nuklon commented 12 months ago

It's probably because lpVtbl is 0, but I don't have any idea on how to set this. On .NET Framework PopulateVTable isn't available, and on .NET Core you cannot assign that to an isntance. But perhaps there's another way I don't know about.

AArnott commented 12 months ago

when marshaling is disabled, an interface is still generated. So the following code compiles (when combined with CsWin32 generated IGroupPolicyObject:

unsafe
{
    object a = new GroupPolicyObject();
    IGroupPolicyObject.Interface? i = (IGroupPolicyObject.Interface)a;
    Console.WriteLine(a);
}

[ComImport, Guid("EA502722-A23D-11d1-A7D3-0000F87571E3")]
public class GroupPolicyObject
{
}

That said, it doesn't run properly. The cast to the interface fails. My best guess is that the GroupPolicyObject class you declared is perhaps decorated with the wrong GUID so it's creating an object that doesn't implement the interface based on a matching GUID.

Nuklon commented 11 months ago

Hmm, I missed that one, thanks! It's the right GUID, but you need to annotate "main" with [STAThread], then you cast it correctly.