Question

I have defined the following class using COM to use the IGroupPolicyObject using C#.NET:

 [ComImport, Guid("EA502722-A23D-11d1-A7D3-0000F87571E3")]
    public class GPClass
    {
        // The C# compiler will add a parameterless constructor that we will call          // to create an instance of the COM coclass.
    }


   [ComImport, Guid("EA502723-A23D-11d1-A7D3-0000F87571E3"),  
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]  
    public interface IGroupPolicyObject  
    {  
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords")]  
        void New(  
            [MarshalAs(UnmanagedType.LPWStr)] string domainName,  
            [MarshalAs(UnmanagedType.LPWStr)] string displayName,  
            uint flags);  

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")]  
        void OpenDsgpo(  
            [MarshalAs(UnmanagedType.LPWStr)] string path,  
            uint flags);  

        void OpenLocalMachineGpo(  
            uint flags);  

        void OpenRemoteMachineGpo(  
            [MarshalAs(UnmanagedType.LPWStr)] string computerName,  
            uint flags);  

        void Save(  
            [MarshalAs(UnmanagedType.Bool)] bool machine,  
            [MarshalAs(UnmanagedType.Bool)] bool add,  
            [MarshalAs(UnmanagedType.LPStruct)] Guid extension,  
            [MarshalAs(UnmanagedType.LPStruct)] Guid app);  

        void Delete();  

        void GetName(  
            [MarshalAs(UnmanagedType.LPWStr)] StringBuilder name,  
            int maxLength);  

        void GetDisplayName(  
            [MarshalAs(UnmanagedType.LPWStr)] StringBuilder name,  
            int maxLength);  

        void SetDisplayName(  
            [MarshalAs(UnmanagedType.LPWStr)] string name);  

        void GetPath(  
            [MarshalAs(UnmanagedType.LPWStr)] StringBuilder path,  
            int maxPath);  

        void GetDSPath(  
            uint section,  
            [MarshalAs(UnmanagedType.LPWStr)] StringBuilder path,  
            int maxPath);  

        void GetFileSysPath(  
            uint section,  
            [MarshalAs(UnmanagedType.LPWStr)] StringBuilder path,  
            int maxPath);  

        IntPtr GetRegistryKey(uint section);  

        uint GetOptions();  

        void SetOptions(  
            uint options,  
            uint mask);  

        void GetMachineName(  
            [MarshalAs(UnmanagedType.LPWStr)] StringBuilder name,  
            int maxLength);  

        uint GetPropertySheetPages(  
            out IntPtr pages);  
    }

The problem is when I try to use the IGroupPolicyObject as follows I get an InvalidCastException:

GPClass gpClass = new GPClass();
IGroupPolicyObject comGroupPolicyObject = (IGroupPolicyObject)gpClass;

Exception I get is: Unable to cast COM object of type 'ConfigureRemoteSources.GPClass' to interface type 'ConfigureRemoteSources.IGroupPolicyObject'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{EA502722-A23D-11D1-A7D3-0000F87571E3}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

Any ideas on how to solve this? Thanks

Was it helpful?

Solution

You can find it back with Regedit.exe, HKCR\CLSID\{EA502722-A23D-11D1-A7D3-0000F87571E3}\InProcServer32 key. Which contains the ThreadModel value, it is set to "Apartment". That means that the coclass is not thread-safe, it must be called from a Single-Threaded Apartment. You'll recognize the acronym, that's what STA means in [STAThread].

There's commonly also a key in HKCR\Interface that declares the proxy/stub DLL that marshals an interface call across apartments. But that's missing. Which is what the error message really means, COM created a separate thread to give the component a safe home but then it couldn't find a way to marshal the call. Microsoft just didn't bother, this coclass is normally used from MMC by running the group policy editor, gpedit.msc. You must provide a similar safe home for this non-threadsafe component, an STA thread that pumps a message loop. The UI thread of a GUI program. You took care of STA with the attribute, probably not of the message loop. You might get away with it, if you notice deadlock then you didn't.

OTHER TIPS

It seems that this article has something clean but I wasn't able to get that working though. I got the issue solved by adding [STAThread] to the main method. (using System.Threading;)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top