Microsoft MVP성태의 닷넷 이야기
.NET Framework: 449. C#에서 C++로 VARIANT 넘겨주는 방법 [링크 복사], [링크+제목 복사],
조회: 22976
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
[TestApp.zip]    

C#에서 C++로 VARIANT 넘겨주는 방법

그냥 방법 위주로 결과만 나열해 보겠습니다.

우선 C/C++ DLL에서 제공하는 함수가 다음과 같은 경우,

WIN32LIB_API int VariantFromCS(VARIANT var)
{
    if (var.vt != VT_BSTR)
    {
        return 0;
    }

    CComBSTR bstr = var.bstrVal;
    return bstr.Length();
}

C#에서 이 함수에 값을 제공하는 방법은 우선 VARIANT 구조체를 만듭니다.

// VARIANTARG (Structures)
// http://www.pinvoke.net/default.aspx/Structures/VARIANTARG.html

[StructLayout(LayoutKind.Explicit, Size = 16)]
struct VARIANTARG
{
    [FieldOffset(0)]
    public ushort vt;

    [FieldOffset(2)]
    public ushort wReserved1;

    [FieldOffset(4)]
    public ushort wReserved2;

    [FieldOffset(6)]
    public ushort wReserved3;

    [FieldOffset(8)]
    public long llVal;

    [FieldOffset(8)]
    public int lVal;

    [FieldOffset(8)]
    public byte bVal;

    [FieldOffset(8)]
    public short iVal;

    [FieldOffset(8)]
    public float fltVal;

    [FieldOffset(8)]
    public double dblVal;

    [FieldOffset(8)]
    public short boolVal;

    [FieldOffset(8)]
    public int scode;

    [FieldOffset(8)]
    public double date;

    [FieldOffset(8)]
    public unsafe ushort* bstrVal;

    [FieldOffset(8)]
    public unsafe byte* pbVal;

    [FieldOffset(8)]
    public unsafe short* piVal;

    [FieldOffset(8)]
    public unsafe int* plVal;

    [FieldOffset(8)]
    public unsafe long* pllVal;

    [FieldOffset(8)]
    public unsafe float* pfltVal;

    [FieldOffset(8)]
    public unsafe double* pdblVal;

    [FieldOffset(8)]
    public unsafe short* pboolVal;

    [FieldOffset(8)]
    public unsafe int* pscode;

    [FieldOffset(8)]
    public unsafe double* pdate;

    [FieldOffset(8)]
    public unsafe ushort** pbstrVal;

    [FieldOffset(8)]
    public unsafe VARIANTARG* pvarVal;

    [FieldOffset(8)]
    public unsafe void* byref;

    [FieldOffset(8)]
    public sbyte cVal;

    [FieldOffset(8)]
    public ushort uiVal;

    [FieldOffset(8)]
    public uint ulVal;

    [FieldOffset(8)]
    public ulong ullVal;

    [FieldOffset(8)]
    public int intVal;

    [FieldOffset(8)]
    public uint uintVal;

    [FieldOffset(8)]
    public unsafe sbyte* pcVal;

    [FieldOffset(8)]
    public unsafe ushort* puiVal;

    [FieldOffset(8)]
    public unsafe uint* pulVal;

    [FieldOffset(8)]
    public unsafe ulong* pullVal;

    [FieldOffset(8)]
    public unsafe int* pintVal;

    [FieldOffset(8)]
    public unsafe uint* puintVal;

    [FieldOffset(8)]
    public unsafe void* pvRecord;
}

이제 C#에서 문자열을 전달하고 싶다면 다음과 같이 코딩하면 됩니다.

[DllImport("Win32Lib.dll")]
static extern int VariantFromCS(VARIANTARG var);

static void Main(string[] args)
{
    VARIANTARG var = new VARIANTARG();
    var.vt = 8; // VT_BSTR == 8

    string txt = "test is good";
    fixed (char* str = txt)
    {
        var.bstrVal = (ushort*)str;
        Console.WriteLine("VariantFromCS Length: " + VariantFromCS(var) + " == " + txt.Length); 

        // 출력 결과
        // VariantFromCS Length: 12 == 12
    }
}




C/C++ 측에서 "VARIANT *"를 받는 요구한다면 어떻게 해야 할까요?

WIN32LIB_API int PointerVariantFromCS(VARIANT *pVar)
{
    if (pVar->vt != VT_BSTR)
    {
        return 0;
    }

    CComBSTR bstr = pVar->bstrVal;
    return bstr.Length();
}

상관없습니다. ^^ C# 측에서 맞춰주기만 하면 됩니다.

[DllImport("Win32Lib.dll")]
static unsafe extern int PointerVariantFromCS(VARIANTARG* pVar);

static void Main(string[] args)
{
    unsafe
    {
        VARIANTARG var = new VARIANTARG();
        var.vt = 8; // VT_BSTR == 8

        string txt = "test is good";

        fixed (char* str = txt)
        {
            var.bstrVal = (ushort*)str;
            Console.WriteLine("PointerVariantFromCS Length: " + PointerVariantFromCS(&var) + " == " + txt.Length);
        
            // 출력 결과
            // PointerVariantFromCS Length: 12 == 12
        }
    }
}




VARIANT의 배열을 받는 경우라면 어떨까요?

WIN32LIB_API int ArrayVariantFromCS(VARIANT *pVar)
{
    int totalLength = 0;

    for (VARIANT *first = pVar; (*first).vt != VT_EMPTY; first++)
    {
        CComBSTR bstr = pVar->bstrVal;
        totalLength += bstr.Length();
    }

    return totalLength;
}

역시 상관없습니다. C/C++에서처럼 하듯이 C#에서도 직관적으로 맞춰주면 됩니다.

[DllImport("Win32Lib.dll")]
static unsafe extern int ArrayVariantFromCS(VARIANTARG[] pVar);

static void Main(string[] args)
{
    unsafe
    {
        string txt = "test is good";
        string txt2 = "this is test";

        fixed (char* str1 = txt)
        fixed (char* str2 = txt2)
        {
            VARIANTARG[] varArray = new VARIANTARG[3];
            varArray[0] = new VARIANTARG();
            varArray[1] = new VARIANTARG();
            varArray[2] = new VARIANTARG();

            varArray[0].vt = 8;
            varArray[0].bstrVal = (ushort*)str1;

            varArray[1].vt = 8;
            varArray[1].bstrVal = (ushort*)str2;

            varArray[2].vt = 0; // VT_EMPTY == 0

            Console.WriteLine("ArrayVariantFromCS Length: " + ArrayVariantFromCS(varArray) + " == " + (txt.Length + txt2.Length));

            // 출력 결과
            // ArrayVariantFromCS Length: 24 == 24
        }
    }
}

예전에 비슷한 주제로 한번 이야기 한 적이 있지요. ^^

How to Interop DISPPARAMS
; https://www.sysnet.pe.kr/2/0/617

위의 방법을 써서 ArrayVariantFromCS 함수에 전달하는 것을 다음과 같이 우회하는 것도 가능합니다.

Guid[] guids = new Guid[2];
IntPtr pGuid = IntPtr.Zero;
fixed (void* pArrayGuid0 = &guids[0])
{
    pGuid = new IntPtr(pArrayGuid0);
    Marshal.GetNativeVariantForObject(txt, pGuid);
}

fixed (void* pArrayGuid1 = &guids[1])
{
    pGuid = new IntPtr(pArrayGuid1);
    Marshal.GetNativeVariantForObject(txt2, pGuid);
}

GCHandle gcHandle = GCHandle.Alloc(guids, GCHandleType.Pinned);
{
    IntPtr argPtr = gcHandle.AddrOfPinnedObject();
    Console.WriteLine("ArrayVariantFromCS(2) Length: " + ArrayVariantFromCS(argPtr));

    // 출력 결과
    // ArrayVariantFromCS(2) Length: 24

    gcHandle.Free();
}

C/C++ 언어와 이렇게나 호환이 잘 되니... 정말이지 C#이란 언어는 사랑하지 않을래야 않을 수가 없습니다. ^^

뭐 이정도면... ^^ 언제든 쉽게 가져다 쓰실 수 있겠죠!

(첨부 파일은 위의 예제 코드를 모두 포함하는 C#과 C++프로젝트입니다.)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 7/5/2014]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... [106]  107  108  109  110  111  112  113  114  115  116  117  118  119  120  ...
NoWriterDateCnt.TitleFile(s)
11274정성태8/22/201719391.NET Framework: 674. Thread 타입의 Suspend/Resume/Join 사용 관련 예외 처리
11273정성태8/22/201721634오류 유형: 415. 윈도우 업데이트 에러 Error 0x80070643
11272정성태8/21/201724804VS.NET IDE: 120. 비주얼 스튜디오 2017 버전 15.3.1 - C# 7.1 공개 [2]
11271정성태8/19/201719263VS.NET IDE: 119. Visual Studio 2017에서 .NET Core 2.0 프로젝트 환경 구성하는 방법
11270정성태8/17/201730725.NET Framework: 673. C#에서 enum을 boxing 없이 int로 변환하기 [2]
11269정성태8/17/201721495디버깅 기술: 93. windbg - 풀 덤프에서 .NET 스레드의 상태를 알아내는 방법
11268정성태8/14/201721083디버깅 기술: 92. windbg - C# Monitor Lock을 획득하고 있는 스레드 찾는 방법
11267정성태8/10/201725138.NET Framework: 672. 모노 개발 환경
11266정성태8/10/201724946.NET Framework: 671. C# 6.0 이상의 소스 코드를 Visual Studio 설치 없이 명령행에서 컴파일하는 방법
11265정성태8/10/201753186기타: 66. 도서: 시작하세요! C# 7.1 프로그래밍: 기본 문법부터 실전 예제까지 [11]
11264정성태8/9/201724113오류 유형: 414. UWP app을 signtool.exe로 서명 시 0x8007000b 오류 발생
11263정성태8/9/201719597오류 유형: 413. The C# project "..." is targeting ".NETFramework, Version=v4.0", which is not installed on this machine. [3]
11262정성태8/5/201718256오류 유형: 412. windbg - SOS does not support the current target architecture. [3]
11261정성태8/4/201720834디버깅 기술: 91. windbg - 풀 덤프 파일로부터 강력한 이름의 어셈블리 추출 후 사용하는 방법
11260정성태8/3/201718953.NET Framework: 670. C# - 실행 파일로부터 공개키를 추출하는 방법
11259정성태8/2/201718190.NET Framework: 669. 지연 서명된 어셈블리를 sn.exe -Vr 등록 없이 사용하는 방법
11258정성태8/1/201719021.NET Framework: 668. 지연 서명된 DLL과 서명된 DLL의 차이점파일 다운로드1
11257정성태7/31/201719175.NET Framework: 667. bypassTrustedAppStrongNames 옵션 설명파일 다운로드1
11256정성태7/25/201720663디버깅 기술: 90. windbg의 lm 명령으로 보이지 않는 .NET 4.0 ClassLibrary를 명시적으로 로드하는 방법 [1]
11255정성태7/18/201723217디버깅 기술: 89. Win32 Debug CRT Heap Internals의 0xBAADF00D 표시 재현 [1]파일 다운로드3
11254정성태7/17/201719594개발 환경 구성: 322. "Visual Studio Emulator for Android" 에뮬레이터를 "Android Studio"와 함께 쓰는 방법
11253정성태7/17/201719950Math: 21. "Coding the Matrix" 문제 2.5.1 풀이 [1]파일 다운로드1
11252정성태7/13/201718462오류 유형: 411. RTVS 또는 PTVS 실행 시 Could not load type 'Microsoft.VisualStudio.InteractiveWindow.Shell.IVsInteractiveWindowFactory2'
11251정성태7/13/201717166디버깅 기술: 88. windbg 분석 - webengine4.dll의 MgdExplicitFlush에서 발생한 System.AccessViolationException의 crash 문제 (2)
11250정성태7/13/201720722디버깅 기술: 87. windbg 분석 - webengine4.dll의 MgdExplicitFlush에서 발생한 System.AccessViolationException의 crash 문제 [1]
11249정성태7/12/201718548오류 유형: 410. LoadLibrary("[...].dll") failed - The specified procedure could not be found.
... [106]  107  108  109  110  111  112  113  114  115  116  117  118  119  120  ...