Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)
(시리즈 글이 7개 있습니다.)
.NET Framework: 969. .NET Framework 및 .NET 5 - UnmanagedCallersOnly 특성 사용
; https://www.sysnet.pe.kr/2/0/12412

.NET Framework: 970. .NET 5 / .NET Core - UnmanagedCallersOnly 특성을 사용한 함수 내보내기
; https://www.sysnet.pe.kr/2/0/12413

.NET Framework: 971. UnmanagedCallersOnly 특성과 DNNE 사용
; https://www.sysnet.pe.kr/2/0/12415

.NET Framework: 972. DNNE가 출력한 NE DLL을 직접 생성하는 방법
; https://www.sysnet.pe.kr/2/0/12421

.NET Framework: 973. .NET 5, .NET Framework에서만 허용하는 UnmanagedCallersOnly 사용예
; https://www.sysnet.pe.kr/2/0/12422

.NET Framework: 976. UnmanagedCallersOnly + C# 9.0 함수 포인터 사용 시 x86 빌드에서 오동작하는 문제
; https://www.sysnet.pe.kr/2/0/12431

닷넷: 2174. C# - .NET 7부터 UnmanagedCallersOnly 함수 export 기능을 AOT 빌드에 통합
; https://www.sysnet.pe.kr/2/0/13464




.NET 5 / .NET Core - UnmanagedCallersOnly 특성을 사용한 함수 내보내기

지난 글에서,

.NET Framework 및 .NET Core 3.1 이하 - UnmanagedCallersOnly 특성 사용
.NET Framework 및 .NET 5 - UnmanagedCallersOnly 특성 사용
; https://www.sysnet.pe.kr/2/0/12412

다룬 UnmanagedCallersOnly 특성은, .NET Core와 .NET 5 환경에서 추가적인 의미를 갖는데, 바로 해당 함수를 export하는 용도로도 사용할 수 있다는 점입니다. 사실 이에 대해서는 약간의 이력이 있는데요, 원래는 그런 용도로 예전에 NativeCallable 특성이 있었습니다.

C# DLL에서 Win32 C/C++처럼 dllexport 함수를 제공하는 방법 - 두 번째 이야기
; https://www.sysnet.pe.kr/2/0/11884

당시, myget.org에서 배포하던 Microsoft.DotNet.ILCompiler 구성 요소는 NativeCallable 특성을 이용해 함수 내보내기를 구현했는데 이후 CoreRT 측으로 넘어가면서,

dotnet / corert
; https://github.com/dotnet/corert

배포 피드도 "https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json"로 변경됩니다. 그리고 다시 한번 해당 팀이 NativeAOT로 바뀌면서,

dotnet / runtimelab
; https://github.com/dotnet/runtimelab/tree/feature/NativeAOT

최종 배포 피드는 "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json"로 바뀌고 버전도 6.0.0-*으로 바뀌었습니다.

새롭게 바뀌었으니, 예제도 새롭게 ^^ 실습을 해보겠습니다.




프로젝트는 .NET Core, .NET Standard, 또는 .NET 5 대상으로 생성합니다. 이 글에서는 .NET Standard 1.1로 실습을 하겠습니다. 그런 다음, Microsoft.DotNet.ILCompiler 참조를 6.0 버전으로 추가합니다.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard1.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.DotNet.ILCompiler" Version="6.0.0-*" />
  </ItemGroup>
</Project>

그리고, (명령행에서 "dotnet new nuget" 등으로 만들거나, 직접 메모장을 이용해 생성한) nuget.config 파일에 Microsoft.DotNet.ILCompiler 구성 요소를 내려받을 수 있는 피드를 추가합니다.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <packageSources>
        <!--To inherit the global NuGet package sources remove the <clear/> line below -->
        <clear />
        <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
        <add key="dotnet-experimental" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json" />
    </packageSources>
</configuration>

환경 준비는 끝났고, 이제 다음과 같이 UnmanagedCallersOnly 특성을 이용해 코드를 작성하시면 됩니다.

using System;
using System.Runtime.InteropServices;

public class Class1
{
    // 반드시 EntryPoint 속성에 값을 설정!
    [UnmanagedCallersOnly(EntryPoint = "mymethod")]
    public static void MyMethod(IntPtr ptrText)
    {
        string text = Marshal.PtrToStringUni(ptrText);
        // Console.WriteLine($"{DateTime.Now} {text}");
    }
}

namespace System.Runtime.InteropServices
{
#if !NET5_0
    [AttributeUsage(AttributeTargets.Method)]
    public sealed class UnmanagedCallersOnlyAttribute : Attribute
    {
        public string EntryPoint;
        public CallingConvention CallingConvention;
        public UnmanagedCallersOnlyAttribute() { }
    }
#endif
}

남은 작업은, "dotnet publish" 명령어로 바이너리를 생성하는 것으로 끝!

dotnet publish /p:NativeLib=Shared -r win-x64 -c Release

이후 depends.exe 또는 dumpbin.exe 등의 도구로 export시킨 함수가 잘 나열되어 있는지 확인하시면 됩니다.




여기서 중요한 것은, 해당 DLL 파일이 "AOT(Ahead-of-time)" 빌드가 되었다는 점입니다. 따라서, 자체 실행 가능한 native 모듈이므로 이 DLL과 관련해서는 어떠한 부가 모듈도 필요가 없습니다. 덕분에, C++에서 사용할 때도 사용법이 다음과 같이 매우 간단합니다.

#include <iostream>
#include <windows.h>

typedef void(__stdcall* mymethod_proc)(intptr_t text);

static void* load_library(const char* path)
{
    HMODULE h = LoadLibraryA(path);
    return (void*)h;
}

static void* get_export(void* h, const char* name)
{
    void* f = GetProcAddress((HMODULE)h, name);
    return f;
}

int main()
{
    const wchar_t* pText = L"Hello World";

    void* mod = load_library("ClassLibrary.dll");
    mymethod_proc mymethod = (mymethod_proc)get_export(mod, "mymethod");
    mymethod((intptr_t)pText);
}

(첨부 파일은 이 글의 예제 코드를 포함합니다.)




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

[연관 글]






[최초 등록일: ]
[최종 수정일: 11/28/2023]

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

비밀번호

댓글 작성자
 




... 151  152  153  154  155  156  157  158  159  160  161  162  163  [164]  165  ...
NoWriterDateCnt.TitleFile(s)
944정성태11/11/201031640VC++: 43. C++/CLI 컴파일 오류 - error C2872: 'IServiceProvider' : ambiguous symbol could be ...
943정성태11/8/201030762디버깅 기술: 30. windbg ".loadby sos" 명령어 [2]
942정성태11/7/201042334.NET Framework: 187. 실행 시에 메서드 가로채기 - CLR Injection: Runtime Method Replacer 개선 [7]파일 다운로드3
941정성태11/6/201025250.NET Framework: 186. windbg로 확인하는 .NET CLR LCG 메서드(DynamicMethod) [1]파일 다운로드1
940정성태11/6/201026113.NET Framework: 185. windbg로 확인하는 .NET CLR 메서드파일 다운로드1
939정성태10/24/201033069Windows: 51. RDP로 접속한 Windows Server 2008 R2 환경에서 Aero Glass 활성화 [1]
938정성태10/23/201024829디버깅 기술: 29. Windbg - Hyper-V 윈도우 7 원격 디버깅 구성 [1]
937정성태10/22/201030963DDK: 5. NT Legacy 드라이버: 프로세스(EXE) 생성/제거 모니터링 [3]파일 다운로드1
936정성태10/21/201029996DDK: 4. Device Driver 응용 프로그램의 빌드 스크립트 - 두 번째 이야기 [2]파일 다운로드1
935정성태10/17/201030607디버깅 기술: 28. Windbg - 윈도우 핸들 테이블 [3]
934정성태10/11/201033594디버깅 기술: 27. Windbg - Local Kernel Debug 모드 [2]
933정성태10/10/201025792.NET Framework: 184. 닷넷에서 호출 스택의 메서드에 대한 인자 값 확인이 가능할까? [2]파일 다운로드1
932정성태10/10/201029024DDK: 3. NT Legacy 드라이버를 이용하여 C#에서 Port 입출력파일 다운로드1
931정성태9/30/201023596오류 유형: 108. Net.Tcp Listener Adapter 서비스 시작 실패
930정성태9/30/201022906웹: 16. 윈도우 미디어 플레이어 - 일시 정지/시작을 스크립트에서 감지
929정성태9/17/201024134웹: 15. IE 9 - 작업 표시줄의 웹 사이트 바로가기 사용자 정의 - JumpLists [3]파일 다운로드1
928정성태9/16/201028306VC++: 42. 쓰기 전용 파일(예: 로그 파일)의 동기화 방법파일 다운로드1
927정성태9/14/201038163VC++: 41. UTF-8 포맷의 INI 파일에 대한 GetPrivateProfile... API 사용 불가 [2]
926정성태9/9/201027440Team Foundation Server: 41. 빌드 스크립트에 Code Coverage 추가 [1]파일 다운로드1
925정성태9/8/201031338Team Foundation Server: 40. Visual Studio 2010 - Code Coverage 결과를 외부 XML 파일로 출력하는 명령행 도구 제작 [1]파일 다운로드1
924정성태9/6/201021600개발 환경 구성: 88. SCVMM이 설치된 도메인에 참여하지 않은 Hyper-V 호스트 추가
923정성태9/5/201027583오류 유형: 107. SCVMM Agent 설치 오류 - Failed to configure the WS-Management service.
922정성태9/4/201036254오류 유형: 106. Hyper-V 가상 머신의 네트워크 끊김 현상
921정성태9/2/201030284DDK: 2. Device Driver 응용 프로그램의 빌드 스크립트 [2]파일 다운로드1
920정성태9/1/201034723오류 유형: 105. WMI - The RPC server is unavailable [2]
919정성태8/30/201040842DDK: 1. Visual Studio 2010 - Device Driver 제작- Hello World 예제 [3]파일 다운로드1
... 151  152  153  154  155  156  157  158  159  160  161  162  163  [164]  165  ...