Skip to content

Conversation

@elinor-fung
Copy link
Member

@elinor-fung elinor-fung commented Nov 17, 2020

  • Add functions for getting/setting system error (Get/SetLastSystemError) and setting P/Inovke error (SetLastWin32Error) to Ancillary.Interop
  • Update generated stub code to clear the system error before invoke, get the system error after and update the stored P/Invoke error

cc @AaronRobinsonMSFT @jkoritzinsky

Examples:

SetLastError=true, blittable signature
public static partial int SetError(int error, byte shouldSetError)
{
    unsafe
    {
        int __retVal = default;
        int __lastError = default;
        //
        // Invoke
        //
        {
            System.Runtime.InteropServices.MarshalEx.SetLastSystemError(0);
            __retVal = SetError__PInvoke__(error, shouldSetError);
            __lastError = System.Runtime.InteropServices.MarshalEx.GetLastSystemError();
        }

        System.Runtime.InteropServices.MarshalEx.SetLastWin32Error(__lastError);
        return __retVal;
    }
}

[System.Runtime.InteropServices.DllImportAttribute("NativeExportsNE", EntryPoint = "set_error")]
extern private static unsafe int SetError__PInvoke__(int error, byte shouldSetError);
SetLastError=true, non-blittable signature
public static partial string SetError_NonBlittableSignature(int error, bool shouldSetError, string errorString)
{
    unsafe
    {
        byte __shouldSetError_gen_native = default;
        ushort *__errorString_gen_native = default;
        string __retVal = default;
        ushort *__retVal_gen_native = default;
        int __lastError = default;
        //
        // Marshal
        //
        __shouldSetError_gen_native = (byte)(shouldSetError ? 1 : 0);
        //
        // Invoke
        //
        fixed (char *__errorString_gen_native__pinned = errorString)
        {
            System.Runtime.InteropServices.MarshalEx.SetLastSystemError(0);
            __retVal_gen_native = SetError_NonBlittableSignature__PInvoke__(error, __shouldSetError_gen_native, (ushort *)__errorString_gen_native__pinned);
            __lastError = System.Runtime.InteropServices.MarshalEx.GetLastSystemError();
        }

        //
        // Unmarshal
        //
        __retVal = __retVal_gen_native == null ? null : new string ((char *)__retVal_gen_native);
        System.Runtime.InteropServices.MarshalEx.SetLastWin32Error(__lastError);
        return __retVal;
    }
}

[System.Runtime.InteropServices.DllImportAttribute("NativeExportsNE", EntryPoint = "set_error_return_string")]
extern private static unsafe ushort *SetError_NonBlittableSignature__PInvoke__(int error, byte shouldSetError, ushort *errorString);

@elinor-fung elinor-fung added the area-DllImportGenerator Source Generated stubs for P/Invokes in C# label Nov 17, 2020
Copy link
Member

@AaronRobinsonMSFT AaronRobinsonMSFT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Looks like we found the owner for proposing these new APIs :-)

I assume we need/want:

  • SetLastSystemError(), even though we could P/Invoke into that ourselves - see example in PR.
  • SetLastWin32Error(), even though we could use reflection to get at the call - see example in PR.

@jkotas
Copy link
Member

jkotas commented Nov 21, 2020

        fixed (char *__errorString_gen_native__pinned = errorString)
        {
            System.Runtime.InteropServices.MarshalEx.SetLastSystemError(0);
            __retVal_gen_native = SetError_NonBlittableSignature__PInvoke__(error, __shouldSetError_gen_native, (ushort *)__errorString_gen_native__pinned);
            System.Runtime.InteropServices.MarshalEx.SetLastWin32Error(System.Runtime.InteropServices.MarshalEx.GetLastSystemError());
        }

        //
        // Unmarshal
        //
        __retVal = __retVal_gen_native == null ? null : new string ((char *)__retVal_gen_native);
        return __retVal;

Is the last error guaranteed to be left intact by all the unmarshalling code? Should SetLastWin32Error be called right before returning instead?

@elinor-fung
Copy link
Member Author

Should SetLastWin32Error be called right before returning instead?

Ahh, yeah. Good call.

@elinor-fung
Copy link
Member Author

Interestingly, the built-in system today can allow writing over the error code in unmarshalling (tried this quickly with a custom marshaler does a Console.WriteLine in its unmarashalling function).

@jkotas
Copy link
Member

jkotas commented Nov 21, 2020

Yes, the built-in system has a patch work of workarounds like this that I am sure has many holes.

@elinor-fung elinor-fung merged commit b36b0b8 into dotnet:feature/DllImportGenerator Nov 30, 2020
@elinor-fung elinor-fung deleted the setLastError branch November 30, 2020 18:41
jkoritzinsky pushed a commit to jkoritzinsky/runtime that referenced this pull request Sep 20, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-DllImportGenerator Source Generated stubs for P/Invokes in C#

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants