it-swarm-ko.tech

C ++ windows dll을 어떻게 C # application exe로 병합 할 수 있습니까?

데이터 I/O에 C++ dll을 사용하는 Windows C # 프로그램이 있습니다. 내 목표는 응용 프로그램을 단일 EXE로 배포하는 것입니다.

그러한 실행 파일을 작성하는 단계는 무엇입니까?

35
Noah

관리 및 관리되지 않는 코드의 단일 어셈블리 배포 2007 년 2 월 4 일 일요일

.NET 개발자는 XCOPY 배포를 좋아합니다. 그리고 그들은 단일 어셈블리 구성 요소를 좋아합니다. 적어도 일부 구성 요소를 사용해야하고 해당 구성 요소의 주 어셈블리에 포함 할 파일 목록을 기억 해야하는 경우 적어도 항상 불안감을 느낍니다. 그래서 최근에 관리 코드 구성 요소를 개발해야하고 C DLL (이를 도와 줘서 Marcus Heege에게 감사드립니다!)의 관리되지 않는 코드로 기능을 보강해야 할 때 어떻게 생각 했습니까? 두 개의 DLL을 쉽게 배포 할 수 있도록하기이 어셈블리가 단지 두 개의 어셈블리 인 경우 ILmerge를 사용하여 하나의 파일로 압축 할 수 있었지만 관리되는 DLL과 관리되지 않는 DLL이있는 혼합 코드 구성 요소에는 작동하지 않습니다.

그래서 여기 해결책을 찾았습니다.

구성 요소의 주 어셈블리와 함께 배포하려는 DLL을 포함 리소스로 포함시킵니다. 그런 다음 아래와 같은 DLL을 추출하도록 클래스 생성자를 설정했습니다. ctor 클래스는 각 AppDomain 내에서 한 번만 호출되므로 무시할 수있는 오버 헤드라고 생각합니다.

namespace MyLib
{
    public class MyClass
    {
        static MyClass()
        {
            ResourceExtractor.ExtractResourceToFile("MyLib.ManagedService.dll", "managedservice.dll");
            ResourceExtractor.ExtractResourceToFile("MyLib.UnmanagedService.dll", "unmanagedservice.dll");
        }

        ...

이 예제에서는 두 개의 DLL을 리소스로 포함했습니다. 하나는 관리되지 않는 코드 DLL이고 다른 하나는 관리되는 코드입니다. DLL (데모 목적으로 만)),이 기법이 두 종류에 어떻게 작동하는지 보여줍니다 코드.

DLL을 자체 파일로 추출하는 코드는 간단합니다.

public static class ResourceExtractor
{
    public static void ExtractResourceToFile(string resourceName, string filename)
    {
        if (!System.IO.File.Exists(filename))
            using (System.IO.Stream s = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
                using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Create))
                {
                    byte[] b = new byte[s.Length];
                    s.Read(b, 0, b.Length);
                    fs.Write(b, 0, b.Length);
                }
    }
}

이와 같이 관리 코드 어셈블리를 사용한 작업은 거의 동일합니다. 구성 요소의 기본 프로젝트 (여기서는 MyLib)에서 참조 (여기서는 ManagedService.dll)를 참조하지만 로컬 복사 속성을 false로 설정하십시오. 또한 어셈블리에서 기존 항목으로 링크하고 빌드 조치를 임베디드 자원으로 설정하십시오.

관리되지 않는 코드 (여기서는 UnmanagedService.dll)의 경우 DLL에 기존 항목으로 연결하고 빌드 작업을 포함 된 리소스로 설정) 기능에 액세스하려면 평소와 같이 DllImport 특성을 사용하십시오. 예 :.

[DllImport("unmanagedservice.dll")] public extern static int Add(int a, int b);

그게 다야! 정적 ctor를 사용하여 클래스의 첫 번째 인스턴스를 만들면 포함 된 DLL이 자체 파일로 추출되어 마치 별도의 파일로 배포 한 것처럼 사용할 수 있습니다. 실행 디렉토리에 대한 쓰기 권한이 있으면 이것이 잘 작동합니다. 적어도 프로토 타입 코드의 경우 이러한 단일 어셈블리 배포 방식이 매우 편리하다고 생각합니다.

즐겨!

http://weblogs.asp.net/ralfw/archive/2007/02/04/single-Assembly-deployment-of-managed-and-unmanaged-code.aspx

18
Nick

Fody.Costura 너겟 사용

  1. 솔루션 열기-> 프로젝트-> Nuget 패키지 관리
  2. Fody.Costura 검색
  3. 컴파일 your project.

그게 다야!

출처 : http://www.manuelmeyer.net/2016/01/net-power-tip-10-merging-assemblies/

3
automan

시도 boxedapp ; 메모리에서 모든 DLL을로드 할 수 있습니다. 또한 .net 런타임을 포함시킬 수도 있습니다. 실제로 독립형 응용 프로그램을 만드는 것이 좋습니다 ...

3
Art

Visual Studio에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 프로젝트 속성-> 리소스-> 리소스 추가-> 기존 파일 추가…를 선택하고 아래 코드를 App.xaml.cs 또는 이와 동등한 코드에 포함하십시오.

public App()
{
    AppDomain.CurrentDomain.AssemblyResolve +=new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}

System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll","");

    dllName = dllName.Replace(".", "_");

    if (dllName.EndsWith("_resources")) return null;

    System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());

    byte[] bytes = (byte[])rm.GetObject(dllName);

    return System.Reflection.Assembly.Load(bytes);
}

내 원래 블로그 게시물은 다음과 같습니다. http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-Assembly/

2
Lars Holm Jensen

ILMerge를 사용해 보셨습니까? http://research.Microsoft.com/~mbarnett/ILMerge.aspx

ILMerge는 여러 .NET 어셈블리를 단일 어셈블리로 병합하는 데 사용할 수있는 유틸리티입니다. Microsoft .NET Framework 개발자 센터의 도구 및 유틸리티 페이지에서 무료로 사용할 수 있습니다.

C++ DLL을 사용하여 /clr 플래그 (전체 또는 부분적으로 C++/CLI), 작동해야합니다.

ilmerge /out:Composite.exe MyMainApp.exe Utility.dll

그러나 일반 (기본) Windows DLL에서는 작동하지 않습니다.

1
Raithlin

스마트 어셈블리 더 많은 일을 할 수 있습니다. dll에 관리되지 않는 코드가 있으면 dll을 단일 어셈블리에 병합 할 수 없으며 대신 필요한 종속성을 리소스로 기본 exe에 포함시킬 수 있습니다. 그것의 플립 사이드는 자유롭지 않습니다.

리소스에 dll을 포함시킨 다음 AppDomain의 어셈블리 ResolveHandler에 의존하여이 작업을 수동으로 수행 할 수 있습니다. 혼합 모드 dll에 관해서는, ResolveHandler 접근법의 많은 변형과 특징이 나를 위해 작동하지 않는다는 것을 발견했습니다 (모두 dll 바이트를 메모리로 읽고 읽습니다). 그들은 모두 관리되는 dll에서 일했습니다. 다음은 나를 위해 일한 것입니다.

static void Main()
{
    AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
    {
        string assemblyName = new AssemblyName(args.Name).Name;
        if (assemblyName.EndsWith(".resources"))
            return null;

        string dllName = assemblyName + ".dll";
        string dllFullPath = Path.Combine(GetMyApplicationSpecificPath(), dllName);

        using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName))
        {
            byte[] data = new byte[stream.Length];
            s.Read(data, 0, data.Length);

            //or just byte[] data = new BinaryReader(s).ReadBytes((int)s.Length);

            File.WriteAllBytes(dllFullPath, data);
        }

        return Assembly.LoadFrom(dllFullPath);
    };
}

여기서 핵심은 바이트를 파일에 쓰고 해당 위치에서로드하는 것입니다. 닭고기 및 계란 문제를 방지하려면 어셈블리에 액세스하기 전에 핸들러를 선언하고로드 (어셈블리 해결) 파트 내부에서 어셈블리 멤버에 액세스하거나 어셈블리를 처리해야하는 항목을 인스턴스화하지 않아야합니다. 또한 임시 파일이 다른 프로그램이나 사용자가 지울 수 있기 때문에 GetMyApplicationSpecificPath()이 임시 디렉토리가 아닌지 확인하십시오 (프로그램이 dll에 액세스하는 동안 삭제되지는 않지만 최소한 AppData는 좋은 위치에 있습니다. 또한 매번 바이트를 작성해야한다는 것을 주목하십시오 .dll이 이미 존재하는 위치에서로드 할 수 없습니다.

어셈블리가 완전히 관리되지 않으면 이러한 dll을로드하는 방법에 대해 link 또는 this 를 볼 수 있습니다.

0
nawfal

Thinstall 은 하나의 솔루션입니다. 기본 Windows 응용 프로그램의 경우 DLL 이진 리소스 개체로 포함시킨 다음 런타임에 추출하기 전에 추출하는 것이 좋습니다.

0
titanae