성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
글쓰기
제목
이름
암호
전자우편
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# COM 개체를 C++에서 사용하는 예제</h1> <p> 다음의 질문이 나온 김에,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C++ C# API 연동 관련 ; <a target='tab' href='https://www.sysnet.pe.kr/3/0/5546'>https://www.sysnet.pe.kr/3/0/5546</a> </pre> <br /> 정리를 해보겠습니다. ^^ 또한, 네이티브가 엮이므로 반드시 x86, x64를 선택해야 하는데 이 글은 x64 기준으로 설명합니다. x86에서 필요한 경우라면, 글에 나온 x64 옵션 등을 모두 x86 기준으로 바꾸면 됩니다.<br /> <br /> <hr style='width: 50%' /><br /> <a name='code1'></a> <br /> 우선, C# DLL(.NET 4.0)을 다음과 같이 만들겠습니다. (.NET Core/5+ 환경이라면 "<a target='tab' href='https://www.sysnet.pe.kr/2/0/13459'>.NET Core 3/5+ 기반의 COM Server를 기존의 regasm처럼 등록하는 방법</a>" 글도 함께 참고하세요.)<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System.Runtime.InteropServices; using System; using System.Windows.Forms; namespace ClassLibrary1 { [ComVisible(true)] [Guid("23172f2f-a3d3-4180-97ae-7805f74a5a46")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface IMyNetCode { void ShowDialog(); } [ComVisible(true)] [Guid("41AC8568-9230-4E63-B7C5-CAAD997EE207")] public class MyNetCode : IMyNetCode { public void ShowDialog() { string platform = (IntPtr.Size == 4) ? "x86" : "x64"; MessageBox.Show($".NET Framework: {Environment.Version}, {platform}"); } } } </pre> <br /> 또한 프로젝트 설정에서 "Signing"을 선택해 "Sign the assembly"를 이용해 서명합니다. 이후, 빌드하고, 명령행에서 ./bin/Debug/ 디렉터리로 이동해 다음과 같은 명령어를 실행,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp\ClassLibrary1\ClassLibrary1\bin\Debug> <span style='color: blue; font-weight: bold'>tlbexp ClassLibrary1.dll /win64</span> Microsoft (R) .NET Framework Assembly to Type Library Converter 4.8.4084.0 Copyright (C) Microsoft Corporation. All rights reserved. TlbExp : warning TX00131175 : When cross-compiling, all type library references should be included on the command line to ensure the correct bit-specific type libraries are loaded. Assembly exported to 'C:\temp\ClassLibrary1\ClassLibrary1\bin\Debug\ClassLibrary1.tlb' </pre> <br /> tlb 파일을 구해 놓습니다. 물론 위의 과정은 프로젝트 속성 창에서 "Register for COM interop" 옵션을 켜면 생략할 수 있지만 그런 경우 Visual Studio IDE를 관리자 권한으로 실행시켜야 하기 때문에 개인적으로 선호하지 않습니다.<br /> <br /> 어차피, TLB 파일은 인터페이스가 바뀌지 않는 한 재생성할 일이 없으므로 저런 식으로 그때그때 구하시는 것을 추천합니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> C# DLL과 TLB 파일이 준비되었다면 이제 C++ Console 프로젝트를 생성하고 x64 타깃으로 바꾼 다음, 다음과 같이 코드를 작성합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > #include <combaseapi.h> #include <Windows.h> #import "../ClassLibrary1/bin/Debug/ClassLibrary1.tlb" no_namespace named_guids int main() { HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); { IMyNetCode* pMyObject = NULL; hr = ::CoCreateInstance(CLSID_MyNetCode, NULL, CLSCTX_INPROC_SERVER, IID_IMyNetCode, (PVOID*)&pMyObject); if (hr != S_OK) { printf("Failed - CoCreateInstance: %x(%d)\n", hr, hr); return 1; } pMyObject->ShowDialog(); } CoUninitialize(); return 0; } </pre> <br /> 코드 작성은 이것으로 끝입니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 자, 이제 Release 빌드를 하고, 다음의 바이너리 파일 2개를 대상 PC에 복사합니다.<br /> <br /> <ol> <li>닷넷 DLL 복사(c:\temp\ClassLibrary1.dll)</li> <li>C++ EXE 복사(c:\temp\ConsoleApplication1.exe)</li> </ol> <br /> 이 글에서는 "C:\temp" 디렉터리에 복사했다고 가정하고 진행하겠습니다. 일단, 현재 상태로는 내 PC든 다른 PC든 정상적으로 실행되지 않습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp>ConsoleApplication1.exe Failed - CoCreateInstance: 80040154(-2147221164) /* 0x80040154 == Class not registered */ </pre> <br /> 왜냐하면, C# DLL의 위치를 찾을 방법이 없기 때문인데, 이것을 위해서는 regasm.exe를 실행해 레지스트리에 COM 관련 설정을 등록해야 합니다. 이를 위해서는 2가지 방법이 있는데요,<br /> <br /> <ul> <li><a target='tab' href='https://www.sysnet.pe.kr/2/0/1286'>gacutil + regarm</a></li> <li>regasm 단독 등록</li> </ul> <br /> gacutil을 사용하는 경우, 일반 사용자 PC에 설치되어 있지 않으므로 regasm만 실행하는 방법이 더 나은데, 이 경우 옵션에 "/codebase"를 더해주면 됩니다. 따라서 관리자 권한의 창을 띄워 다음의 명령을 수행합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp> <span style='color: blue; font-weight: bold'>C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regasm /codebase ClassLibrary1.dll</span> Microsoft .NET Framework 버전 4.7.3190.0용 Microsoft .NET Framework Assembly Registration Utility 버전 4.7.3190.0 Copyright (C) Microsoft Corporation. All rights reserved. 형식이 등록되었습니다. </pre> <br /> 끝입니다. 이제 ConsoleApplication1.exe를 실행하면 정상적으로 실행되는 것을 확인할 수 있습니다.<br /> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1846&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다. (.NET Core/5+ 프로젝트 예제는 <a target='tab' href='https://www.sysnet.pe.kr/2/0/13459'>별도의 글에 첨부</a>했습니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 시간 되시면, 다음의 글도 읽어 보시고. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 배열을 반환하는 C# COM 개체의 메서드를 C++에서 사용 시 메모리 누수 현상 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12491'>https://www.sysnet.pe.kr/2/0/12491</a> regasm.exe로 어셈블리 등록 시 시스템 변경 사항 (1) - .NET 2.0 + x86/x64/AnyCPU ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/1286'>https://www.sysnet.pe.kr/2/0/1286</a> regasm.exe로 어셈블리 등록 시 시스템 변경 사항 (2) - .NET 4.0 + .NET 2.0 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/1287'>https://www.sysnet.pe.kr/2/0/1287</a> regasm.exe로 어셈블리 등록 시 시스템 변경 사항 (3) - Type Library ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/1288'>https://www.sysnet.pe.kr/2/0/1288</a> regsvcs.exe로 어셈블리 등록 시 시스템 변경 사항 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/1289'>https://www.sysnet.pe.kr/2/0/1289</a> </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1397
(왼쪽의 숫자를 입력해야 합니다.)