C# - CoCreateInstance 관련 Inteop 오류 정리
CoCreateInstance의 pinvoke 호출을 다음과 같이 정의해 볼까요?
[DllImport("ole32.dll")]
internal static extern int CoCreateInstance(
[In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
[MarshalAs(UnmanagedType.IUnknown)] IntPtr pUnkOuter,
CLSCTX dwClsCtx,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[In, Out] ref IntPtr ppv);
이걸로 사용해 보면,
using System;
using System.Runtime.InteropServices;
class Program
{
[Flags]
internal enum CLSCTX : uint
{
INPROC_SERVER = 0x1,
INPROC_HANDLER = 0x2,
LOCAL_SERVER = 0x4,
INPROC_SERVER16 = 0x8,
REMOTE_SERVER = 0x10,
INPROC_HANDLER16 = 0x20,
RESERVED1 = 0x40,
RESERVED2 = 0x80,
RESERVED3 = 0x100,
RESERVED4 = 0x200,
NO_CODE_DOWNLOAD = 0x400,
RESERVED5 = 0x800,
NO_CUSTOM_MARSHAL = 0x1000,
ENABLE_CODE_DOWNLOAD = 0x2000,
NO_FAILURE_LOG = 0x4000,
DISABLE_AAA = 0x8000,
ENABLE_AAA = 0x10000,
FROM_DEFAULT_CONTEXT = 0x20000,
ACTIVATE_32_BIT_SERVER = 0x40000,
ACTIVATE_64_BIT_SERVER = 0x80000,
INPROC = INPROC_SERVER | INPROC_HANDLER,
SERVER = INPROC_SERVER | LOCAL_SERVER | REMOTE_SERVER,
ALL = SERVER | INPROC_HANDLER
}
[DllImport("ole32.dll")]
internal static extern int CoCreateInstance(
[In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
[MarshalAs(UnmanagedType.IUnknown)] IntPtr /* nuint */ pUnkOuter,
CLSCTX dwClsCtx,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[In, Out] ref IntPtr ppv);
public static Guid CLSID_FolderInitHandler = new Guid("469afbdf-084f-4dc9-904f-9e824c48bc37");
public static Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
static void Main(string[] args)
{
IntPtr pUnknown = IntPtr.Zero;
try
{
int hr = CoCreateInstance(CLSID_FolderInitHandler, IntPtr.Zero /* 0 */, CLSCTX.INPROC_SERVER, IID_IUnknown, ref pUnknown);
Console.WriteLine(hr);
}
finally
{
if (pUnknown != IntPtr.Zero)
{
Marshal.Release(pUnknown);
}
}
}
}
실행 시 다음과 같은 예외가 발생합니다.
Unhandled Exception: System.Runtime.InteropServices.MarshalDirectiveException: Cannot marshal 'parameter #2': Invalid managed/unmanaged type combination (Int/UInt must be paired with SysInt or SysUInt).
at Program.CoCreateInstance(Guid rclsid, IntPtr pUnkOuter, CLSCTX dwClsCtx, Guid riid, IntPtr& ppv)
at Program.Main(String[] args)
왜냐하면, UnmanagedType.IUnknown으로 마샬링을 지정했으면 IntPtr로 하면 안 되고 object로 해야 합니다.
[DllImport("ole32.dll")]
internal static extern int CoCreateInstance([In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
[MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter,
CLSCTX dwClsCtx, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, [In, Out] ref IntPtr ppv);
int hr = CoCreateInstance(CLSID_FolderInitHandler, null, CLSCTX.INPROC_SERVER, IID_IUnknown, ref pUnknown);
Console.WriteLine(hr); // 출력 결과 0
혹은 IntPtr로 할 거라면 MarshalAs를 지정하지 말아야 합니다.
[DllImport("ole32.dll")]
internal static extern int CoCreateInstance([In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
IntPtr pUnkOuter,
CLSCTX dwClsCtx, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, [In, Out] ref IntPtr ppv);
int hr = CoCreateInstance(CLSID_FolderInitHandler, IntPtr.Zero, CLSCTX.INPROC_SERVER, IID_IUnknown, ref pUnknown);
Console.WriteLine(hr); // 출력 결과 0
또 하나 실수할 수 있는 것은 MarshalAs를 지정한 object를,
[DllImport("ole32.dll")]
internal static extern int CoCreateInstance([In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
[MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter,
CLSCTX dwClsCtx, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, [In, Out] ref IntPtr ppv);
IntPtr.Zero로 던졌을 때입니다.
int hr = CoCreateInstance(CLSID_FolderInitHandler, IntPtr.Zero, CLSCTX.INPROC_SERVER, IID_IUnknown, ref pUnknown);
Console.WriteLine(hr); // 출력 결과: -2147221232
이번에는 예외가 발생하지는 않고 hr로 반환합니다. 그래도 hr 값의 의미를 보면 pUnkOuter 인자에서 잘못된 것임을 짐작게 합니다.
0x80040110 Class does not support aggregation (or class object is remote)
(
첨부 파일은 이 글의 예제 코드를 포함합니다.)
C# - CoCreateInstance 관련 Inteop 오류 정리
; https://www.sysnet.pe.kr/2/0/12678
Wslhub.Sdk 사용으로 알아보는 CoInitializeSecurity 사용 제약
; https://www.sysnet.pe.kr/2/0/12665
별도 DLL에 포함된 타입을 STAThread Main 메서드에서 사용하는 경우 CoInitializeSecurity 자동 호출
; https://www.sysnet.pe.kr/2/0/12666
COM+ 서버 응용 프로그램을 이용해 CoInitializeSecurity 제약 해결
; https://www.sysnet.pe.kr/2/0/12667
ionescu007/lxss github repo에 공개된 lxssmanager.dll의 CLSID_LxssUserSession/IID_ILxssSession 사용법
; https://www.sysnet.pe.kr/2/0/12676
역공학을 통한 lxssmanager.dll의 ILxssSession 사용법 분석
; https://www.sysnet.pe.kr/2/0/12677
C# - DLL Surrogate를 이용한 Out-of-process COM 개체 제작
; https://www.sysnet.pe.kr/2/0/12668
DLL Surrogate를 이용한 Out-of-process COM 개체에서의 CoInitializeSecurity 문제
; https://www.sysnet.pe.kr/2/0/12670
CoInitializeSecurity의 전역 설정을 재정의하는 CoSetProxyBlanket 함수 사용법
; https://www.sysnet.pe.kr/2/0/12679
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]