mono / CppSharp

Tools and libraries to glue C/C++ APIs to high-level languages
MIT License
3.12k stars 512 forks source link

Function with output pointer parameters #1381

Open PeterDraex opened 4 years ago

PeterDraex commented 4 years ago
Brief Description

I'm trying to generate wrapper for the following function:

HRESULT
WINAPI
WebAuthNAuthenticatorGetAssertion(
    _In_        HWND                                                hWnd,
    _In_        LPCWSTR                                             pwszRpId,
    _In_        PCWEBAUTHN_CLIENT_DATA                              pWebAuthNClientData,
    _In_opt_    PCWEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS      pWebAuthNGetAssertionOptions,
    _Outptr_result_maybenull_ PWEBAUTHN_ASSERTION                   *ppWebAuthNAssertion);

As you see, this function has out parameter of type PWEBAUTHN_ASSERTION*.

The following managed code is generated for this function:

public static int WebAuthNAuthenticatorGetAssertion(
   global::System.IntPtr hWnd,
   string pwszRpId,
   global::WebAuthN.WEBAUTHN_CLIENT_DATA pWebAuthNClientData,
   global::WebAuthN.WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS pWebAuthNGetAssertionOptions,
   global::WebAuthN.WEBAUTHN_ASSERTION ppWebAuthNAssertion)
{
    var __arg0 = (IntPtr)hWnd;
    var __arg2 = ReferenceEquals(pWebAuthNClientData, null) ? global::System.IntPtr.Zero : pWebAuthNClientData.__Instance;
    var __arg3 = ReferenceEquals(pWebAuthNGetAssertionOptions, null) ? global::System.IntPtr.Zero : pWebAuthNGetAssertionOptions.__Instance;
    var ____arg4 = ReferenceEquals(ppWebAuthNAssertion, null) ? global::System.IntPtr.Zero : ppWebAuthNAssertion.__Instance;
    var __arg4 = new global::System.IntPtr(&____arg4);
    var __ret = __Internal.WebAuthNAuthenticatorGetAssertion(__arg0, pwszRpId, __arg2, __arg3, __arg4);
    return __ret;
}

As you see, the output parameter generates parameter of class-type _WEBAUTHNASSERTION.

Call of this function works, but when I try to access the output object, System.AccessViolationException is thrown.

What would be the correct type of this output parameter in generated code? How can that be achieved?

OS: Windows 10 64-bit

Used headers

https://github.com/microsoft/webauthn/blob/master/webauthn.h

Used settings

Target: MSVC/GCC/Clang

Other settings:

driver.ParserOptions.ForceClangToolchainLookup = true;
driver.ParserOptions.Verbose = true;
var options = driver.Options;
options.GeneratorKind = GeneratorKind.CSharp;
options.Verbose = true;
tritao commented 4 years ago

You should also include the function body of the generated code, so we can look at how its being marshalled.

Anyway, since this is an out parameter, you could try something like:

ctx.FindFunction("WebAuthNAuthenticatorGetAssertion").First().FindParameter("ppWebAuthNAssertion").Usage = ParameterUsage.Out;

Or use SetFunctionParameterUsage, see https://github.com/mono/CppSharp/blob/7acd5809148ee7bdf843328d8e96f0b07b5bdf96/src/Generator/Library.cs#L269.

PeterDraex commented 4 years ago

@tritao

I've tried adding your suggestions to Preprocess(). They both result in this code:

        public static int WebAuthNAuthenticatorGetAssertion(global::System.IntPtr hWnd, string pwszRpId, global::WebAuthN.WEBAUTHN_CLIENT_DATA pWebAuthNClientData, global::WebAuthN.WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS pWebAuthNGetAssertionOptions, out global::WebAuthN.WEBAUTHN_ASSERTION ppWebAuthNAssertion)
        {
            var __arg0 = (IntPtr)hWnd;
            var __arg2 = ReferenceEquals(pWebAuthNClientData, null) ? global::System.IntPtr.Zero : pWebAuthNClientData.__Instance;
            var __arg3 = ReferenceEquals(pWebAuthNGetAssertionOptions, null) ? global::System.IntPtr.Zero : pWebAuthNGetAssertionOptions.__Instance;
            var ____arg4 = ReferenceEquals(ppWebAuthNAssertion, null) ? global::System.IntPtr.Zero : ppWebAuthNAssertion.__Instance;
            var __arg4 = new global::System.IntPtr(&____arg4);
            var __ret = __Internal.WebAuthNAuthenticatorGetAssertion(__arg0, pwszRpId, __arg2, __arg3, __arg4);
            return __ret;
        }

The compiler has two problems with this code:

Any ideas?

PeterDraex commented 4 years ago

The following code works correctly!

public static int WebAuthNAuthenticatorGetAssertion(global::System.IntPtr hWnd, string pwszRpId, global::WebAuthN.WEBAUTHN_CLIENT_DATA pWebAuthNClientData, global::WebAuthN.WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS pWebAuthNGetAssertionOptions, out global::WebAuthN.WEBAUTHN_ASSERTION ppWebAuthNAssertion)
{
    var __arg0 = (IntPtr)hWnd;
    var __arg2 = ReferenceEquals(pWebAuthNClientData, null) ? global::System.IntPtr.Zero : pWebAuthNClientData.__Instance;
    var __arg3 = ReferenceEquals(pWebAuthNGetAssertionOptions, null) ? global::System.IntPtr.Zero : pWebAuthNGetAssertionOptions.__Instance;
    var __ret = __Internal.WebAuthNAuthenticatorGetAssertion(__arg0, pwszRpId, __arg2, __arg3, out IntPtr __arg4); // requires addition of "out" to method header

    ppWebAuthNAssertion = global::WebAuthN.WEBAUTHN_ASSERTION.__CreateInstance(__arg4);

    return __ret;
}

Now the question is, how to get CppSharp, to generate it.