COM Interops InvalidCastException with IGroupPolicyObject
-
14-06-2021 - |
문제
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
해결책
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.
다른 팁
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;
)