Exemplo n.º 1
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 = 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();
                    }
                }
            }

            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;
            }
        }