Implemented VirtualPrinterDriver project
This commit is contained in:
parent
f29c84821b
commit
5c87967c3f
125 changed files with 8191 additions and 0 deletions
51
Common/VirtualPrinter.Utils/Consts.cs
Normal file
51
Common/VirtualPrinter.Utils/Consts.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
namespace VirtualPrinter.Utils
|
||||
{
|
||||
public struct Files
|
||||
{
|
||||
public const string FILES = @"Files";
|
||||
public const string PRINTER_SERVICE_EXE = "VPDAgent.exe";
|
||||
public const string SETUP_DRIVER_EXE = "setupdrv.exe";
|
||||
public const string AGENT_PROGRESS_EXE = "VPDAgentProgress.exe";
|
||||
public const string DILIVERY_EXE = "delivery.exe";
|
||||
public const string LICENCE_FILE = "";
|
||||
public const string PRE_CONVERTER = @"C:\Program Files (x86)\MyPreConverter.exe ARG";
|
||||
public const string POST_CONVERTER = @"C:\Program Files (x86)\MyPostConverter.exe ARG";
|
||||
}
|
||||
|
||||
public struct Keys
|
||||
{
|
||||
public const string PRINTER_DRIVER_KEY32 = @"SOFTWARE\vpd\PrinterDriver";
|
||||
public const string PRINTER_DRIVER_KEY64 = @"SOFTWARE\Wow6432Node\vpd\PrinterDriver";
|
||||
public const string POSTCONVERTER_KEY = @"Application\Postconverter";
|
||||
public const string PRECONVERTER_KEY = @"Application\Preconverter";
|
||||
public const string CONVERTER_KEY = @"Converter";
|
||||
public const string CONVERTER_PDF_KEY = CONVERTER_KEY + @"\PDF";
|
||||
public const string CONVERTER_TIFF_KEY = CONVERTER_KEY + @"\TIFF";
|
||||
public const string CONVERTER_REDIRECT_KEY = CONVERTER_KEY + @"\Redirect";
|
||||
}
|
||||
|
||||
public struct KeyNames
|
||||
{
|
||||
public const string EXECUTABLE_FILE = "Executable File";
|
||||
public const string INSTALLATION_DIR = "Installation Directory";
|
||||
public const string THREADS = "Threads";
|
||||
public const string SHOW_PROGRESS = "Show Progress";
|
||||
public const string PAGES_PER_SHEET = "Pages per Sheet";
|
||||
public const string FILE_NAME_MASK = "File name mask";
|
||||
public const string OUTPUT_DIR = "Output Directory";
|
||||
public const string ENABLED = "Enabled";
|
||||
public const string MULTIPAGE = "Multipage";
|
||||
public const string PRODUCE_PDFA = "Produce PDFA";
|
||||
public const string ALLOW_PRINTING = "Allow printing";
|
||||
public const string ALLOW_COPYING = "Allow printing";
|
||||
public const string SUBSETTING = "Subsetting";
|
||||
public const string QUALITY = "Image Quality";
|
||||
public const string BITS_PIXEL = "Bits per pixel";
|
||||
public const string COMPRESSION = "Compression";
|
||||
public const string SERVER_PORT = "Server port";
|
||||
public const string RENDER_DPI = "RENDER: DPI";
|
||||
public const string FORMAT = "Intermediate Format";
|
||||
public const string PRINT_FORMAT = "Format";
|
||||
public const string PRINTER = "Printer";
|
||||
}
|
||||
}
|
||||
24
Common/VirtualPrinter.Utils/DirectoryHelper.cs
Normal file
24
Common/VirtualPrinter.Utils/DirectoryHelper.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
using System.IO;
|
||||
|
||||
using VirtualPrinter.Agent.Core;
|
||||
|
||||
namespace VirtualPrinter.Utils
|
||||
{
|
||||
public class DirectoryHelper : IDirectoryHelper
|
||||
{
|
||||
public string GetOutputDirectory(IExConfig config)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(config.ResolvedOutputDirectory))
|
||||
{
|
||||
var outputDir = Path.Combine(Path.GetTempPath(), "PrinterOutput");
|
||||
if (!Directory.Exists(outputDir))
|
||||
{
|
||||
Directory.CreateDirectory(outputDir);
|
||||
}
|
||||
return outputDir;
|
||||
}
|
||||
|
||||
return config.ResolvedOutputDirectory;
|
||||
}
|
||||
}
|
||||
}
|
||||
35
Common/VirtualPrinter.Utils/Properties/AssemblyInfo.cs
Normal file
35
Common/VirtualPrinter.Utils/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("VirtualPrinter.Utils")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("cd1c8e9d-5335-41ac-b0c0-88fd7c7c55f3")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
170
Common/VirtualPrinter.Utils/RegistryRepository.cs
Normal file
170
Common/VirtualPrinter.Utils/RegistryRepository.cs
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
using VirtualPrinter.Agent.Core;
|
||||
using VirtualPrinter.Agent.Core.Enums;
|
||||
|
||||
namespace VirtualPrinter.Utils
|
||||
{
|
||||
public class RegistryRepository : IRegistryRepository
|
||||
{
|
||||
private const short DefaultServerPort = 9101;
|
||||
|
||||
public bool TryGetGhostscriptPath(out string path)
|
||||
{
|
||||
path = null;
|
||||
|
||||
try
|
||||
{
|
||||
var regView = GetRegistryView();
|
||||
|
||||
using(var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, regView))
|
||||
{
|
||||
const string gsSubKey = @"SOFTWARE\GPL Ghostscript";
|
||||
using(var ghostscript = baseKey.OpenSubKey(gsSubKey))
|
||||
{
|
||||
CheckForNull(ghostscript, gsSubKey);
|
||||
var subKeys = ghostscript.GetSubKeyNames();
|
||||
|
||||
var lastSubKey = subKeys.Last();
|
||||
using(var subKey = ghostscript.OpenSubKey(lastSubKey))
|
||||
{
|
||||
CheckForNull(subKey, lastSubKey);
|
||||
path = subKey.GetValue("GS_LIB").ToString().Split(';').FirstOrDefault();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
path = Directory.GetParent(path).FullName;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Console.WriteLine(exception);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public IExConfig GetRegistryConfig()
|
||||
{
|
||||
var regView = GetRegistryView();
|
||||
var subKey = GetSubKey();
|
||||
var registryConfig = new RegistryConfig();
|
||||
|
||||
using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, regView))
|
||||
{
|
||||
using (var driver = baseKey.OpenSubKey(subKey))
|
||||
{
|
||||
CheckForNull(driver, subKey);
|
||||
|
||||
using(var key = driver.OpenSubKey(Keys.POSTCONVERTER_KEY))
|
||||
{
|
||||
CheckForNull(key, Keys.POSTCONVERTER_KEY);
|
||||
registryConfig.Postconverter = key.GetValue(KeyNames.EXECUTABLE_FILE).ToString();
|
||||
}
|
||||
|
||||
using(var key = driver.OpenSubKey(Keys.PRECONVERTER_KEY))
|
||||
{
|
||||
CheckForNull(key, Keys.PRECONVERTER_KEY);
|
||||
registryConfig.Preconverter = key.GetValue(KeyNames.EXECUTABLE_FILE).ToString();
|
||||
}
|
||||
|
||||
using (var key = driver.OpenSubKey(Keys.CONVERTER_KEY))
|
||||
{
|
||||
CheckForNull(key, Keys.CONVERTER_KEY);
|
||||
registryConfig.OutputDirectory = key.GetValue(KeyNames.OUTPUT_DIR).ToString();
|
||||
registryConfig.FileNameMask = key.GetValue(KeyNames.FILE_NAME_MASK).ToString();
|
||||
var portStr = key.GetValue(KeyNames.SERVER_PORT).ToString();
|
||||
registryConfig.PrinterPort = short.TryParse(portStr, out var portVal) ? portVal : DefaultServerPort;
|
||||
registryConfig.IntermediateFormat = key.GetValue(KeyNames.FORMAT)?.ToString().ToLower() == "ps" ? IntermediateFormat.Ps : IntermediateFormat.Xps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return registryConfig;
|
||||
}
|
||||
|
||||
[ContractAnnotation("key:null => void")]
|
||||
private void CheckForNull(RegistryKey key, string keyName)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new NullReferenceException(keyName);
|
||||
}
|
||||
}
|
||||
|
||||
public IUserConfig GetUserRegistryConfig(string sid)
|
||||
{
|
||||
var regView = GetRegistryView();
|
||||
var userConfig = new UserRegistryConfig();
|
||||
|
||||
using (var users = RegistryKey.OpenBaseKey(RegistryHive.Users, regView))
|
||||
{
|
||||
var subKey = $@"{sid}\{Keys.PRINTER_DRIVER_KEY32}";
|
||||
using (var driver = users.OpenSubKey(subKey))
|
||||
{
|
||||
CheckForNull(driver, subKey);
|
||||
|
||||
using (var converter = driver.OpenSubKey(Keys.CONVERTER_KEY))
|
||||
{
|
||||
CheckForNull(converter, Keys.CONVERTER_KEY);
|
||||
|
||||
subKey = "Redirect";
|
||||
using (var redirect = converter.OpenSubKey(subKey))
|
||||
{
|
||||
CheckForNull(redirect, subKey);
|
||||
|
||||
userConfig.RedirectEnabled = (int?) redirect.GetValue("Enabled") == 1;
|
||||
userConfig.RedirectPrinter = redirect.GetValue("Printer").ToString();
|
||||
userConfig.Format = converter.GetValue("Format").ToString();
|
||||
|
||||
var dpiStr = (string)driver.GetValue("RENDER: DPI");
|
||||
if (dpiStr == null)
|
||||
{
|
||||
userConfig.UserRenderDpi = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
userConfig.UserRenderDpi = double.TryParse(dpiStr, out var dpiVal) ? dpiVal : (double?) null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return userConfig;
|
||||
}
|
||||
|
||||
private RegistryView GetRegistryView()
|
||||
{
|
||||
if (Environment.Is64BitOperatingSystem)
|
||||
{
|
||||
return RegistryView.Registry64;
|
||||
}
|
||||
|
||||
return RegistryView.Registry32;
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
private string GetSubKey()
|
||||
{
|
||||
if (Environment.Is64BitOperatingSystem)
|
||||
{
|
||||
return Keys.PRINTER_DRIVER_KEY64;
|
||||
}
|
||||
|
||||
return Keys.PRINTER_DRIVER_KEY32;
|
||||
}
|
||||
}
|
||||
}
|
||||
95
Common/VirtualPrinter.Utils/Shell.cs
Normal file
95
Common/VirtualPrinter.Utils/Shell.cs
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
using VirtualPrinter.Agent.Core;
|
||||
using VirtualPrinter.Logging;
|
||||
|
||||
namespace VirtualPrinter.Utils
|
||||
{
|
||||
public class Shell : IShell
|
||||
{
|
||||
private readonly IVirtualPrinterLogger<Shell> _logger = new VirtualPrinterLogger<Shell>();
|
||||
|
||||
public void WriteIniEntry(string section, string key, string value, string iniFilePath)
|
||||
{
|
||||
Win32Sys.WritePrivateProfileString(section, key, value, iniFilePath);
|
||||
}
|
||||
|
||||
public T ReadIniEntry<T>(string section, string key, string iniFilePath)
|
||||
{
|
||||
var buffer = new StringBuilder(64 * 1024);
|
||||
Win32Sys.GetPrivateProfileString(section, key, string.Empty, buffer, buffer.Capacity, iniFilePath);
|
||||
var value = buffer.ToString().Trim();
|
||||
return (T)Convert.ChangeType(value, typeof(T));
|
||||
}
|
||||
|
||||
public void Execute(IJobInfo job, ISessionInfo session, string exe, string args)
|
||||
{
|
||||
var thr = new Thread
|
||||
(
|
||||
() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(exe))
|
||||
throw new FileNotFoundException(exe);
|
||||
#if DEBUG
|
||||
System.Diagnostics.Process.Start(exe, args);
|
||||
#else
|
||||
StartProcessAsUser(job, session, exe, args);
|
||||
#endif
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LogError(exception, "Failed to create process");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
thr.Start();
|
||||
}
|
||||
|
||||
public bool FileExists(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
throw new ArgumentException("The path may not be null or empty.");
|
||||
}
|
||||
|
||||
return File.Exists(path);
|
||||
}
|
||||
|
||||
private void StartProcessAsUser([NotNull]IJobInfo job, [NotNull]ISessionInfo session, string exe, string args)
|
||||
{
|
||||
if (job == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(job));
|
||||
}
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(session));
|
||||
}
|
||||
|
||||
var cmd = $@"""{exe}"" {args}";
|
||||
var id = session.Id;
|
||||
var user = job.MachineName.TrimStart('\\') + '\\' + job.UserName;
|
||||
LogDebug($"Executing '{cmd}' for '{user}' ({id})...");
|
||||
Win32Sys.CreateProcessAsUser(id, user, cmd);
|
||||
}
|
||||
|
||||
private void LogDebug(string message, params object[] args)
|
||||
{
|
||||
_logger.Debug(message, args);
|
||||
}
|
||||
|
||||
private void LogError(Exception exception, string message, params object[] args)
|
||||
{
|
||||
_logger.Error(exception, message, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
69
Common/VirtualPrinter.Utils/VirtualPrinter.Utils.csproj
Normal file
69
Common/VirtualPrinter.Utils/VirtualPrinter.Utils.csproj
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>VirtualPrinter.Utils</RootNamespace>
|
||||
<AssemblyName>VirtualPrinter.Utils</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\..\Files\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Consts.cs" />
|
||||
<Compile Include="DirectoryHelper.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="RegistryRepository.cs" />
|
||||
<Compile Include="Shell.cs" />
|
||||
<Compile Include="Win32Sys.cs" />
|
||||
<Compile Include="Windows.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VirtualPrinter.Agent.Core\VirtualPrinter.Agent.Core.csproj">
|
||||
<Project>{135C85EB-2116-4CC4-8CCB-B6804B9D6467}</Project>
|
||||
<Name>VirtualPrinter.Agent.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\VirtualPrinter.Logging\VirtualPrinter.Logging.csproj">
|
||||
<Project>{AA25364D-22D5-44B0-86A5-6FB14C686308}</Project>
|
||||
<Name>VirtualPrinter.Logging</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Cassia" Version="3.0.0-alpha.9" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
|
||||
<PackageReference Include="System.Security.Principal.Windows" Version="4.7.0" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
239
Common/VirtualPrinter.Utils/Win32Sys.cs
Normal file
239
Common/VirtualPrinter.Utils/Win32Sys.cs
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace VirtualPrinter.Utils
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Global")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
|
||||
internal static class Win32Sys
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates process with given command line via Win32 API.
|
||||
/// Use this method to start a process as a service.
|
||||
/// </summary>
|
||||
/// <param name="sessId"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <param name="commandLine"></param>
|
||||
internal static void CreateProcessAsUser(int sessId, string user, string commandLine)
|
||||
{
|
||||
WTSQueryUserToken((uint) sessId, out var userToken);
|
||||
if (userToken.IsInvalid)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not query user token for session {sessId}! (" + GetLastError() + ")",
|
||||
Windows.LastError);
|
||||
}
|
||||
|
||||
CreateProcessAsUser(userToken, user, commandLine);
|
||||
}
|
||||
|
||||
private static void CreateProcessAsUser([NotNull]SafeTokenHandle token, string user, string commandLine)
|
||||
{
|
||||
var processInformation = new PROCESS_INFORMATION();
|
||||
try
|
||||
{
|
||||
var securityAttributes = new SECURITY_ATTRIBUTES();
|
||||
securityAttributes.Length = Marshal.SizeOf(securityAttributes);
|
||||
|
||||
var startupInfo = new STARTUPINFO();
|
||||
startupInfo.cb = Marshal.SizeOf(startupInfo);
|
||||
startupInfo.lpDesktop = "winsta0\\default";
|
||||
|
||||
var info = new ProfileInfo();
|
||||
info.dwSize = Marshal.SizeOf(info);
|
||||
info.lpUserName = user;
|
||||
info.dwFlags = 1;
|
||||
|
||||
var result = LoadUserProfile(token, ref info);
|
||||
if (!result)
|
||||
{
|
||||
throw Windows.LastError;
|
||||
}
|
||||
|
||||
result = CreateEnvironmentBlock(out var lpEnvironment, token, false);
|
||||
if (!result)
|
||||
{
|
||||
throw Windows.LastError;
|
||||
}
|
||||
|
||||
result = CreateProcessAsUser
|
||||
(
|
||||
token,
|
||||
null,
|
||||
commandLine,
|
||||
ref securityAttributes,
|
||||
ref securityAttributes,
|
||||
false,
|
||||
0x00000400,
|
||||
lpEnvironment,
|
||||
null,
|
||||
ref startupInfo,
|
||||
ref processInformation
|
||||
);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
throw Windows.LastError;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (processInformation.hProcess != IntPtr.Zero)
|
||||
{
|
||||
CloseMyHandle(processInformation.hProcess);
|
||||
}
|
||||
|
||||
if (processInformation.hThread != IntPtr.Zero)
|
||||
{
|
||||
CloseMyHandle(processInformation.hThread);
|
||||
}
|
||||
|
||||
if (!token.IsInvalid)
|
||||
{
|
||||
token.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Classes
|
||||
|
||||
public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
private SafeTokenHandle() : base(true)
|
||||
{
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return CloseHandle(handle);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{handle}";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Structures
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct PROCESS_INFORMATION
|
||||
{
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public int dwProcessID;
|
||||
public int dwThreadID;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct STARTUPINFO
|
||||
{
|
||||
public int cb;
|
||||
public string lpReserved;
|
||||
public string lpDesktop;
|
||||
public string lpTitle;
|
||||
public int dwX;
|
||||
public int dwY;
|
||||
public int dwXSize;
|
||||
public int dwXCountChars;
|
||||
public int dwYCountChars;
|
||||
public int dwFillAttribute;
|
||||
public int dwFlags;
|
||||
public short wShowWindow;
|
||||
public short cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ProfileInfo
|
||||
{
|
||||
public int dwSize;
|
||||
public int dwFlags;
|
||||
public string lpUserName;
|
||||
public string lpProfilePath;
|
||||
public string lpDefaultPath;
|
||||
public string lpServerName;
|
||||
public string lpPolicyPath;
|
||||
public IntPtr hProfile;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SECURITY_ATTRIBUTES
|
||||
{
|
||||
public int Length;
|
||||
public IntPtr lpSecurityDescriptor;
|
||||
public bool bInheritHandle;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Windows interop
|
||||
|
||||
[DllImport("userenv.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern bool LoadUserProfile(SafeTokenHandle hToken, ref ProfileInfo lpProfileInfo);
|
||||
|
||||
[DllImport("userenv.dll", SetLastError = true)]
|
||||
private static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment,
|
||||
SafeTokenHandle hToken, bool bInherit);
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true,
|
||||
CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
|
||||
private static extern bool CloseMyHandle(IntPtr handle);
|
||||
|
||||
[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true,
|
||||
CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
|
||||
private static extern bool CreateProcessAsUser(SafeTokenHandle hToken,
|
||||
string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle,
|
||||
int dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,
|
||||
ref STARTUPINFO lpStartupInfo, ref PROCESS_INFORMATION lpProcessInformation);
|
||||
|
||||
[DllImport("wtsapi32.dll", SetLastError = true)]
|
||||
private static extern bool WTSQueryUserToken(uint sessionId, out SafeTokenHandle Token);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern uint GetLastError();
|
||||
|
||||
[DllImport("kernel32")]
|
||||
public static extern int GetPrivateProfileString
|
||||
(
|
||||
string section,
|
||||
string key,
|
||||
string def,
|
||||
StringBuilder retVal,
|
||||
int size,
|
||||
string filePath
|
||||
);
|
||||
|
||||
[DllImport("kernel32")]
|
||||
public static extern long WritePrivateProfileString
|
||||
(
|
||||
string section,
|
||||
string key,
|
||||
string val,
|
||||
string filePath
|
||||
);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
14
Common/VirtualPrinter.Utils/Windows.cs
Normal file
14
Common/VirtualPrinter.Utils/Windows.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace VirtualPrinter.Utils
|
||||
{
|
||||
public class Windows
|
||||
{
|
||||
[NotNull]
|
||||
public static Exception LastError => new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue