성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] What has case distinction but is ne...
[정성태] 대소문자 '변환'과 함께 따라오는 문제가 바로 대소문자 구분 없...
[정성태] Reverse-engineering what a "short" ...
[정성태] 윈도우의 경우, 스레드 관련 자원을 완전히 회수하기 위해 Thr...
[지현명] Android쪽에서 activity 접근 할때 아래꺼 적어 놓고...
[지현명] Maui.Android에서 폴더 관련 내용 정리 잘 되어 있네요...
[정성태] @정한솔 언급하신 사항이 맞습니다. (C# 13부터) 중간에 i...
[정한솔] 기존 printAll(params int[] args)를 pri...
[정성태] 제가 거기까지는 테스트를 안 해봤군요. ^^ 재미 삼아 저 당시...
[정재겸] 질문이 하나 더 있습니다. 처음에 키보드 인풋은 먹다가 마...
글쓰기
제목
이름
암호
전자우편
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'>.NET 6+ 기반의 COM Server 내에 Type Library를 내장하는 방법</h1> <p> 보통, C# COM DLL을 C++에서 사용하려면 다음과 같은 과정을 거칩니다.<br /> <br /> <ol> <li>C# COM DLL 제작</li> <li><a target='tab' href='https://www.sysnet.pe.kr/2/0/13458'>dscom을 이용해 DLL로부터 TLB 파일 생성</a></li> <li>C++ 프로젝트에서는 #import 명령어로 TLB 파일 사용</li> </ol> <br /> 그런데, 위에서 2번 과정이 별로 매끄럽지 않습니다. 게다가 C/C++에서 사용하려면 DLL과 함께 항상 TLB 파일도 함께 배포해야 하는 것도 마음에 들지 않습니다.<br /> <br /> 이를 위해 한 가지 대안이라면 2번 과정을 msbuild task로 자동화하는 정도가 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0-windows</TargetFramework> <OutputType>Library</OutputType> <UseWindowsForms>true</UseWindowsForms> <ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets> <a target='tab' href='https://www.sysnet.pe.kr/2/0/13459'><EnableComHosting>true</EnableComHosting></a> <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <Platform>x64</Platform> </PropertyGroup> <PropertyGroup> <SignAssembly>true</SignAssembly> </PropertyGroup> <PropertyGroup> <AssemblyOriginatorKeyFile>test.snk</AssemblyOriginatorKeyFile> </PropertyGroup> <span style='color: blue; font-weight: bold'><Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Exec Command="dscom tlbexport &quot;$(TargetPath)&quot;" /> </Target></span> </Project> </pre> <br /> 일단 위와 같이 build event로 tlb 파일을 만들었으면 ItemGroup에 <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/core/native-interop/expose-components-to-com#embedding-type-libraries-in-the-com-host'>ComHostTypeLibrary</a>를 이용해 TLB를 내장할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <Project Sdk="Microsoft.NET.Sdk"> <!-- ...[생략]... --> <Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Exec Command="dscom tlbexport &quot;$(TargetPath)&quot;" /> </Target> <span style='color: blue; font-weight: bold'><ItemGroup> <ComHostTypeLibrary Include="$(AssemblyName).tlb" Id="1"/> </ItemGroup></span> </Project> </pre> <br /> 아쉬운 점이 하나 있다면, 저 프로젝트를 맨 처음 빌드할 때는 tlb 파일이 없어 DLL 생성에 실패하게 되고, 결국 PostBuildEvent가 실행되지 않아 닭이 먼저냐/달걀이 먼저냐 하는 문제에 빠집니다.<br /> <br /> 그나마 이런 문제를 완화하기 위해 Condition을 줄 수 있지만,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <Project Sdk="Microsoft.NET.Sdk"> <!-- ...[생략]... --> <Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Exec Command="dscom tlbexport &quot;$(TargetPath)&quot;" /> </Target> <ItemGroup <span style='color: blue; font-weight: bold'>Condition="Exists('$(AssemblyName).tlb')"</span>> <ComHostTypeLibrary Include="$(AssemblyName).tlb" Id="1"/> </ItemGroup> </Project> </pre> <br /> 제대로 된 TLB를 생성하기 위해 빌드를 반드시 2번 해야 한다는 것을 잊으면 안 됩니다. 그래도 대개의 경우 TLB가 변경될 정도로 COM 규약이 변경되는 경우는 많지 않으므로 큰 제약은 아닙니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 여기서 재미있는 것은, TLB 파일을 내장하는 DLL이 ClassLibrary1.dll 파일이 아닌 ClassLibrary1.comhost.dll 파일이라는 점입니다. 그래서 <EnableComHosting>true</EnableComHosting> 옵션을 사용하지 않았다면 저렇게 ComHostTypeLibrary 처리도 의미가 없습니다.<br /> <br /> 마지막으로, C/C++에서 "#import" 구문을 이용해 tlh/tli 파일을 이용하려는 경우 다음과 같이 comhost DLL을 편리하게 사용할 수 있습니다.<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> <span style='color: blue; font-weight: bold'>#import "..\ClassLibrary1\bin\Debug\ClassLibrary1.comhost.dll" no_namespace named_guids</span> 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 /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=2110&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
5020
(왼쪽의 숫자를 입력해야 합니다.)