-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement SetLastError ourselves when allowMarshaling is false #600
Comments
@lonitra is this important for the winforms cswin32 project? |
I had not seen this attribute before, and it is not present in our codebase, so to my knowledge, I don't think so. |
Does winforms want to use generated code from cswin32 without marshalling? |
@lonitra WinForms uses |
@elachlan Would you be interested in implementing this? We'd need to do something fancy like LibraryImport does to ensure that we get to call GetLastError before the runtime has a chance on that same thread to call anything else that might call SetLastError. |
I can give it a go. Do you know where I can find the .net implementation of it when using library import? I figure I'd just check the setting and after the pinvoke call, add a call to GetLastError, then throw a Am I missing something? |
Thanks!
When the CLR emits the interop code for a I can't find it in the documentation now, but I believe when the CLR does do marshaling, it isn't exactly guaranteed that after an interop call completes that the CLR hasn't injected other interop calls for its own purposes, in which case the 'last error' may be overwritten by the time the first interop call returns. This means that if CsWin32 generates a method that tries to imitate the CLR's marshaling behavior, there isn't a guarantee that our own call to GetLastError will actually return the value from our own native call -- it might be from a CLR engine's call into Win32. So we have to be careful. Now, by targeting net7.0 and using the internal static partial int GetTickCount()
{
int __lastError;
int __retVal;
{
System.Runtime.InteropServices.Marshal.SetLastSystemError(0);
__retVal = __PInvoke();
__lastError = System.Runtime.InteropServices.Marshal.GetLastSystemError();
}
System.Runtime.InteropServices.Marshal.SetLastPInvokeError(__lastError);
return __retVal;
// Local P/Invoke
[System.Runtime.InteropServices.DllImportAttribute("Kernel32", EntryPoint = "GetTickCount", ExactSpelling = true)]
static extern unsafe int __PInvoke();
} Notice how the But here's the rub: while net7.0 evidently guarantees the correctness of this code, I don't think the CLR (e.g. net472) makes the same guarantee. Remember how I said the call into the extern method may inadvertently trigger the CLR to make other native calls before it returns? But I guess with Core CLR it's safe. Well, that and perhaps because LibraryImport always generates enough code to ensure that marshaling never occurs. So... I think CsWin32 should emit this same kind of wrapper, but only when these conditions are true:
Still want to tackle it, @elachlan? |
Cool! Thanks for the write up, that is super helpful. Don't assign it to me just yet. I might focus on a couple of other issues first. But It seems mostly straight forward. I will see if I get time this week. |
Would it be possible to at least not generate the SetLastError when allowMarshalling is false? I can write the surrounding code myself but SetLastError is making CsWIn32 unusable in project with marshalling disabled. |
@AArnott any chance a beta build could be pushed sometime soon? Would love to test this particular feature out. 👀 |
I'd love for you to try it out. Would it work for you to consume the daily builds, per these instructions? |
|
Good news: Updating CsWin32 to |
It's worth noting that CsWin32's support for disabling marshalling won't actually be usable with
DisableRuntimeMarshallingAttribute
yet because ofSetLastError
: https://docs.microsoft.com/en-us/dotnet/standard/native-interop/disabled-marshalling#disabled-featuresOriginally posted by @alexrp in #593 (comment)
The text was updated successfully, but these errors were encountered: