Skip to content
This repository was archived by the owner on Nov 1, 2020. It is now read-only.
This repository was archived by the owner on Nov 1, 2020. It is now read-only.

[Windows Forms] Form.Close crash application #7994

Closed

Description

@kant2002

If I show Form using Form.Show or Form.ShowDialog then after close form, application crashed.

Activity

  1. jkotas commented on Feb 18, 2020

    @jkotas
    Member

    Could you please share the code to reproduce this crash (e.g. a scratch github repo that one can just run dotnet publish -c Release -r win-x64 to get a repro), and stacktrace of the crash that you see?

  2. kant2002 commented on Feb 18, 2020

    @kant2002
    ContributorAuthor

    Sample as simple as application which create new form. and I manually close that form. I have slightly more complicated example, and this is exception message which I manage to capture.

    Method '[System.Windows.Forms]System.Windows.Forms.UnsafeNativeMethods.UiaReturnRawElementProvider(HandleRef,native int,native int,IRawElementProviderSimple)' requires marshalling that is not yet supported by this compiler.
    

    It seems to be COM related ☹️ . See https://github.com/kant2002/CoreRTWinFormsTestBed for application where I experience issue. Press "Press Me" button. Close opened form.

  3. MichalStrehovsky commented on Feb 18, 2020

    @MichalStrehovsky
    Member

    Can you check if there's any exceptions being thrown before going down that paths? (Here's the doc on how to set up breakpoints on exceptions just in case, but I guess you know about it).

    From a quick look at WinForms source, this is already related to the error window, so I wonder if this is just WinForms trying to pop a dialog because something before that went wrong.

  4. kant2002 commented on Feb 18, 2020

    @kant2002
    ContributorAuthor

    Before that was System.Drawing.NativeMethods+BITMAPINFOHEADER is missing structure marshalling data. To enable structure marshalling data, add a MarshalStructure directive to the application rd.xml file. For more information, please visit http://go.microsoft.com/fwlink/?LinkID=393965 but its happens during startup of the application and once form loaded, everything working fine. After these exceptions I press button, and again everything is fine. Only on Form close exception System.Windows.Forms.UnsafeNativeMethods.UiaReturnRawElementProvider happens

  5. MichalStrehovsky commented on Feb 19, 2020

    @MichalStrehovsky
    Member

    Callstack:

    >	WinForms.exe!System_Windows_Forms_System_Windows_Forms_UnsafeNativeMethods__UiaReturnRawElementProvider�()	Unknown
     	WinForms.exe!System_Windows_Forms_System_Windows_Forms_Control__ReleaseUiaProvider�()	Unknown
     	WinForms.exe!System_Windows_Forms_System_Windows_Forms_Control__WmDestroy�()	Unknown
     	WinForms.exe!System_Windows_Forms_System_Windows_Forms_Control__WndProc�()	Unknown
     	WinForms.exe!System_Windows_Forms_System_Windows_Forms_ScrollableControl__WndProc�()	Unknown
     	WinForms.exe!System_Windows_Forms_System_Windows_Forms_ContainerControl__WndProc�()	Unknown
     	WinForms.exe!System_Windows_Forms_System_Windows_Forms_Form__WndProc�()	Unknown
     	WinForms.exe!System_Windows_Forms_System_Windows_Forms_Control_ControlNativeWindow__OnMessage�()	Unknown
     	WinForms.exe!System_Windows_Forms_System_Windows_Forms_Control_ControlNativeWindow__WndProc�()	Unknown
     	WinForms.exe!System_Windows_Forms_System_Windows_Forms_NativeWindow__Callback�()	Unknown
    

    We are actually in luck: the COM parameter is a null reference. We can marshal a null reference. It marshals into a null pointer.

    Adding a COM marshaller that can only marshal a null (and throws for everything else) shouldn't be too difficult.

  6. kant2002 commented on Mar 5, 2020

    @kant2002
    ContributorAuthor

    I try to debug this issue, to better understand how CoreRT make it's magic and have a set of questions

    • If I properly understand error which I seeing coming because PInvokeILEmitter cannot emit methods which has MethodImplAttributes.PreserveSig.
    • This part of runtime is not well known for me, but I always thought that this attribute flag not only for COM interop (I may be wrong here).

    Next set of questions coming from my attempt to understand magic.
    Quick glance on the PInvokeILEmitter lead me to thinking that you are make PInvoke magic by emitting IL.

    • Can I assume that this is some limited subset of IL ?
    • Can I assume that this IL will be lately transformed to native code?
    • Does this mean that all marshalling in CoreRT is just custom IL code which follow the rules of runtime as explained in docs.
  7. MichalStrehovsky commented on Mar 5, 2020

    @MichalStrehovsky
    Member

    If I properly understand error which I seeing coming because PInvokeILEmitter cannot emit methods which has MethodImplAttributes.PreserveSig.

    PreserveSig is one of the things CoreRT doesn't support. This is a pretty rare flag and mostly matters in COM. I don't think it's a problem for the Forms.Close crash.

    I'm pretty sure that in this case, the compiler is actually throwing because we can't determine the marshaller kind to marshal an interface type (we take this return statement because none of the if above match an interface).

    Yes, P/invoke is done by emitting IL - it's not a limited subset: all IL is available. The IL is then passed to the native compiler (e.g. RyuJIT) to compile into native code.

    It works along the lines of this:

    [DllImport("foo", CharSet = Unicode)]
    extern static void Greet(string name);

    This is converted (within the compiler) into what logically looks like this:

    [DllImport("foo", CharSet = Unicode, EntryPoint="Greet")]
    extern static void rawPinvoke_Greet(char* name);
    
    static void Greet(string name)
    {
        fixed (char* pName = name)
            rawPinvoke_Greet(pName);
    }

    Basically, the marshalling IL generator goes over all parameters/return types, converts them into the representation expected by the native side, and marshals them forward (managed to native) or backward (native to managed, if it's a return value).

    What's missing here is the handling for interfaces. We'll only be able to handle the null value of an interface. The rest is very complex.

    Basically we'll want to convert this:

    [DllImport("foo", CharSet = Unicode)]
    extern static void Greet(IFooer nameProvider);

    Into:

    [DllImport("foo", CharSet = Unicode, EntryPoint="Greet")]
    extern static void rawPinvoke_Greet(IntPtr nameProvider);
    
    static void Greet(IFooer nameProvider)
    {
        if (nameProvider != null)
            throw new NotSupportedException();
        rawPinvoke_Greet(null);
    }
  8. jkotas commented on Mar 18, 2020

    @jkotas
    Member

    If dotnet/runtime#33485 goes through, we are going to have an official API to inject prebuilt COM interop into the app. It can be then used to supply the required COM interop needed by WinForms.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions