성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C#에서 C++로 VARIANT 넘겨주는 방법</h1> <p> 그냥 방법 위주로 결과만 나열해 보겠습니다.<br /> <br /> 우선 C/C++ DLL에서 제공하는 함수가 다음과 같은 경우,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > WIN32LIB_API int VariantFromCS(<span style='color: blue; font-weight: bold'>VARIANT var</span>) { if (var.vt != VT_BSTR) { return 0; } CComBSTR bstr = var.bstrVal; return bstr.Length(); } </pre> <br /> C#에서 이 함수에 값을 제공하는 방법은 우선 VARIANT 구조체를 만듭니다.<br /> <br /> <pre style='height: 400px; margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // VARIANTARG (Structures) // <a target='tab' href='http://www.pinvoke.net/default.aspx/Structures/VARIANTARG.html'>http://www.pinvoke.net/default.aspx/Structures/VARIANTARG.html</a> [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; } </pre> <br /> 이제 C#에서 문자열을 전달하고 싶다면 다음과 같이 코딩하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [DllImport("Win32Lib.dll")] <span style='color: blue; font-weight: bold'>static extern int VariantFromCS(VARIANTARG var);</span> static void Main(string[] args) { VARIANTARG var = new VARIANTARG(); <span style='color: blue; font-weight: bold'>var.vt = 8;</span> // VT_BSTR == 8 string txt = "test is good"; fixed (char* str = txt) { <span style='color: blue; font-weight: bold'>var.bstrVal = (ushort*)str;</span> Console.WriteLine("VariantFromCS Length: " + <span style='color: blue; font-weight: bold'>VariantFromCS(var)</span> + " == " + txt.Length); // 출력 결과 // VariantFromCS Length: 12 == 12 } } </pre> <br /> <hr style='width: 50%' /><br /> <br /> C/C++ 측에서 "VARIANT *"를 받는 요구한다면 어떻게 해야 할까요?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > WIN32LIB_API int PointerVariantFromCS(<span style='color: blue; font-weight: bold'>VARIANT *pVar</span>) { if (pVar->vt != VT_BSTR) { return 0; } CComBSTR bstr = pVar->bstrVal; return bstr.Length(); } </pre> <br /> 상관없습니다. ^^ C# 측에서 맞춰주기만 하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [DllImport("Win32Lib.dll")] static <span style='color: blue; font-weight: bold'>unsafe</span> extern int PointerVariantFromCS(<span style='color: blue; font-weight: bold'>VARIANTARG* pVar</span>); 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: " + <span style='color: blue; font-weight: bold'>PointerVariantFromCS(&var)</span> + " == " + txt.Length); // 출력 결과 // PointerVariantFromCS Length: 12 == 12 } } } </pre> <br /> <hr style='width: 50%' /><br /> <br /> VARIANT의 배열을 받는 경우라면 어떨까요? <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 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; } </pre> <br /> 역시 상관없습니다. C/C++에서처럼 하듯이 C#에서도 직관적으로 맞춰주면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [DllImport("Win32Lib.dll")] static unsafe extern int ArrayVariantFromCS(<span style='color: blue; font-weight: bold'>VARIANTARG[] pVar</span>); 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(); <span style='color: blue; font-weight: bold'> 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</span> Console.WriteLine("ArrayVariantFromCS Length: " + <span style='color: blue; font-weight: bold'>ArrayVariantFromCS(varArray)</span> + " == " + (txt.Length + txt2.Length)); // 출력 결과 // ArrayVariantFromCS Length: 24 == 24 } } } </pre> <br /> 예전에 비슷한 주제로 한번 이야기 한 적이 있지요. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > How to Interop DISPPARAMS ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/617'>http://www.sysnet.pe.kr/2/0/617</a> </pre> <br /> 위의 방법을 써서 ArrayVariantFromCS 함수에 전달하는 것을 다음과 같이 우회하는 것도 가능합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 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(); } </pre> <br /> C/C++ 언어와 이렇게나 호환이 잘 되니... 정말이지 C#이란 언어는 사랑하지 않을래야 않을 수가 없습니다. ^^<br /> <br /> 뭐 이정도면... ^^ 언제든 쉽게 가져다 쓰실 수 있겠죠!<br /> <br /> (<a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=859&boardid=331301885'>첨부 파일은 위의 예제 코드를 모두 포함하는 C#과 C++프로젝트</a>입니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
6519
(왼쪽의 숫자를 입력해야 합니다.)