Пример #1
0
        /// <summary>
        /// Create a ComHost with an embedded CLSIDMap file to map CLSIDs to .NET Classes.
        /// </summary>
        /// <param name="comHostSourceFilePath">The path of Apphost template, which has the place holder</param>
        /// <param name="comHostDestinationFilePath">The destination path for desired location to place, including the file name</param>
        /// <param name="clsidmapFilePath">The path to the *.clsidmap file.</param>
        public static void Create(
            string comHostSourceFilePath,
            string comHostDestinationFilePath,
            string clsidmapFilePath)
        {
            var destinationDirectory = new FileInfo(comHostDestinationFilePath).Directory.FullName;

            if (!Directory.Exists(destinationDirectory))
            {
                Directory.CreateDirectory(destinationDirectory);
            }

            // Copy apphost to destination path so it inherits the same attributes/permissions.
            File.Copy(comHostSourceFilePath, comHostDestinationFilePath, overwrite: true);

            if (!ResourceUpdater.IsSupportedOS())
            {
                throw new ComHostCustomizationUnsupportedOSException();
            }

            string clsidMap = File.ReadAllText(clsidmapFilePath);

            byte[] clsidMapBytes = Encoding.UTF8.GetBytes(clsidMap);

            using (ResourceUpdater updater = new ResourceUpdater(comHostDestinationFilePath))
            {
                updater.AddResource(clsidMapBytes, (IntPtr)ClsidmapResourceType, (IntPtr)ClsidmapResourceId);
                updater.Update();
            }
        }
Пример #2
0
        /// <summary>
        /// Create an AppHost with embedded configuration of app binary location
        /// </summary>
        /// <param name="appHostSourceFilePath">The path of Apphost template, which has the place holder</param>
        /// <param name="appHostDestinationFilePath">The destination path for desired location to place, including the file name</param>
        /// <param name="appBinaryFilePath">Full path to app binary or relative path to the result apphost file</param>
        /// <param name="windowsGraphicalUserInterface">Specify whether to set the subsystem to GUI. Only valid for PE apphosts.</param>
        /// <param name="assemblyToCopyResorcesFrom">Path to the intermediate assembly, used for copying resources to PE apphosts.</param>
        public static void CreateAppHost(
            string appHostSourceFilePath,
            string appHostDestinationFilePath,
            string appBinaryFilePath,
            bool windowsGraphicalUserInterface = false,
            string assemblyToCopyResorcesFrom  = null)
        {
            var bytesToWrite = Encoding.UTF8.GetBytes(appBinaryFilePath);

            if (bytesToWrite.Length > 1024)
            {
                throw new AppNameTooLongException(appBinaryFilePath);
            }

            CopyAppHost(appHostSourceFilePath, appHostDestinationFilePath);

            // Re-write the destination apphost with the proper contents.
            bool appHostIsPEImage = false;

            using (var memoryMappedFile = MemoryMappedFile.CreateFromFile(appHostDestinationFilePath))
            {
                using (MemoryMappedViewAccessor accessor = memoryMappedFile.CreateViewAccessor())
                {
                    BinaryUtils.SearchAndReplace(accessor, AppBinaryPathPlaceholderSearchValue, bytesToWrite);

                    appHostIsPEImage = BinaryUtils.IsPEImage(accessor);

                    if (windowsGraphicalUserInterface)
                    {
                        if (!appHostIsPEImage)
                        {
                            throw new AppHostNotPEFileException();
                        }

                        BinaryUtils.SetWindowsGraphicalUserInterfaceBit(accessor);
                    }
                }
            }

            if (assemblyToCopyResorcesFrom != null && appHostIsPEImage)
            {
                if (ResourceUpdater.IsSupportedOS())
                {
                    // Copy resources from managed dll to the apphost
                    new ResourceUpdater(appHostDestinationFilePath)
                    .AddResourcesFromPEImage(assemblyToCopyResorcesFrom)
                    .Update();
                }
                else
                {
                    throw new AppHostCustomizationUnsupportedOSException();
                }
            }

            // Memory-mapped write does not updating last write time
            File.SetLastWriteTimeUtc(appHostDestinationFilePath, DateTime.UtcNow);
        }
Пример #3
0
        /// <summary>
        /// Create a ComHost with an embedded CLSIDMap file to map CLSIDs to .NET Classes.
        /// </summary>
        /// <param name="comHostSourceFilePath">The path of Apphost template, which has the place holder</param>
        /// <param name="comHostDestinationFilePath">The destination path for desired location to place, including the file name</param>
        /// <param name="clsidmapFilePath">The path to the *.clsidmap file.</param>
        /// <param name="typeLibraries">Resource ids for tlbs and paths to the tlb files to be embedded.</param>
        public static void Create(
            string comHostSourceFilePath,
            string comHostDestinationFilePath,
            string clsidmapFilePath,
            IReadOnlyDictionary <int, string> typeLibraries = null)
        {
            var destinationDirectory = new FileInfo(comHostDestinationFilePath).Directory.FullName;

            if (!Directory.Exists(destinationDirectory))
            {
                Directory.CreateDirectory(destinationDirectory);
            }

            // Copy apphost to destination path so it inherits the same attributes/permissions.
            File.Copy(comHostSourceFilePath, comHostDestinationFilePath, overwrite: true);

            if (!ResourceUpdater.IsSupportedOS())
            {
                throw new ComHostCustomizationUnsupportedOSException();
            }

            string clsidMap = File.ReadAllText(clsidmapFilePath);

            byte[] clsidMapBytes = Encoding.UTF8.GetBytes(clsidMap);

            using (ResourceUpdater updater = new ResourceUpdater(comHostDestinationFilePath))
            {
                updater.AddResource(clsidMapBytes, (IntPtr)ClsidmapResourceType, (IntPtr)ClsidmapResourceId);
                if (typeLibraries is not null)
                {
                    foreach (var typeLibrary in typeLibraries)
                    {
                        if (!ResourceUpdater.IsIntResource((IntPtr)typeLibrary.Key))
                        {
                            throw new InvalidTypeLibraryIdException(typeLibrary.Value, typeLibrary.Key);
                        }

                        try
                        {
                            byte[] tlbFileBytes = File.ReadAllBytes(typeLibrary.Value);
                            updater.AddResource(tlbFileBytes, "typelib", (IntPtr)typeLibrary.Key);
                        }
                        catch (FileNotFoundException ex)
                        {
                            throw new TypeLibraryDoesNotExistException(typeLibrary.Value, ex);
                        }
                        catch (HResultException hr) when(hr.Win32HResult == E_INVALIDARG)
                        {
                            throw new InvalidTypeLibraryException(typeLibrary.Value, hr);
                        }
                    }
                }
                updater.Update();
            }
        }
Пример #4
0
        public void CreateApphostShellShim(FilePath entryPoint, FilePath shimPath)
        {
            string appHostSourcePath;

            if (OperatingSystem.IsWindows())
            {
                appHostSourcePath = Path.Combine(_appHostSourceDirectory, ApphostNameWithoutExtension + ".exe");
            }
            else
            {
                appHostSourcePath = Path.Combine(_appHostSourceDirectory, ApphostNameWithoutExtension);
            }

            var    appHostDestinationFilePath = Path.GetFullPath(shimPath.Value);
            string entryPointFullPath         = Path.GetFullPath(entryPoint.Value);
            var    appBinaryFilePath          = Path.GetRelativePath(Path.GetDirectoryName(appHostDestinationFilePath), entryPointFullPath);


            if (ResourceUpdater.IsSupportedOS())
            {
                var windowsGraphicalUserInterfaceBit = PEUtils.GetWindowsGraphicalUserInterfaceBit(entryPointFullPath);
                HostWriter.CreateAppHost(appHostSourceFilePath: appHostSourcePath,
                                         appHostDestinationFilePath: appHostDestinationFilePath,
                                         appBinaryFilePath: appBinaryFilePath,
                                         windowsGraphicalUserInterface: (windowsGraphicalUserInterfaceBit == WindowsGUISubsystem),
                                         assemblyToCopyResorcesFrom: entryPointFullPath);
            }
            else
            {
                // by passing null to assemblyToCopyResorcesFrom, it will skip copying resources,
                // which is only supported on Windows
                HostWriter.CreateAppHost(appHostSourceFilePath: appHostSourcePath,
                                         appHostDestinationFilePath: appHostDestinationFilePath,
                                         appBinaryFilePath: appBinaryFilePath,
                                         windowsGraphicalUserInterface: false,
                                         assemblyToCopyResorcesFrom: null,
                                         enableMacOSCodeSign: OperatingSystem.IsMacOS());
            }

            _filePermissionSetter.SetUserExecutionPermission(appHostDestinationFilePath);
        }
Пример #5
0
        /// <summary>
        /// Create an AppHost with embedded configuration of app binary location
        /// </summary>
        /// <param name="appHostSourceFilePath">The path of Apphost template, which has the place holder</param>
        /// <param name="appHostDestinationFilePath">The destination path for desired location to place, including the file name</param>
        /// <param name="appBinaryFilePath">Full path to app binary or relative path to the result apphost file</param>
        /// <param name="windowsGraphicalUserInterface">Specify whether to set the subsystem to GUI. Only valid for PE apphosts.</param>
        /// <param name="assemblyToCopyResorcesFrom">Path to the intermediate assembly, used for copying resources to PE apphosts.</param>
        public static void CreateAppHost(
            string appHostSourceFilePath,
            string appHostDestinationFilePath,
            string appBinaryFilePath,
            bool windowsGraphicalUserInterface = false,
            string assemblyToCopyResorcesFrom  = null)
        {
            var bytesToWrite = Encoding.UTF8.GetBytes(appBinaryFilePath);

            if (bytesToWrite.Length > 1024)
            {
                throw new AppNameTooLongException(appBinaryFilePath);
            }

            BinaryUtils.CopyFile(appHostSourceFilePath, appHostDestinationFilePath);
            bool appHostIsPEImage = false;

            void RewriteAppHost()
            {
                // Re-write the destination apphost with the proper contents.
                using (var memoryMappedFile = MemoryMappedFile.CreateFromFile(appHostDestinationFilePath))
                {
                    using (MemoryMappedViewAccessor accessor = memoryMappedFile.CreateViewAccessor())
                    {
                        BinaryUtils.SearchAndReplace(accessor, AppBinaryPathPlaceholderSearchValue, bytesToWrite);

                        appHostIsPEImage = BinaryUtils.IsPEImage(accessor);

                        if (windowsGraphicalUserInterface)
                        {
                            if (!appHostIsPEImage)
                            {
                                throw new AppHostNotPEFileException();
                            }

                            BinaryUtils.SetWindowsGraphicalUserInterfaceBit(accessor);
                        }
                    }
                }
            }

            void UpdateResources()
            {
                if (assemblyToCopyResorcesFrom != null && appHostIsPEImage)
                {
                    if (ResourceUpdater.IsSupportedOS())
                    {
                        // Copy resources from managed dll to the apphost
                        new ResourceUpdater(appHostDestinationFilePath)
                        .AddResourcesFromPEImage(assemblyToCopyResorcesFrom)
                        .Update();
                    }
                    else
                    {
                        throw new AppHostCustomizationUnsupportedOSException();
                    }
                }
            }

            try
            {
                RetryUtil.RetryOnIOError(RewriteAppHost);

                RetryUtil.RetryOnWin32Error(UpdateResources);

                // Memory-mapped write does not updating last write time
                RetryUtil.RetryOnIOError(() => File.SetLastWriteTimeUtc(appHostDestinationFilePath, DateTime.UtcNow));
            }
            catch (Exception ex)
            {
                // Delete the destination file so we don't leave an unmodified apphost
                try
                {
                    File.Delete(appHostDestinationFilePath);
                }
                catch (Exception failedToDeleteEx)
                {
                    throw new AggregateException(ex, failedToDeleteEx);
                }

                throw;
            }
        }
Пример #6
0
        /// <summary>
        /// Create an AppHost with embedded configuration of app binary location
        /// </summary>
        /// <param name="appHostSourceFilePath">The path of Apphost template, which has the place holder</param>
        /// <param name="appHostDestinationFilePath">The destination path for desired location to place, including the file name</param>
        /// <param name="appBinaryFilePath">Full path to app binary or relative path to the result apphost file</param>
        /// <param name="windowsGraphicalUserInterface">Specify whether to set the subsystem to GUI. Only valid for PE apphosts.</param>
        /// <param name="assemblyToCopyResorcesFrom">Path to the intermediate assembly, used for copying resources to PE apphosts.</param>
        public static void CreateAppHost(
            string appHostSourceFilePath,
            string appHostDestinationFilePath,
            string appBinaryFilePath,
            bool windowsGraphicalUserInterface = false,
            string assemblyToCopyResorcesFrom  = null)
        {
            var bytesToWrite = Encoding.UTF8.GetBytes(appBinaryFilePath);

            if (bytesToWrite.Length > 1024)
            {
                throw new AppNameTooLongException(appBinaryFilePath);
            }

            BinaryUtils.CopyFile(appHostSourceFilePath, appHostDestinationFilePath);

            bool appHostIsPEImage = false;

            void RewriteAppHost()
            {
                // Re-write the destination apphost with the proper contents.
                using (var memoryMappedFile = MemoryMappedFile.CreateFromFile(appHostDestinationFilePath))
                {
                    using (MemoryMappedViewAccessor accessor = memoryMappedFile.CreateViewAccessor())
                    {
                        BinaryUtils.SearchAndReplace(accessor, AppBinaryPathPlaceholderSearchValue, bytesToWrite);

                        appHostIsPEImage = BinaryUtils.IsPEImage(accessor);

                        if (windowsGraphicalUserInterface)
                        {
                            if (!appHostIsPEImage)
                            {
                                throw new AppHostNotPEFileException();
                            }

                            BinaryUtils.SetWindowsGraphicalUserInterfaceBit(accessor);
                        }
                    }
                }
            }

            void UpdateResources()
            {
                if (assemblyToCopyResorcesFrom != null && appHostIsPEImage)
                {
                    if (ResourceUpdater.IsSupportedOS())
                    {
                        // Copy resources from managed dll to the apphost
                        new ResourceUpdater(appHostDestinationFilePath)
                        .AddResourcesFromPEImage(assemblyToCopyResorcesFrom)
                        .Update();
                    }
                    else
                    {
                        throw new AppHostCustomizationUnsupportedOSException();
                    }
                }
            }

            void RemoveSignatureIfMachO()
            {
                MachOUtils.RemoveSignature(appHostDestinationFilePath);
            }

            void SetLastWriteTime()
            {
                // Memory-mapped write does not updating last write time
                File.SetLastWriteTimeUtc(appHostDestinationFilePath, DateTime.UtcNow);
            }

            try
            {
                if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    var       filePermissionOctal = Convert.ToInt32("755", 8); // -rwxr-xr-x
                    const int EINTR           = 4;
                    int       chmodReturnCode = 0;

                    do
                    {
                        chmodReturnCode = chmod(appHostDestinationFilePath, filePermissionOctal);
                    }while (chmodReturnCode == -1 && Marshal.GetLastWin32Error() == EINTR);

                    if (chmodReturnCode == -1)
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error(), $"Could not set file permission {filePermissionOctal} for {appHostDestinationFilePath}.");
                    }
                }

                RetryUtil.RetryOnIOError(RewriteAppHost);

                RetryUtil.RetryOnWin32Error(UpdateResources);

                RetryUtil.RetryOnIOError(RemoveSignatureIfMachO);

                RetryUtil.RetryOnIOError(SetLastWriteTime);
            }
            catch (Exception ex)
            {
                // Delete the destination file so we don't leave an unmodified apphost
                try
                {
                    File.Delete(appHostDestinationFilePath);
                }
                catch (Exception failedToDeleteEx)
                {
                    throw new AggregateException(ex, failedToDeleteEx);
                }

                throw;
            }
        }
Пример #7
0
        /// <summary>
        /// Create an AppHost with embedded configuration of app binary location
        /// </summary>
        /// <param name="appHostSourceFilePath">The path of Apphost template, which has the place holder</param>
        /// <param name="appHostDestinationFilePath">The destination path for desired location to place, including the file name</param>
        /// <param name="appBinaryFilePath">Full path to app binary or relative path to the result apphost file</param>
        /// <param name="windowsGraphicalUserInterface">Specify whether to set the subsystem to GUI. Only valid for PE apphosts.</param>
        /// <param name="assemblyToCopyResorcesFrom">Path to the intermediate assembly, used for copying resources to PE apphosts.</param>
        public static void CreateAppHost(
            string appHostSourceFilePath,
            string appHostDestinationFilePath,
            string appBinaryFilePath,
            bool windowsGraphicalUserInterface = false,
            string assemblyToCopyResorcesFrom  = null)
        {
            var bytesToWrite = Encoding.UTF8.GetBytes(appBinaryFilePath);

            if (bytesToWrite.Length > 1024)
            {
                throw new AppNameTooLongException(appBinaryFilePath);
            }

            bool appHostIsPEImage = false;

            void RewriteAppHost(MemoryMappedViewAccessor accessor)
            {
                // Re-write the destination apphost with the proper contents.
                BinaryUtils.SearchAndReplace(accessor, AppBinaryPathPlaceholderSearchValue, bytesToWrite);

                appHostIsPEImage = PEUtils.IsPEImage(accessor);

                if (windowsGraphicalUserInterface)
                {
                    if (!appHostIsPEImage)
                    {
                        throw new AppHostNotPEFileException();
                    }

                    PEUtils.SetWindowsGraphicalUserInterfaceBit(accessor);
                }
            }

            void UpdateResources()
            {
                if (assemblyToCopyResorcesFrom != null && appHostIsPEImage)
                {
                    if (ResourceUpdater.IsSupportedOS())
                    {
                        // Copy resources from managed dll to the apphost
                        new ResourceUpdater(appHostDestinationFilePath)
                        .AddResourcesFromPEImage(assemblyToCopyResorcesFrom)
                        .Update();
                    }
                    else
                    {
                        throw new AppHostCustomizationUnsupportedOSException();
                    }
                }
            }

            try
            {
                RetryUtil.RetryOnIOError(() =>
                {
                    FileStream appHostSourceStream    = null;
                    MemoryMappedFile memoryMappedFile = null;
                    MemoryMappedViewAccessor memoryMappedViewAccessor = null;
                    try
                    {
                        // Open the source host file.
                        appHostSourceStream      = new FileStream(appHostSourceFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
                        memoryMappedFile         = MemoryMappedFile.CreateFromFile(appHostSourceStream, null, 0, MemoryMappedFileAccess.Read, HandleInheritability.None, true);
                        memoryMappedViewAccessor = memoryMappedFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.CopyOnWrite);

                        // Get the size of the source app host to ensure that we don't write extra data to the destination.
                        // On Windows, the size of the view accessor is rounded up to the next page boundary.
                        long sourceAppHostLength = appHostSourceStream.Length;

                        // Transform the host file in-memory.
                        RewriteAppHost(memoryMappedViewAccessor);

                        // Save the transformed host.
                        using (FileStream fileStream = new FileStream(appHostDestinationFilePath, FileMode.Create))
                        {
                            BinaryUtils.WriteToStream(memoryMappedViewAccessor, fileStream, sourceAppHostLength);

                            // Remove the signature from MachO hosts.
                            if (!appHostIsPEImage)
                            {
                                MachOUtils.RemoveSignature(fileStream);
                            }
                        }
                    }
                    finally
                    {
                        memoryMappedViewAccessor?.Dispose();
                        memoryMappedFile?.Dispose();
                        appHostSourceStream?.Dispose();
                    }
                });

                RetryUtil.RetryOnWin32Error(UpdateResources);

                if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    var       filePermissionOctal = Convert.ToInt32("755", 8); // -rwxr-xr-x
                    const int EINTR           = 4;
                    int       chmodReturnCode = 0;

                    do
                    {
                        chmodReturnCode = chmod(appHostDestinationFilePath, filePermissionOctal);
                    }while (chmodReturnCode == -1 && Marshal.GetLastWin32Error() == EINTR);

                    if (chmodReturnCode == -1)
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error(), $"Could not set file permission {filePermissionOctal} for {appHostDestinationFilePath}.");
                    }
                }
            }
            catch (Exception ex)
            {
                // Delete the destination file so we don't leave an unmodified apphost
                try
                {
                    File.Delete(appHostDestinationFilePath);
                }
                catch (Exception failedToDeleteEx)
                {
                    throw new AggregateException(ex, failedToDeleteEx);
                }

                throw;
            }
        }