programing

dlls를 wpf를 사용하여 단일 .exe로 Marge하다

closeapi 2023. 4. 16. 15:09
반응형

dlls를 wpf를 사용하여 단일 .exe로 Marge하다

저는 현재 의존관계가 많은 프로젝트를 진행하고 있습니다.모든 참조된 dll을 임베디드 리소스와 마찬가지로 .exe로 컴파일하고 싶습니다.ILMerge를 시도했지만 .xaml 리소스를 처리할 수 없습니다.

그래서 질문입니다.여러 종속성을 가진 WPF 프로젝트를 하나의 .exe로 병합할 수 있는 방법이 있습니까?

http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application

이것은 저에게 매력적으로 작용했고, 완전히 무료입니다.

블로그가 사라질 경우를 대비해서 코드를 추가합니다.

1)을 1) ㄴㄴㄹ 수 하세요..csproj 삭제:

<Target Name="AfterResolveReferences">
  <ItemGroup>
    <EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'">
      <LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName>
    </EmbeddedResource>
  </ItemGroup>
</Target>

메인을 ) ★★★★★★★★★★★★★★★★★★★★★★★★」Program.cs음음음같 뭇매하다

[STAThreadAttribute]
public static void Main()
{
    AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
    App.Main();
}

) 3) 을 합니다.OnResolveAssembly★★★★

private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
    Assembly executingAssembly = Assembly.GetExecutingAssembly();
    AssemblyName assemblyName = new AssemblyName(args.Name);

    var path = assemblyName.Name + ".dll";
    if (assemblyName.CultureInfo.Equals(CultureInfo.InvariantCulture) == false) path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path);

    using (Stream stream = executingAssembly.GetManifestResourceStream(path))
    {
        if (stream == null) return null;

        var assemblyRawBytes = new byte[stream.Length];
        stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
        return Assembly.Load(assemblyRawBytes);
    }
}

Costura를 사용하세요.Fody - Nuget Pkg으로 제공되므로 리소스를 어셈블리에 삽입할 수 있습니다.

Install-Package Costura.Fody

프로젝트에 추가한 참조는 모두 메인 어셈블리에 자동으로 포함됩니다.

{smartassembly}도 이러한 제품 중 하나입니다.그것은 당신의 dls를 관찰하거나 박아넣을 수 있다.

http://www.smartassembly.com/ 를 사용해 보세요.

또, 애플리케이션의 많은 개선을 실시해, 보다 고속으로 실행할 수도 있습니다.

그리고 네.WPF 에 사용할 수 있습니다.

업데이트 8/06/2015: ILRepack 2.0.0(ILMerge의 오픈 소스 대체)은 현재 대부분의 WPF 케이스 머지를 지원하고 있습니다.https://twitter.com/Gluckies/status/607680149157462016

ILMerge 웹사이트에 게재된 바와 같이, Jeffrey Richter의 이러한 dls를 리소스로 취급합니다.

많은 응용 프로그램은 많은 DLL 파일에 의존하는 EXE 파일로 구성됩니다.이 애플리케이션을 전개할 때는, 모든 파일을 전개할 필요가 있습니다.그러나 단일 EXE 파일만 배포하는 데 사용할 수 있는 방법이 있습니다.우선, Microsoft 의 일부로서 출하되고 있지 않다.EXE 파일에 의존하고 있는 모든 DLL 파일을 특정합니다.NET Framework 자체.그런 다음 이러한 DLL을 Visual Studio 프로젝트에 추가하십시오.추가하는 각 DLL 파일에 대해 해당 속성을 표시하고 "빌드 작업"을 "포함된 리소스"로 변경합니다.이것에 의해, C# 컴파일러는 EXE 파일에 DLL 파일을 짜넣습니다.이 EXE 파일을 1개 전개할 수 있습니다.실행 시 CLR이 종속 DLL 어셈블리를 찾을 수 없으므로 문제가 발생합니다.이 문제를 해결하려면 응용 프로그램이 초기화될 때 AppDomain의 ResolveAssembly 이벤트에 콜백 메서드를 등록하십시오.코드는 다음과 같습니다.

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {

   String resourceName = "AssemblyLoadingAndReflection." +

      new AssemblyName(args.Name).Name + ".dll";

   using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) {

      Byte[] assemblyData = new Byte[stream.Length];

      stream.Read(assemblyData, 0, assemblyData.Length);

      return Assembly.Load(assemblyData);

   }

}; 

이제 스레드가 종속 DLL 파일의 유형을 참조하는 메서드를 처음 호출하면 AssemblyResolve 이벤트가 발생하고 위의 콜백코드가 원하는 임베디드 DLL 리소스를 검색하여 바이트를 인수로서 사용하는 어셈블리의 로드 메서드의 오버로드를 호출하여 로드합니다.

.NET 원자로는 조립체를 병합하는 기능을 가지고 있으며 비용이 많이 들지 않습니다.

이것은 마티외에서 인용된 코드를 수정한 것으로, 코드를 추출하기 위해서 네임스페이스를 알 필요가 없습니다.WPF 의 경우는, 애플리케이션의 기동 이벤트 코드에 입력합니다.

AppDomain.CurrentDomain.AssemblyResolve += (s, args) =>
{
    // Note: Requires a using statement for System.Reflection and System.Diagnostics.
    Assembly assembly = Assembly.GetExecutingAssembly();
    List<string> embeddedResources = new List<string>(assembly.GetManifestResourceNames());
    string assemblyName = new AssemblyName(args.Name).Name;
    string fileName = string.Format("{0}.dll", assemblyName);
    string resourceName = embeddedResources.Where(ern => ern.EndsWith(fileName)).FirstOrDefault();
    if (!string.IsNullOrWhiteSpace(resourceName))
    {
        using (var stream = assembly.GetManifestResourceStream(resourceName))
        {
            Byte[] assemblyData = new Byte[stream.Length];
            stream.Read(assemblyData, 0, assemblyData.Length);
            var test = Assembly.Load(assemblyData);
            string namespace_ = test.GetTypes().Where(t => t.Name == assemblyName).Select(t => t.Namespace).FirstOrDefault();
#if DEBUG
            Debug.WriteLine(string.Format("\tNamespace for '{0}' is '{1}'", fileName, namespace_));
#endif
            return Assembly.Load(assemblyData);
        }
    }

    return null;
}; 

컴파일 시 사용할 수 있도록 ExternalDLLs라는 이름의 폴더를 만들고 거기에 dlls를 복사하여 위와 같이 Embedded Resource로 설정합니다.코드에서 사용하려면 참조를 설정해야 하지만 로컬 복사를 False로 설정해야 합니다.코드를 오류 없이 깔끔하게 컴파일하려면 코드 내의 스테이트먼트를 dls 네임스페이스로 설정해야 합니다.

여기에서는 임베디드 자원명을 회전시켜 출력창에 그 네임스페이스를 표시합니다.

private void getEmbeddedResourceNamespaces()
{
    // Note: Requires a using statement for System.Reflection and System.Diagnostics.
    Assembly assembly = Assembly.GetExecutingAssembly();
    List<string> embeddedResourceNames = new List<string>(assembly.GetManifestResourceNames());
    foreach (string resourceName in embeddedResourceNames)
    {
        using (var stream = assembly.GetManifestResourceStream(resourceName))
        {
            Byte[] assemblyData = new Byte[stream.Length];
            stream.Read(assemblyData, 0, assemblyData.Length);
            try
            {
                var test = Assembly.Load(assemblyData);
                foreach (Type type in test.GetTypes())
                {
                    Debug.WriteLine(string.Format("\tNamespace for '{0}' is '{1}'", type.Name, type.Namespace));
                }
            }
            catch 
            {
            }
        }
    }
}

.Netz ( http://madebits.com/netz/ )를 사용해 보세요.맥주와 같이 무료이며, 타겟이 exe라면 좋은 일을 할 수 있습니다.

.NET Core 3.0 이후 이 기능은 의 일부가 되었습니다.네트워크:

https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0#single-file-executables

다음을 사용하여 단일 실행 파일로 게시할 수 있습니다.dotnet:

dotnet publish -r win-x64 -p:PublishSingleFile=true

또는 Visual Studio에서 동일한 작업을 수행할 수 있습니다. Publish Profile Settings에서 대상 런타임(단일 파일로 게시하려면 대상 런타임 중 하나를 선택해야 함)을 선택한 다음 "File Select Options" 섹션을 확장하고 "Product Single File"을 선택합니다.정확한 단계는 Visual Studio 버전에 따라 다를 수 있습니다.

이러한 디폴트는, 로 지정할 수도 있습니다..csproj파일:

<PropertyGroup>
  <RuntimeIdentifier>win10-x64</RuntimeIdentifier>
  <PublishSingleFile>true</PublishSingleFile>
</PropertyGroup>

다만, 이 어프로치를 사용하면, 유닛 테스트의 실행에 문제가 있었기 때문에, 공개시에 그 옵션을 선택하는 것만으로 끝납니다.

  1. 이 파일을 .syslogrofj 파일에 추가합니다.

>

<Target Name="AfterResolveReferences">
  <ItemGroup>
    <EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'">
      <LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName>
    </EmbeddedResource>
  </ItemGroup>
</Target>
  1. 프로젝트/속성/응용프로그램/스타업오브젝트 우클릭/신호로 선택.프로그램.

  2. program.cs 파일에 다음을 추가합니다.

    시스템을 사용합니다.반사, 시스템 사용.IO(시스템 사용).세계화

    [STAThreadAttribute]
    static void Main()
    {
        AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
        ...
    
    
    private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
    {
        Assembly executingAssembly = Assembly.GetExecutingAssembly();
        AssemblyName assemblyName = new AssemblyName(args.Name);
        string path = assemblyName.Name + ".dll";
        if (assemblyName.CultureInfo.Equals(CultureInfo.InvariantCulture) == false)
        {
            path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path);
        }
        using (Stream stream = executingAssembly.GetManifestResourceStream(path))
        {
            if (stream == null)
                return null;
            byte[] assemblyRawBytes = new byte[stream.Length];
            stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
            return Assembly.Load(assemblyRawBytes);
        }
    }   
    

출처 : http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application

다른 솔루션은 모두 C#에 있기 때문에 VB용으로 이것이 필요했습니다.NET, 여기에는 C#의 += 구문 대신 구성 변경 내용을 삽입할 위치, 필요한 가져오기 및 핸들러 추가 방법에 대한 설명이 포함됩니다.

각 프로젝트가 아닌 모든 WPF 응용 프로그램에 대해 코드를 단일 EXE로 컴파일하려면 다음 항목을 추가해야 합니다.출력 폴더에는 DLL이 계속 포함되지만 EXE에는 모든 DLL이 포함됩니다.

  1. WPF 프로젝트 언로드(보통 뷰)
  2. 프로젝트를 오른쪽 클릭하여 편집합니다.
  3. 문서에서 이 줄 뒤에 다음 코드를 붙여넣습니다.
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />

붙여넣을 코드

<Target Name="AfterResolveReferences">
   <ItemGroup>
      <EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'">
         <LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)
         </LogicalName>
      </EmbeddedResource>
   </ItemGroup>
</Target>
  1. 프로젝트를 닫고 저장한 후 다시 로드합니다.
  2. Application.xaml.vb 파일에 다음 코드를 추가합니다.파일에 이미 존재하는 경우는, 이 코드를 추가합니다.
Imports System.Reflection
Imports System.Globalization
Imports System.IO

Class Application

    Public Sub New()
        AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf OnResolveAssembly
    End Sub

    Private Shared Function OnResolveAssembly(ByVal sender As Object, ByVal args As ResolveEventArgs) As Assembly

        Dim executingAssembly As Assembly = Assembly.GetExecutingAssembly()
        Dim assemblyName As AssemblyName = New AssemblyName(args.Name)
        Dim path = assemblyName.Name & ".dll"
        If assemblyName.CultureInfo.Equals(CultureInfo.InvariantCulture) = False Then path = String.Format("{0}\{1}", assemblyName.CultureInfo, path)

        Using stream As Stream = executingAssembly.GetManifestResourceStream(path)
            If stream Is Nothing Then Return Nothing
            Dim assemblyRawBytes = New Byte(stream.Length - 1) {}
            stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length)
            Return Assembly.Load(assemblyRawBytes)
        End Using

    End Function

End Class

언급URL : https://stackoverflow.com/questions/1025843/merging-dlls-into-a-single-exe-with-wpf

반응형