Implemented VirtualPrinterDriver project
This commit is contained in:
parent
f29c84821b
commit
5c87967c3f
125 changed files with 8191 additions and 0 deletions
|
|
@ -0,0 +1,32 @@
|
|||
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.Agent.Autofac")]
|
||||
[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("fc76a2af-b0db-4ec8-a6b7-dbd25d461ab5")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<?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>{1B2F0781-82D7-4576-B936-C6A26053D6ED}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>VirtualPrinter.Agent.Autofac</RootNamespace>
|
||||
<AssemblyName>VirtualPrinter.Agent.Autofac</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<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' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\..\Files\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="VirtualPrinterModule.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.IO.Compression" />
|
||||
<Reference Include="System.Printing" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Transactions" />
|
||||
<Reference Include="System.Xml" />
|
||||
</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.Agent.Lib\VirtualPrinter.Agent.Lib.csproj">
|
||||
<Project>{94e8105f-5001-403b-b9f1-b0b0b236ad65}</Project>
|
||||
<Name>VirtualPrinter.Agent.Lib</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\VirtualPrinter.Logging\VirtualPrinter.Logging.csproj">
|
||||
<Project>{AA25364D-22D5-44B0-86A5-6FB14C686308}</Project>
|
||||
<Name>VirtualPrinter.Logging</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\VirtualPrinter.Utils\VirtualPrinter.Utils.csproj">
|
||||
<Project>{CD1C8E9D-5335-41AC-B0C0-88FD7C7C55F3}</Project>
|
||||
<Name>VirtualPrinter.Utils</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autofac" Version="6.0.0" />
|
||||
<PackageReference Include="Autofac.Extras.NLog" Version="4.0.0" />
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0-rc.2.20475.5" />
|
||||
<PackageReference Include="NLog" Version="4.6.1" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="5.0.0-rc.2.20475.5" />
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
33
Common/VirtualPrinter.Agent.Autofac/VirtualPrinterModule.cs
Normal file
33
Common/VirtualPrinter.Agent.Autofac/VirtualPrinterModule.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
using Autofac;
|
||||
|
||||
using VirtualPrinter.Agent.Core;
|
||||
using VirtualPrinter.Agent.Lib;
|
||||
using VirtualPrinter.Agent.Lib.Misc;
|
||||
using VirtualPrinter.Utils;
|
||||
|
||||
namespace VirtualPrinter.Agent.Autofac
|
||||
{
|
||||
/// <summary>
|
||||
/// All classes to be resolved with IoC are registered here
|
||||
/// </summary>
|
||||
public class VirtualPrinterModule : Module
|
||||
{
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
builder.RegisterType<GhostScriptConverter>().As<IPostScriptConverter>();
|
||||
builder.RegisterType<UserRegistryConfig>().As<IUserConfig>();
|
||||
builder.RegisterType<JobService>().As<IJobService>();
|
||||
builder.RegisterType<JobFactory>().As<IJobFactory>();
|
||||
builder.RegisterType<JobProcessor>().As<IJobProcessor>();
|
||||
builder.RegisterType<Job>().As<IJob>();
|
||||
builder.RegisterType<Shell>().As<IShell>();
|
||||
builder.RegisterType<VirtualTcpInputPrinter>().As<IVirtualPrinter>();
|
||||
builder.RegisterType<RegistryConfig>().As<IExConfig>();
|
||||
builder.RegisterType<VirtualPrinterService>().As<IVirtualPrinterService>();
|
||||
builder.RegisterType<JobRedirector>().As<IJobRedirector>();
|
||||
builder.RegisterType<RegistryRepository>().As<IRegistryRepository>();
|
||||
builder.RegisterType<Shell>().As<IShell>();
|
||||
builder.RegisterType<DirectoryHelper>().As<IDirectoryHelper>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
namespace VirtualPrinter.Agent.Core.Enums
|
||||
{
|
||||
public enum IntermediateFormat
|
||||
{
|
||||
Ps,
|
||||
Xps
|
||||
}
|
||||
}
|
||||
20
Common/VirtualPrinter.Agent.Core/Interfaces/IConfig.cs
Normal file
20
Common/VirtualPrinter.Agent.Core/Interfaces/IConfig.cs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
using JetBrains.Annotations;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public interface IConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// The mask for the filename.
|
||||
/// </summary>
|
||||
/// <remarks>The mask can be look like {yyyy}{MM}{DD}{hh}{mm}{ss}{job05}{page03}</remarks>
|
||||
[NotNull]
|
||||
string FileNameMask { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The port of the printer.
|
||||
/// </summary>
|
||||
/// <remarks>E.g. 9101</remarks>
|
||||
short PrinterPort { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public interface IDirectoryHelper
|
||||
{
|
||||
string GetOutputDirectory(IExConfig config);
|
||||
}
|
||||
}
|
||||
36
Common/VirtualPrinter.Agent.Core/Interfaces/IExConfig.cs
Normal file
36
Common/VirtualPrinter.Agent.Core/Interfaces/IExConfig.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
using VirtualPrinter.Agent.Core.Enums;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public interface IExConfig : IConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Splits a preconverter into two strings.
|
||||
/// </summary>
|
||||
/// <remarks>e.g. "C:\Program Files (x86)\MySoftware\MySoftware.exe PRINT" now becomes: string 1 = "C:\Program Files (x86)\MySoftware\MySoftware.exe" and string 2 = "PRINT"</remarks>
|
||||
[NotNull]
|
||||
Tuple<string, string> ResolvedPreconverter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Splits a postconverter into two strings.
|
||||
/// </summary>
|
||||
/// <remarks>e.g. "C:\Program Files (x86)\MySoftware\MySoftware.exe PRINTCOMPLETE" now becomes: string 1 = "C:\Program Files (x86)\MySoftware\MySoftware.exe" and string 2 = "PRINTCOMPLETE"</remarks>
|
||||
[NotNull]
|
||||
Tuple<string, string> ResolvedPostconverter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The full path of the output directory.
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
string ResolvedOutputDirectory { get; }
|
||||
|
||||
/// <summary>
|
||||
/// An intermediate format which is read by the printer or similar.
|
||||
/// </summary>
|
||||
IntermediateFormat IntermediateFormat { get; }
|
||||
}
|
||||
}
|
||||
34
Common/VirtualPrinter.Agent.Core/Interfaces/IJob.cs
Normal file
34
Common/VirtualPrinter.Agent.Core/Interfaces/IJob.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
using JetBrains.Annotations;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// The information of the job.
|
||||
/// </summary>
|
||||
public interface IJob
|
||||
{
|
||||
/// <summary>
|
||||
/// The path to the file containing the data.
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
string RawDataPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The path to the ini file.
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
string IniDataPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Several job infos.
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
IJobInfo JobInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Information about the session.
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
ISessionInfo SessionInfo { get; }
|
||||
}
|
||||
}
|
||||
15
Common/VirtualPrinter.Agent.Core/Interfaces/IJobFactory.cs
Normal file
15
Common/VirtualPrinter.Agent.Core/Interfaces/IJobFactory.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using System.IO;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public interface IJobFactory
|
||||
{
|
||||
[CanBeNull]
|
||||
IJob Create([NotNull]string printerName, [NotNull]Stream stream);
|
||||
|
||||
[NotNull]
|
||||
IJob Create([NotNull]string iniPath, [NotNull]string rawPath, IJobInfo jobInfo, ISessionInfo sessionInfo);
|
||||
}
|
||||
}
|
||||
15
Common/VirtualPrinter.Agent.Core/Interfaces/IJobInfo.cs
Normal file
15
Common/VirtualPrinter.Agent.Core/Interfaces/IJobInfo.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using System.Printing;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public interface IJobInfo
|
||||
{
|
||||
int JobId { get; set; }
|
||||
string Name { get; set; }
|
||||
string DomainName { get; set; }
|
||||
string MachineName { get; set; }
|
||||
string UserName { get; set; }
|
||||
PrintJobStatus Status { get; set; }
|
||||
string DeviceName { get; set; }
|
||||
}
|
||||
}
|
||||
18
Common/VirtualPrinter.Agent.Core/Interfaces/IJobProcessor.cs
Normal file
18
Common/VirtualPrinter.Agent.Core/Interfaces/IJobProcessor.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public interface IJobProcessor
|
||||
{
|
||||
/// <summary>
|
||||
/// Processes an <see cref="IJob"/> passed to it with the information from the <see cref="IUserConfig"/>.
|
||||
/// </summary>
|
||||
/// <param name="job"></param>
|
||||
/// <param name="userConfig"></param>
|
||||
/// <exception cref="ArgumentNullException">Throws when the <param name="job">job</param> or the <param name="userConfig"> is null.</param></exception>
|
||||
/// <exception cref="PostScriptConversionException">The job cannot be converted. There is no redirect to a printer. Will not be thrown.</exception>
|
||||
void Process([NotNull]IJob job, [NotNull]IUserConfig userConfig);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public interface IJobRedirector
|
||||
{
|
||||
/// <summary>
|
||||
/// Redirects the information from the <param name="job">job</param> and the <param name="userConfig">config</param> to an Process to be executed.
|
||||
/// </summary>
|
||||
/// <param name="job"></param>
|
||||
/// <param name="userConfig"></param>
|
||||
/// <exception cref="ArgumentNullException">Throws when the <see cref="IJob"/> or the <see cref="IUserConfig"/> is null.</exception>
|
||||
void Redirect([NotNull]IJob job, [NotNull]IUserConfig userConfig);
|
||||
}
|
||||
}
|
||||
47
Common/VirtualPrinter.Agent.Core/Interfaces/IJobService.cs
Normal file
47
Common/VirtualPrinter.Agent.Core/Interfaces/IJobService.cs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public interface IJobService
|
||||
{
|
||||
/// <summary>
|
||||
/// Starts the <see cref="IJob"/> in a new Process.
|
||||
/// </summary>
|
||||
/// <param name="job"></param>
|
||||
/// <exception cref="ArgumentNullException">Throws when the <see cref="IJob"/> is null.</exception>
|
||||
void Start([NotNull]IJob job);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an new <see cref="IJob"/> from the <param name="iniPath">ini file</param> and the <param name="rawPath">raw path</param>.
|
||||
/// </summary>
|
||||
/// <param name="iniPath"></param>
|
||||
/// <param name="rawPath"></param>
|
||||
/// <returns>An new <see cref="IJob"/> object.</returns>
|
||||
/// <exception cref="ArgumentException">Throws when the <paramref name="iniPath"/> or the <paramref name="rawPath"/> is null or empty.</exception>
|
||||
[NotNull]
|
||||
IJob CreateJob([NotNull]string iniPath, [NotNull]string rawPath);
|
||||
|
||||
/// <summary>
|
||||
/// Reads the <see cref="PrintStatus"/> from the <paramref name="iniPath"/>
|
||||
/// </summary>
|
||||
/// <param name="iniPath"></param>
|
||||
/// <returns>A <see cref="PrintStatus"/></returns>
|
||||
/// <exception cref="ArgumentException">Throws when the <paramref name="iniPath"/> is null or empty.</exception>
|
||||
PrintStatus ReadStatus([NotNull]string iniPath);
|
||||
|
||||
/// <summary>
|
||||
/// Starts a new process to finish the <see cref="IJob"/>.
|
||||
/// </summary>
|
||||
/// <param name="job"></param>
|
||||
void Finish([NotNull]IJob job);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JobStatus"/> from the ini file.
|
||||
/// </summary>
|
||||
/// <param name="iniPath">The path to the ini file</param>
|
||||
/// <returns><see cref="JobStatus"/></returns>
|
||||
JobStatus ReadJobStatus(string iniPath);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
using VirtualPrinter.Agent.Lib.Model;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public interface IPostScriptConverter
|
||||
{
|
||||
event EventHandler<IJob> ProgressInitialized;
|
||||
event EventHandler<IJob> ProgressFinished;
|
||||
event EventHandler<ProgressUpdateArgs> ProgressUpdate;
|
||||
|
||||
void Convert(IJob job, string target, PostScriptRenderOptions options);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
using JetBrains.Annotations;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public interface IRegistryRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Try to get the ghostscript path from.
|
||||
/// </summary>
|
||||
/// <returns>True if the path exists.</returns>
|
||||
[ContractAnnotation("=>true,path:notnull; =>false,path:null")]
|
||||
bool TryGetGhostscriptPath(out string path);
|
||||
|
||||
/// <summary>
|
||||
/// Get the <see cref="IExConfig"/> from the registry.
|
||||
/// </summary>
|
||||
/// <returns>The configuration that was read from the registry in HKEY_LOCAL_MACHINE\SOFTWARE.</returns>
|
||||
[NotNull]
|
||||
IExConfig GetRegistryConfig();
|
||||
|
||||
/// <summary>
|
||||
/// Get the <see cref="IUserConfig"/> from the registry.
|
||||
/// </summary>
|
||||
/// <param name="sid">The security identifier with which each Windows user can be clearly identified in the network.</param>
|
||||
/// <returns>The configuration that was read from the registry in HKEY_USERS</returns>
|
||||
[NotNull]
|
||||
IUserConfig GetUserRegistryConfig([NotNull]string sid);
|
||||
}
|
||||
}
|
||||
11
Common/VirtualPrinter.Agent.Core/Interfaces/ISessionInfo.cs
Normal file
11
Common/VirtualPrinter.Agent.Core/Interfaces/ISessionInfo.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public interface ISessionInfo
|
||||
{
|
||||
int Id { get; set; }
|
||||
|
||||
string Desktop { get; set; }
|
||||
|
||||
string Sid { get; set; }
|
||||
}
|
||||
}
|
||||
16
Common/VirtualPrinter.Agent.Core/Interfaces/IShell.cs
Normal file
16
Common/VirtualPrinter.Agent.Core/Interfaces/IShell.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using JetBrains.Annotations;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public interface IShell
|
||||
{
|
||||
void WriteIniEntry(string section, string key, string value, string iniFilePath);
|
||||
|
||||
[NotNull]
|
||||
T ReadIniEntry<T>(string section, string key, string iniFilePath);
|
||||
|
||||
void Execute(IJobInfo job, ISessionInfo session, string exe, string args);
|
||||
|
||||
bool FileExists([NotNull]string path);
|
||||
}
|
||||
}
|
||||
26
Common/VirtualPrinter.Agent.Core/Interfaces/IUserConfig.cs
Normal file
26
Common/VirtualPrinter.Agent.Core/Interfaces/IUserConfig.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using JetBrains.Annotations;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public interface IUserConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// The printer stored in the registry.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
string RedirectPrinter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The DPI value stored in the registry.
|
||||
/// </summary>
|
||||
/// <remarks>Initial value is null.</remarks>
|
||||
double? UserRenderDpi { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The format that you choose on your client side stored in the registry.
|
||||
/// </summary>
|
||||
/// <remarks>Intital value is PDF</remarks>
|
||||
[NotNull]
|
||||
string Format { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public interface IVirtualPrinter : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialize the virtual printer.
|
||||
/// </summary>
|
||||
void Init();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public interface IVirtualPrinterService
|
||||
{
|
||||
void Start();
|
||||
void Stop();
|
||||
}
|
||||
}
|
||||
9
Common/VirtualPrinter.Agent.Core/Interfaces/JobStatus.cs
Normal file
9
Common/VirtualPrinter.Agent.Core/Interfaces/JobStatus.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public enum JobStatus
|
||||
{
|
||||
Completed,
|
||||
Failed,
|
||||
InProgress
|
||||
}
|
||||
}
|
||||
15
Common/VirtualPrinter.Agent.Core/Model/JobInfo.cs
Normal file
15
Common/VirtualPrinter.Agent.Core/Model/JobInfo.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using System.Printing;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public struct JobInfo : IJobInfo
|
||||
{
|
||||
public int JobId { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string DomainName { get; set; }
|
||||
public string MachineName { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public PrintJobStatus Status { get; set; }
|
||||
public string DeviceName { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public class PostScriptConversionException : Exception
|
||||
{
|
||||
public PostScriptConversionException()
|
||||
{
|
||||
}
|
||||
|
||||
public PostScriptConversionException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public PostScriptConversionException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public struct PostScriptRenderOptions
|
||||
{
|
||||
public double? UserRenderDpi { get; set; }
|
||||
public PostScriptRenderPdfOptions PdfOptions { get; set; }
|
||||
public PostScriptRenderTiffOptions TiffOptions { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public struct PostScriptRenderPdfOptions
|
||||
{
|
||||
public bool Enabled { set; get; }
|
||||
public bool Archivable { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public struct PostScriptRenderTiffOptions
|
||||
{
|
||||
public bool Enabled { set; get; }
|
||||
}
|
||||
}
|
||||
13
Common/VirtualPrinter.Agent.Core/Model/PrintExts.cs
Normal file
13
Common/VirtualPrinter.Agent.Core/Model/PrintExts.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
using JetBrains.Annotations;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public static class PrintExts
|
||||
{
|
||||
[NotNull]
|
||||
public static string ToIni(this PrintStatus status)
|
||||
{
|
||||
return status.ToString().ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Common/VirtualPrinter.Agent.Core/Model/PrintStatus.cs
Normal file
15
Common/VirtualPrinter.Agent.Core/Model/PrintStatus.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public enum PrintStatus
|
||||
{
|
||||
Undefined = 0,
|
||||
|
||||
Paused,
|
||||
|
||||
Resumed,
|
||||
|
||||
Complete,
|
||||
|
||||
Canceled
|
||||
}
|
||||
}
|
||||
22
Common/VirtualPrinter.Agent.Core/Model/ProgressUpdateArgs.cs
Normal file
22
Common/VirtualPrinter.Agent.Core/Model/ProgressUpdateArgs.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
using VirtualPrinter.Agent.Core;
|
||||
|
||||
namespace VirtualPrinter.Agent.Lib.Model
|
||||
{
|
||||
public class ProgressUpdateArgs : EventArgs
|
||||
{
|
||||
public ProgressUpdateArgs([NotNull] IJob job, uint val)
|
||||
{
|
||||
Job = job;
|
||||
Value = val;
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
public IJob Job { get; }
|
||||
|
||||
public uint Value { get; }
|
||||
}
|
||||
}
|
||||
49
Common/VirtualPrinter.Agent.Core/Model/RegistryConfig.cs
Normal file
49
Common/VirtualPrinter.Agent.Core/Model/RegistryConfig.cs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
using VirtualPrinter.Agent.Core.Enums;
|
||||
|
||||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public class RegistryConfig : IExConfig
|
||||
{
|
||||
public string Postconverter { get; set; }
|
||||
|
||||
public string Preconverter { get; set; }
|
||||
|
||||
public string OutputDirectory { get; set; }
|
||||
|
||||
public string FileNameMask { get; set; }
|
||||
|
||||
public short PrinterPort { get; set; }
|
||||
|
||||
public Tuple<string, string> ResolvedPreconverter
|
||||
{
|
||||
get { return GetResolvedArgs(Preconverter); }
|
||||
}
|
||||
|
||||
public Tuple<string, string> ResolvedPostconverter
|
||||
{
|
||||
get { return GetResolvedArgs(Postconverter); }
|
||||
}
|
||||
|
||||
public string ResolvedOutputDirectory
|
||||
{
|
||||
get { return string.IsNullOrWhiteSpace(OutputDirectory) ? "" : Path.GetFullPath(OutputDirectory); }
|
||||
}
|
||||
|
||||
public IntermediateFormat IntermediateFormat { get; set; }
|
||||
|
||||
[NotNull]
|
||||
private static Tuple<string, string> GetResolvedArgs([NotNull]string text)
|
||||
{
|
||||
const string ending = ".exe";
|
||||
var parts = text.Split(new[] { ending }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
return Tuple.Create(Path.GetFullPath(parts.First() + ending), parts.Last().Trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Common/VirtualPrinter.Agent.Core/Model/SessionInfo.cs
Normal file
11
Common/VirtualPrinter.Agent.Core/Model/SessionInfo.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public struct SessionInfo : ISessionInfo
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Desktop { get; set; }
|
||||
|
||||
public string Sid { get; set; }
|
||||
}
|
||||
}
|
||||
13
Common/VirtualPrinter.Agent.Core/Model/UserRegistryConfig.cs
Normal file
13
Common/VirtualPrinter.Agent.Core/Model/UserRegistryConfig.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
namespace VirtualPrinter.Agent.Core
|
||||
{
|
||||
public class UserRegistryConfig : IUserConfig
|
||||
{
|
||||
public bool RedirectEnabled { get; set; }
|
||||
|
||||
public string RedirectPrinter { get; set; }
|
||||
|
||||
public double? UserRenderDpi { get; set; }
|
||||
|
||||
public string Format { get; set; }
|
||||
}
|
||||
}
|
||||
35
Common/VirtualPrinter.Agent.Core/Properties/AssemblyInfo.cs
Normal file
35
Common/VirtualPrinter.Agent.Core/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// Allgemeine Informationen über eine Assembly werden über die folgenden
|
||||
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
|
||||
// die einer Assembly zugeordnet sind.
|
||||
[assembly: AssemblyTitle("VirtualPrinter.Agent.Core")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
|
||||
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
|
||||
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
|
||||
[assembly: Guid("135c85eb-2116-4cc4-8ccb-b6804b9d6467")]
|
||||
|
||||
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
|
||||
//
|
||||
// Hauptversion
|
||||
// Nebenversion
|
||||
// Buildnummer
|
||||
// Revision
|
||||
//
|
||||
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
|
||||
// indem Sie "*" wie unten gezeigt eingeben:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
<?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>{135C85EB-2116-4CC4-8CCB-B6804B9D6467}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>VirtualPrinter.Agent.Core</RootNamespace>
|
||||
<AssemblyName>VirtualPrinter.Agent.Core</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</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="ReachFramework" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Printing" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Enums\IntermediateFormat.cs" />
|
||||
<Compile Include="Interfaces\IDirectoryHelper.cs" />
|
||||
<Compile Include="Interfaces\IConfig.cs" />
|
||||
<Compile Include="Interfaces\IExConfig.cs" />
|
||||
<Compile Include="Interfaces\IJob.cs" />
|
||||
<Compile Include="Interfaces\IJobFactory.cs" />
|
||||
<Compile Include="Interfaces\IJobInfo.cs" />
|
||||
<Compile Include="Interfaces\IJobProcessor.cs" />
|
||||
<Compile Include="Interfaces\IJobRedirector.cs" />
|
||||
<Compile Include="Interfaces\IJobService.cs" />
|
||||
<Compile Include="Interfaces\IPostScriptConverter.cs" />
|
||||
<Compile Include="Interfaces\IRegistryRepository.cs" />
|
||||
<Compile Include="Interfaces\ISessionInfo.cs" />
|
||||
<Compile Include="Interfaces\IShell.cs" />
|
||||
<Compile Include="Interfaces\IUserConfig.cs" />
|
||||
<Compile Include="Interfaces\IVirtualPrinter.cs" />
|
||||
<Compile Include="Interfaces\IVirtualPrinterService.cs" />
|
||||
<Compile Include="Interfaces\JobStatus.cs" />
|
||||
<Compile Include="Model\JobInfo.cs" />
|
||||
<Compile Include="Model\PostScriptConversionException.cs" />
|
||||
<Compile Include="Model\PostScriptRenderOptions.cs" />
|
||||
<Compile Include="Model\PostScriptRenderPdfOptions.cs" />
|
||||
<Compile Include="Model\PostScriptRenderTiffOptions.cs" />
|
||||
<Compile Include="Model\ProgressUpdateArgs.cs" />
|
||||
<Compile Include="Model\RegistryConfig.cs" />
|
||||
<Compile Include="Model\UserRegistryConfig.cs" />
|
||||
<Compile Include="Model\PrintExts.cs" />
|
||||
<Compile Include="Model\PrintStatus.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Model\SessionInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
218
Common/VirtualPrinter.Agent.Lib/Misc/GhostScriptConverter.cs
Normal file
218
Common/VirtualPrinter.Agent.Lib/Misc/GhostScriptConverter.cs
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
using VirtualPrinter.Agent.Core;
|
||||
using VirtualPrinter.Agent.Lib.Model;
|
||||
using VirtualPrinter.Logging;
|
||||
|
||||
namespace VirtualPrinter.Agent.Lib.Misc
|
||||
{
|
||||
public class GhostScriptConverter : IPostScriptConverter
|
||||
{
|
||||
private const string GsWin64 = "gswin64c.exe";
|
||||
private const string GsWin32 = "gswin32c.exe";
|
||||
|
||||
[NotNull]
|
||||
private readonly IVirtualPrinterLogger<GhostScriptConverter> _logger;
|
||||
|
||||
[NotNull]
|
||||
private readonly IRegistryRepository _registryRepository;
|
||||
|
||||
[NotNull]
|
||||
private readonly IShell _shell;
|
||||
|
||||
public event EventHandler<IJob> ProgressInitialized;
|
||||
public event EventHandler<IJob> ProgressFinished;
|
||||
public event EventHandler<ProgressUpdateArgs> ProgressUpdate;
|
||||
|
||||
public GhostScriptConverter
|
||||
(
|
||||
[NotNull]IVirtualPrinterLogger<GhostScriptConverter> logger,
|
||||
[NotNull]IRegistryRepository registryRepository,
|
||||
[NotNull]IShell shell
|
||||
)
|
||||
{
|
||||
if (logger == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
if (registryRepository == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(registryRepository));
|
||||
}
|
||||
|
||||
if (shell == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(shell));
|
||||
}
|
||||
|
||||
_logger = logger;
|
||||
_registryRepository = registryRepository;
|
||||
_shell = shell;
|
||||
}
|
||||
|
||||
public void Convert(IJob job, string target, PostScriptRenderOptions options)
|
||||
{
|
||||
var ghostScriptExe = GetGhostScriptPath();
|
||||
|
||||
if (ghostScriptExe == null)
|
||||
{
|
||||
throw new PostScriptConversionException("GhostScript not found. Please place local variable.");
|
||||
}
|
||||
|
||||
ProgressInitialized?.Invoke(this, job);
|
||||
|
||||
var pdfTarget = target + ".pdf";
|
||||
if (options.PdfOptions.Enabled)
|
||||
{
|
||||
Convert(job, ghostScriptExe, GetArgumentsForPdfConversion(job.RawDataPath, pdfTarget, options));
|
||||
|
||||
if (!_shell.FileExists(pdfTarget))
|
||||
{
|
||||
throw new PostScriptConversionException("Postscript conversion failed after output.");
|
||||
}
|
||||
}
|
||||
|
||||
if (options.TiffOptions.Enabled)
|
||||
{
|
||||
var tiffTarget = target + ".tif";
|
||||
|
||||
Convert(job, ghostScriptExe, GetArgumentsForTiffConversion(job.RawDataPath, tiffTarget, options));
|
||||
Convert(job, ghostScriptExe, GetArgumentsForPdfConversion(job.RawDataPath, pdfTarget, options));
|
||||
|
||||
if (!_shell.FileExists(tiffTarget))
|
||||
{
|
||||
throw new PostScriptConversionException("Postscript conversion failed after output.");
|
||||
}
|
||||
}
|
||||
|
||||
ProgressFinished?.Invoke(this, job);
|
||||
}
|
||||
|
||||
[CanBeNull]
|
||||
private string GetGhostScriptPath()
|
||||
{
|
||||
return GetGhostScriptPath(GsWin64) ?? GetGhostScriptPath(GsWin32);
|
||||
}
|
||||
|
||||
[CanBeNull]
|
||||
private string GetGhostScriptPath(string execName)
|
||||
{
|
||||
if (!_registryRepository.TryGetGhostscriptPath(out var path))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var ghostScriptBinPath = Path.Combine(path, "bin");
|
||||
var fullPath = Path.Combine(ghostScriptBinPath, execName);
|
||||
|
||||
return _shell.FileExists(fullPath) ? fullPath : null;
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
private static string GetArgumentsForPdfConversion(string source, string target, PostScriptRenderOptions options)
|
||||
{
|
||||
const string initialArguments = "-q -P- -dSAFER -dNOPAUSE -dBATCH -dNoCancel -sDEVICE=pdfwrite";
|
||||
var finalArguments = $"-sOutputFile=\"{target}\" \"{source}\"";
|
||||
|
||||
var optionalArguments = "";
|
||||
|
||||
if (options.PdfOptions.Archivable)
|
||||
{
|
||||
optionalArguments += "-sColorConversionStrategy=/RGB -dUseCIEColor -dPDFACompatibilityPolicy=2";
|
||||
}
|
||||
|
||||
if (options.UserRenderDpi != null && options.UserRenderDpi > 0)
|
||||
{
|
||||
optionalArguments += "-r" + options.UserRenderDpi.Value;
|
||||
}
|
||||
|
||||
return $"{initialArguments} {optionalArguments} {finalArguments}";
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
private static string GetArgumentsForTiffConversion(string source, string target, PostScriptRenderOptions options)
|
||||
{
|
||||
const string initialArguments = "-q -P- -dSAFER -dNOPAUSE -dBATCH -sDEVICE=tiff12nc -sCompression=lzw";
|
||||
var finalArguments = $"-sOutputFile=\"{target}\" \"{source}\"";
|
||||
|
||||
var optionalArguments = "-dTextAlphaBits=4 ";
|
||||
|
||||
if (options.UserRenderDpi != null && options.UserRenderDpi > 0)
|
||||
{
|
||||
optionalArguments += "-r" + options.UserRenderDpi.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
optionalArguments += "-r300";
|
||||
}
|
||||
|
||||
return $"{initialArguments} {optionalArguments} {finalArguments}";
|
||||
}
|
||||
|
||||
private void Convert(IJob job, string gsExe, string gsArguments)
|
||||
{
|
||||
LogDebug("Starting ps conversion ...\n"+gsExe + " " + gsArguments);
|
||||
|
||||
var process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = gsExe,
|
||||
Arguments = gsArguments,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
CreateNoWindow = true
|
||||
}
|
||||
};
|
||||
|
||||
process.Start();
|
||||
|
||||
while (!process.StandardOutput.EndOfStream)
|
||||
{
|
||||
var readLine = process.StandardOutput.ReadLine();
|
||||
var progress = ParseProgress(readLine);
|
||||
|
||||
if (progress == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ProgressUpdate?.Invoke(this, new ProgressUpdateArgs(job, progress.Value));
|
||||
}
|
||||
}
|
||||
|
||||
private static uint? ParseProgress([CanBeNull]string line)
|
||||
{
|
||||
// Example output:
|
||||
// %%[Page: 49]%%
|
||||
if (line == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var groups = Regex.Match(line, @"%%\[Page:(.*)\]%%").Groups;
|
||||
if (groups.Count < 2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!uint.TryParse(groups[1].Value, out var result))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void LogDebug(string message, params object[] args)
|
||||
{
|
||||
_logger.Debug(message, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Common/VirtualPrinter.Agent.Lib/Misc/Job.cs
Normal file
15
Common/VirtualPrinter.Agent.Lib/Misc/Job.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using VirtualPrinter.Agent.Core;
|
||||
|
||||
namespace VirtualPrinter.Agent.Lib.Misc
|
||||
{
|
||||
public class Job : IJob
|
||||
{
|
||||
public string RawDataPath { get; set; }
|
||||
|
||||
public string IniDataPath { get; set; }
|
||||
|
||||
public IJobInfo JobInfo { get; set; }
|
||||
|
||||
public ISessionInfo SessionInfo { get; set; }
|
||||
}
|
||||
}
|
||||
243
Common/VirtualPrinter.Agent.Lib/Misc/JobFactory.cs
Normal file
243
Common/VirtualPrinter.Agent.Lib/Misc/JobFactory.cs
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Printing;
|
||||
using System.Security.Principal;
|
||||
|
||||
using Cassia;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
using VirtualPrinter.Agent.Core;
|
||||
using VirtualPrinter.Agent.Core.Enums;
|
||||
using VirtualPrinter.Logging;
|
||||
|
||||
namespace VirtualPrinter.Agent.Lib.Misc
|
||||
{
|
||||
public class JobFactory : IJobFactory
|
||||
{
|
||||
[NotNull]
|
||||
private readonly IVirtualPrinterLogger<JobFactory> _logger;
|
||||
private readonly IDirectoryHelper _directoryHelper;
|
||||
[NotNull]
|
||||
private readonly IRegistryRepository _registryRepository;
|
||||
|
||||
public JobFactory
|
||||
(
|
||||
[NotNull]IRegistryRepository registryRepository,
|
||||
[NotNull]IVirtualPrinterLogger<JobFactory> logger,
|
||||
[NotNull]IDirectoryHelper directoryHelper
|
||||
)
|
||||
{
|
||||
if (registryRepository == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(registryRepository));
|
||||
}
|
||||
|
||||
if (logger == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
if (directoryHelper == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
_registryRepository = registryRepository;
|
||||
_logger = logger;
|
||||
_directoryHelper = directoryHelper;
|
||||
}
|
||||
|
||||
public IJob Create(string printerName, Stream stream)
|
||||
{
|
||||
if (printerName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(printerName));
|
||||
}
|
||||
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(stream));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
var config = _registryRepository.GetRegistryConfig();
|
||||
var root = _directoryHelper.GetOutputDirectory(config);
|
||||
var jobInfo = GetCurrentPrintJobs(printerName).FirstOrDefault();
|
||||
if (jobInfo == null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
var session = GetCurrentSessions(jobInfo).FirstOrDefault();
|
||||
var iniName = GenerateFileName(now, jobInfo.JobId, 0, config.FileNameMask, "ini");
|
||||
var iniPath = Path.Combine(root, iniName);
|
||||
var extension = GetRawFileExtension(config.IntermediateFormat);
|
||||
var rawName = $"{Path.GetFileNameWithoutExtension(iniName)}.{extension}";
|
||||
var rawPath = Path.Combine(root, rawName);
|
||||
using (var output = File.Create(rawPath))
|
||||
{
|
||||
stream.CopyTo(output);
|
||||
}
|
||||
|
||||
return new Job
|
||||
{
|
||||
RawDataPath = rawPath,
|
||||
IniDataPath = iniPath,
|
||||
JobInfo = jobInfo,
|
||||
SessionInfo = session
|
||||
};
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LogError(exception, "Failed to create job.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public IJob Create(string iniPath, string rawPath, IJobInfo jobInfo, ISessionInfo sessionInfo)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(iniPath))
|
||||
{
|
||||
throw new ArgumentException("Value cannot be null or whitespace.", nameof(iniPath));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(rawPath))
|
||||
{
|
||||
throw new ArgumentException("Value cannot be null or whitespace.", nameof(rawPath));
|
||||
}
|
||||
|
||||
return new Job
|
||||
{
|
||||
IniDataPath = iniPath,
|
||||
RawDataPath = rawPath,
|
||||
JobInfo = jobInfo,
|
||||
SessionInfo = sessionInfo
|
||||
};
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
private string GenerateFileName(DateTime time, int job, int page, [NotNull]string pattern, [NotNull]string ending)
|
||||
{
|
||||
var fileName = pattern;
|
||||
fileName = fileName.Replace("{yyyy}", $"{time.Year:0000}");
|
||||
fileName = fileName.Replace("{MM}", $"{time.Month:00}");
|
||||
fileName = fileName.Replace("{DD}", $"{time.Day:00}");
|
||||
fileName = fileName.Replace("{hh}", $"{time.Hour:00}");
|
||||
fileName = fileName.Replace("{mm}", $"{time.Minute:00}");
|
||||
fileName = fileName.Replace("{ss}", $"{time.Second:00}");
|
||||
fileName = fileName.Replace("{fff}", $"{time.Millisecond:000}");
|
||||
fileName = fileName.Replace("{job05}", $"{job:00000}");
|
||||
fileName = fileName.Replace("{page03}", $"{page:000}");
|
||||
|
||||
return $"{fileName}.{ending}";
|
||||
}
|
||||
|
||||
private IEnumerable<SessionInfo> GetCurrentSessions([NotNull]IJobInfo job)
|
||||
{
|
||||
var domain = job.DomainName;
|
||||
var machine = job.MachineName?.TrimStart('\\');
|
||||
var user = job.UserName;
|
||||
|
||||
LogDebug($"Searching for session of {domain}\\{user} on {machine} !");
|
||||
|
||||
if (domain == null || machine == null || user == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
const StringComparison cmp = StringComparison.OrdinalIgnoreCase;
|
||||
using (var server = new TerminalServicesManager().GetLocalServer())
|
||||
{
|
||||
var sessions = server.GetSessions().Where(s => s.UserName != null && s.DomainName != null);
|
||||
foreach (var session in sessions)
|
||||
{
|
||||
if (!session.UserName.Equals(user, cmp))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var isSingleUser = session.DomainName.Equals(machine, cmp);
|
||||
var isDomainUser = session.DomainName.Equals(domain, cmp);
|
||||
if (!isSingleUser && !isDomainUser)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var sessionId = session.SessionId;
|
||||
var desktopName = session.WindowStationName;
|
||||
var account = session.UserAccount;
|
||||
yield return new SessionInfo
|
||||
{
|
||||
Id = sessionId,
|
||||
Desktop = desktopName,
|
||||
Sid = account.Translate(typeof(SecurityIdentifier)).Value
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ItemNotNull]
|
||||
private IEnumerable<IJobInfo> GetCurrentPrintJobs(string printerName)
|
||||
{
|
||||
using (var server = new LocalPrintServer())
|
||||
{
|
||||
using (var queue = server.GetPrintQueue(printerName))
|
||||
{
|
||||
using (var jobs = queue.GetPrintJobInfoCollection())
|
||||
{
|
||||
foreach (var job in jobs)
|
||||
{
|
||||
using (job)
|
||||
{
|
||||
var id = job.JobIdentifier;
|
||||
var machine = server.Name;
|
||||
var domain = Environment.UserDomainName;
|
||||
var user = job.Submitter;
|
||||
var name = job.Name;
|
||||
yield return new JobInfo
|
||||
{
|
||||
JobId = id,
|
||||
Name = name,
|
||||
DomainName = domain,
|
||||
MachineName = machine,
|
||||
UserName = user,
|
||||
Status = job.JobStatus,
|
||||
DeviceName = queue.Name
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
private string GetRawFileExtension(IntermediateFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case IntermediateFormat.Xps:
|
||||
return "xps";
|
||||
case IntermediateFormat.Ps:
|
||||
return "ps";
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
private void LogDebug(string message)
|
||||
{
|
||||
_logger.Debug(message);
|
||||
}
|
||||
|
||||
private void LogError(Exception exception, string message, params object[] args)
|
||||
{
|
||||
_logger.Error(exception, message, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
150
Common/VirtualPrinter.Agent.Lib/Misc/JobProcessor.cs
Normal file
150
Common/VirtualPrinter.Agent.Lib/Misc/JobProcessor.cs
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
using VirtualPrinter.Agent.Core;
|
||||
using VirtualPrinter.Agent.Lib.Model;
|
||||
using VirtualPrinter.Logging;
|
||||
using VirtualPrinter.ProgressInfo.Core;
|
||||
|
||||
namespace VirtualPrinter.Agent.Lib.Misc
|
||||
{
|
||||
public class JobProcessor : IJobProcessor
|
||||
{
|
||||
[NotNull]
|
||||
private readonly IRegistryRepository _registryRepository;
|
||||
|
||||
[NotNull]
|
||||
private readonly IJobRedirector _jobRedirector;
|
||||
|
||||
[NotNull]
|
||||
private readonly IVirtualPrinterLogger<JobProcessor> _logger;
|
||||
|
||||
[NotNull]
|
||||
private readonly IPostScriptConverter _postScriptConverter;
|
||||
|
||||
[NotNull]
|
||||
private readonly IProgressInfo _progressInfo;
|
||||
private readonly IDirectoryHelper _directoryHelper;
|
||||
|
||||
public JobProcessor
|
||||
(
|
||||
[NotNull]IRegistryRepository registryRepository,
|
||||
[NotNull]IVirtualPrinterLogger<JobProcessor> logger,
|
||||
[NotNull]IPostScriptConverter postScriptConverter,
|
||||
[NotNull]IJobRedirector redirector,
|
||||
[NotNull]IProgressInfo progressInfo,
|
||||
[NotNull]IDirectoryHelper directoryHelper
|
||||
)
|
||||
{
|
||||
if (registryRepository == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(registryRepository));
|
||||
}
|
||||
|
||||
if (logger == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
if (postScriptConverter == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(postScriptConverter));
|
||||
}
|
||||
|
||||
if (redirector == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(redirector));
|
||||
}
|
||||
|
||||
if (progressInfo == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(progressInfo));
|
||||
}
|
||||
|
||||
if (directoryHelper == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(directoryHelper));
|
||||
}
|
||||
|
||||
_registryRepository = registryRepository;
|
||||
_logger = logger;
|
||||
_postScriptConverter = postScriptConverter;
|
||||
_jobRedirector = redirector;
|
||||
_progressInfo = progressInfo;
|
||||
_directoryHelper = directoryHelper;
|
||||
_postScriptConverter.ProgressInitialized += OnProgressInitialized;
|
||||
_postScriptConverter.ProgressFinished += OnProgressFinished;
|
||||
_postScriptConverter.ProgressUpdate += OnProgressUpdate;
|
||||
}
|
||||
|
||||
public void Process(IJob job, IUserConfig userConfig)
|
||||
{
|
||||
if (job == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(job));
|
||||
}
|
||||
|
||||
if (userConfig == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(userConfig));
|
||||
}
|
||||
|
||||
var targetFile = $"{Path.GetFileNameWithoutExtension(job.RawDataPath)}";
|
||||
var config = _registryRepository.GetRegistryConfig();
|
||||
var dir = _directoryHelper.GetOutputDirectory(config);
|
||||
targetFile = Path.Combine(dir, targetFile);
|
||||
|
||||
var options = new PostScriptRenderOptions
|
||||
{
|
||||
UserRenderDpi = userConfig.UserRenderDpi,
|
||||
PdfOptions = new PostScriptRenderPdfOptions
|
||||
{
|
||||
Enabled = userConfig.Format == "PDF" || string.IsNullOrEmpty(userConfig.Format)
|
||||
},
|
||||
TiffOptions = new PostScriptRenderTiffOptions
|
||||
{
|
||||
Enabled = userConfig.Format == "TIFF"
|
||||
}
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
_postScriptConverter.Convert(job, targetFile, options);
|
||||
}
|
||||
catch (PostScriptConversionException exception)
|
||||
{
|
||||
LogError(exception, "Error processing PS file.");
|
||||
return;
|
||||
}
|
||||
|
||||
_jobRedirector.Redirect(job, userConfig);
|
||||
}
|
||||
|
||||
private void OnProgressUpdate(object sender, [NotNull]ProgressUpdateArgs args)
|
||||
{
|
||||
if (args == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(args));
|
||||
}
|
||||
|
||||
_progressInfo.Progress(args.Job, args.Value);
|
||||
}
|
||||
|
||||
private void OnProgressFinished(object sender, IJob job)
|
||||
{
|
||||
_progressInfo.Finish(job);
|
||||
}
|
||||
|
||||
private void OnProgressInitialized(object sender, IJob job)
|
||||
{
|
||||
_progressInfo.Initialize(job);
|
||||
}
|
||||
|
||||
private void LogError(Exception exception, string message, params object[] args)
|
||||
{
|
||||
_logger.Error(exception, message, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
106
Common/VirtualPrinter.Agent.Lib/Misc/JobRedirector.cs
Normal file
106
Common/VirtualPrinter.Agent.Lib/Misc/JobRedirector.cs
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
using VirtualPrinter.Agent.Core;
|
||||
using VirtualPrinter.Delivery;
|
||||
using VirtualPrinter.Logging;
|
||||
using VirtualPrinter.Utils;
|
||||
|
||||
namespace VirtualPrinter.Agent.Lib.Misc
|
||||
{
|
||||
public class JobRedirector : IJobRedirector
|
||||
{
|
||||
[NotNull]
|
||||
private readonly IVirtualPrinterLogger<JobRedirector> _logger;
|
||||
|
||||
[NotNull]
|
||||
private readonly IShell _shell;
|
||||
|
||||
public JobRedirector([NotNull]IVirtualPrinterLogger<JobRedirector> logger, [NotNull]IShell shell)
|
||||
{
|
||||
if (logger == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
if (shell == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(shell));
|
||||
}
|
||||
|
||||
_logger = logger;
|
||||
_shell = shell;
|
||||
}
|
||||
|
||||
public void Redirect(IJob job, IUserConfig userConfig)
|
||||
{
|
||||
if (job == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(job));
|
||||
}
|
||||
|
||||
if (userConfig == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(userConfig));
|
||||
}
|
||||
|
||||
var printer = userConfig.RedirectPrinter;
|
||||
if (string.IsNullOrWhiteSpace(printer))
|
||||
{
|
||||
LogWarn("Can not redirect to empty printer.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var pdfToRedirect = GetPdfPath(job.RawDataPath);
|
||||
|
||||
LogDebug($"Redirecting '{pdfToRedirect}' to '{printer}'...");
|
||||
|
||||
var redirectExe = Path.GetFullPath(typeof(Redirector).Assembly.Location);
|
||||
var redirectArgs = $@"redirect ""{pdfToRedirect}"" ""{printer}""";
|
||||
|
||||
_shell.Execute(job.JobInfo, job.SessionInfo, redirectExe, redirectArgs);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LogError(exception, $"{exception.GetType()}: {exception.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
private static string GetPdfPath([NotNull]string rawFilePath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(rawFilePath))
|
||||
{
|
||||
throw new ArgumentException(nameof(rawFilePath));
|
||||
}
|
||||
|
||||
var directoryName = Path.GetDirectoryName(rawFilePath);
|
||||
if (string.IsNullOrWhiteSpace(directoryName))
|
||||
{
|
||||
throw new ArgumentException(nameof(directoryName));
|
||||
}
|
||||
|
||||
var file = Path.GetFileNameWithoutExtension(rawFilePath);
|
||||
return Path.Combine(directoryName, file) + ".pdf";
|
||||
}
|
||||
|
||||
private void LogDebug(string message, params object[] args)
|
||||
{
|
||||
_logger.Debug(message, args);
|
||||
}
|
||||
|
||||
private void LogWarn(string message, params object[] args)
|
||||
{
|
||||
_logger.Warn(message, args);
|
||||
}
|
||||
|
||||
private void LogError(Exception exception, string message, params object[] args)
|
||||
{
|
||||
_logger.Error(exception, message, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
170
Common/VirtualPrinter.Agent.Lib/Misc/JobService.cs
Normal file
170
Common/VirtualPrinter.Agent.Lib/Misc/JobService.cs
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Printing;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
using VirtualPrinter.Agent.Core;
|
||||
|
||||
namespace VirtualPrinter.Agent.Lib.Misc
|
||||
{
|
||||
public class JobService : IJobService
|
||||
{
|
||||
[NotNull]
|
||||
private readonly IRegistryRepository _registryRepository;
|
||||
|
||||
[NotNull]
|
||||
private readonly IJobFactory _jobFactory;
|
||||
|
||||
[NotNull]
|
||||
private readonly IShell _shell;
|
||||
private IDirectoryHelper _directoryHelper;
|
||||
|
||||
public JobService
|
||||
(
|
||||
[NotNull]IRegistryRepository registryRepository,
|
||||
[NotNull]IJobFactory jobFactory,
|
||||
[NotNull]IShell shell,
|
||||
[NotNull]IDirectoryHelper directoryHelper
|
||||
)
|
||||
{
|
||||
if (registryRepository == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(registryRepository));
|
||||
}
|
||||
|
||||
if (jobFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(jobFactory));
|
||||
}
|
||||
|
||||
if (shell == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(shell));
|
||||
}
|
||||
|
||||
if (directoryHelper == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(directoryHelper));
|
||||
}
|
||||
|
||||
_registryRepository = registryRepository;
|
||||
_jobFactory = jobFactory;
|
||||
_shell = shell;
|
||||
_directoryHelper = directoryHelper;
|
||||
}
|
||||
|
||||
public void Start(IJob job)
|
||||
{
|
||||
if (job == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(job));
|
||||
}
|
||||
|
||||
const PrintStatus status = PrintStatus.Paused;
|
||||
|
||||
var iniFile = Path.GetFullPath(job.IniDataPath);
|
||||
var config = _registryRepository.GetRegistryConfig();
|
||||
var pre = config.ResolvedPreconverter;
|
||||
WriteJobStartIni(job, status);
|
||||
|
||||
_shell.Execute(job.JobInfo, job.SessionInfo, pre.Item1, $"{pre.Item2} \"{iniFile}\"");
|
||||
}
|
||||
|
||||
public IJob CreateJob(string iniFile, string rawFile)
|
||||
{
|
||||
var jobInfo = GetJobInfo(iniFile);
|
||||
|
||||
var sessionInfo = GetSessionInfo(iniFile);
|
||||
|
||||
return _jobFactory.Create(iniFile, rawFile, jobInfo, sessionInfo);
|
||||
}
|
||||
|
||||
public PrintStatus ReadStatus(string iniPath)
|
||||
{
|
||||
var txt = _shell.ReadIniEntry<string>("Preconverting", "Status", iniPath);
|
||||
Enum.TryParse(txt, true, out PrintStatus result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public JobStatus ReadJobStatus(string iniPath)
|
||||
{
|
||||
var status = _shell.ReadIniEntry<string>("Job", "Status", iniPath);
|
||||
Enum.TryParse(status, true, out JobStatus result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Finish(IJob job)
|
||||
{
|
||||
var config = _registryRepository.GetRegistryConfig();
|
||||
WriteJobFinishIni(job.IniDataPath, config);
|
||||
var iniFile = Path.GetFullPath(job.IniDataPath);
|
||||
var post = config.ResolvedPostconverter;
|
||||
|
||||
_shell.Execute(job.JobInfo, job.SessionInfo, post.Item1, $"{post.Item2} \"{iniFile}\"");
|
||||
}
|
||||
|
||||
private void WriteJobStartIni([NotNull]IJob job, PrintStatus status)
|
||||
{
|
||||
_shell.WriteIniEntry("Job", "Status", JobStatus.InProgress.ToString().ToLowerInvariant(), job.IniDataPath);
|
||||
_shell.WriteIniEntry("Device", "DeviceName", job.JobInfo.DeviceName, job.IniDataPath);
|
||||
_shell.WriteIniEntry("Document", "Name", job.JobInfo.Name.Normalize(), job.IniDataPath);
|
||||
_shell.WriteIniEntry("Document", "JobID", $"{job.JobInfo.JobId}", job.IniDataPath);
|
||||
_shell.WriteIniEntry("Document", "DomainName", job.JobInfo.DomainName, job.IniDataPath);
|
||||
_shell.WriteIniEntry("Document", "MachineName", job.JobInfo.MachineName, job.IniDataPath);
|
||||
_shell.WriteIniEntry("Document", "UserName", job.JobInfo.UserName, job.IniDataPath);
|
||||
_shell.WriteIniEntry("Document", "SessionID", $"{job.SessionInfo.Id}", job.IniDataPath);
|
||||
_shell.WriteIniEntry("Document", "Desktop", $"{job.SessionInfo.Desktop}", job.IniDataPath);
|
||||
_shell.WriteIniEntry("Document", "SID", $"{job.SessionInfo.Sid}", job.IniDataPath);
|
||||
_shell.WriteIniEntry("Document", "Status", job.JobInfo.Status.ToString(), job.IniDataPath);
|
||||
_shell.WriteIniEntry("Preconverting", "Status", status.ToIni(), job.IniDataPath);
|
||||
}
|
||||
|
||||
private SessionInfo GetSessionInfo(string iniFile)
|
||||
{
|
||||
var sessionInfo = new SessionInfo
|
||||
{
|
||||
Id = _shell.ReadIniEntry<int>("Document",
|
||||
"SessionID",
|
||||
iniFile),
|
||||
Sid = _shell.ReadIniEntry<string>("Document", "SID", iniFile),
|
||||
Desktop = _shell.ReadIniEntry<string>("Document", "Desktop", iniFile)
|
||||
};
|
||||
return sessionInfo;
|
||||
}
|
||||
|
||||
private JobInfo GetJobInfo(string iniFile)
|
||||
{
|
||||
var jobInfo = new JobInfo
|
||||
{
|
||||
DomainName = _shell.ReadIniEntry<string>("Document",
|
||||
"DomainName",
|
||||
iniFile),
|
||||
MachineName = _shell.ReadIniEntry<string>("Document",
|
||||
"MachineName",
|
||||
iniFile),
|
||||
UserName = _shell.ReadIniEntry<string>("Document",
|
||||
"UserName",
|
||||
iniFile)
|
||||
};
|
||||
return jobInfo;
|
||||
}
|
||||
|
||||
private void WriteJobFinishIni(string iniPath, [NotNull]IExConfig config)
|
||||
{
|
||||
const PrintStatus status = PrintStatus.Complete;
|
||||
const PrintJobStatus spoolerState = PrintJobStatus.Printed;
|
||||
|
||||
_shell.WriteIniEntry("Preconverting", "Status", status.ToIni(), iniPath);
|
||||
var pdfFile = Path.GetFileNameWithoutExtension(iniPath) + ".pdf";
|
||||
var tiffFile = Path.GetFileNameWithoutExtension(iniPath) + ".tif";
|
||||
var dir = _directoryHelper.GetOutputDirectory(config);
|
||||
pdfFile = Path.Combine(dir, pdfFile);
|
||||
tiffFile = Path.Combine(dir, tiffFile);
|
||||
_shell.WriteIniEntry("PDF", "File0", pdfFile, iniPath);
|
||||
_shell.WriteIniEntry("TIFF", "File0", tiffFile, iniPath);
|
||||
_shell.WriteIniEntry("Document", "Status", spoolerState.ToString(), iniPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
276
Common/VirtualPrinter.Agent.Lib/Misc/VirtualTcpInputPrinter.cs
Normal file
276
Common/VirtualPrinter.Agent.Lib/Misc/VirtualTcpInputPrinter.cs
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
using JetBrains.Annotations;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
|
||||
using VirtualPrinter.Agent.Core;
|
||||
using VirtualPrinter.Logging;
|
||||
using VirtualPrinter.SetupDriver;
|
||||
|
||||
namespace VirtualPrinter.Agent.Lib.Misc
|
||||
{
|
||||
public class VirtualTcpInputPrinter : IVirtualPrinter
|
||||
{
|
||||
[NotNull]
|
||||
private readonly IRegistryRepository _registryRepository;
|
||||
|
||||
[NotNull]
|
||||
private readonly IJobFactory _jobFactory;
|
||||
|
||||
[NotNull]
|
||||
private readonly IJobService _jobService;
|
||||
|
||||
[NotNull]
|
||||
private readonly IVirtualPrinterLogger<VirtualTcpInputPrinter> _logger;
|
||||
|
||||
[NotNull]
|
||||
private readonly IJobProcessor _jobProcessor;
|
||||
private IDirectoryHelper _directoryHelper;
|
||||
private TcpListener _socket;
|
||||
|
||||
private FileSystemWatcher _watcher;
|
||||
|
||||
public VirtualTcpInputPrinter
|
||||
(
|
||||
[NotNull]IRegistryRepository registryRepository,
|
||||
[NotNull]IVirtualPrinterLogger<VirtualTcpInputPrinter> logger,
|
||||
[NotNull]IJobFactory jobFactory,
|
||||
[NotNull]IJobService jobService,
|
||||
[NotNull]IJobProcessor jobProcessor,
|
||||
[NotNull]IDirectoryHelper directoryHelper
|
||||
)
|
||||
{
|
||||
_registryRepository = registryRepository;
|
||||
_logger = logger;
|
||||
_jobFactory = jobFactory;
|
||||
_jobService = jobService;
|
||||
_jobProcessor = jobProcessor;
|
||||
_directoryHelper = directoryHelper;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_watcher.Dispose();
|
||||
_socket.Stop();
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
var config = GetRegistryConfig();
|
||||
|
||||
var dir = _directoryHelper.GetOutputDirectory(config);
|
||||
_watcher = new FileSystemWatcher(dir, "*.ini")
|
||||
{
|
||||
IncludeSubdirectories = false,
|
||||
NotifyFilter = NotifyFilters.LastWrite,
|
||||
EnableRaisingEvents = true
|
||||
};
|
||||
_watcher.Changed += IniFileChanged;
|
||||
_socket = new TcpListener(IPAddress.Loopback, config.PrinterPort);
|
||||
_socket.Start();
|
||||
_socket.BeginAcceptTcpClient(HandleClient, _socket);
|
||||
|
||||
LogDebug($"Waiting on {_socket.LocalEndpoint}...");
|
||||
}
|
||||
|
||||
private void HandleClient([NotNull]IAsyncResult ar)
|
||||
{
|
||||
const string printer = Defaults.PrinterName;
|
||||
IJob job;
|
||||
|
||||
var socket = (TcpListener) ar.AsyncState;
|
||||
using (var client = socket.EndAcceptTcpClient(ar))
|
||||
{
|
||||
var local = client.Client.LocalEndPoint;
|
||||
var remote = client.Client.RemoteEndPoint;
|
||||
|
||||
LogDebug($"{remote} --> {local}");
|
||||
job = _jobFactory.Create(printer, client.GetStream());
|
||||
if (job == null)
|
||||
{
|
||||
LogError("Job could not be created.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LogDebug($"Temporarily printed '{job.RawDataPath}'!");
|
||||
socket.BeginAcceptTcpClient(HandleClient, ar.AsyncState);
|
||||
|
||||
_jobService.Start(job);
|
||||
}
|
||||
|
||||
private void IniFileChanged(object sender, [NotNull]FileSystemEventArgs e)
|
||||
{
|
||||
var ini = e.FullPath;
|
||||
if (!ini.ToLowerInvariant().EndsWith(".ini"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var rawName = $"{Path.GetFileNameWithoutExtension(ini)}.ps";
|
||||
var config = GetRegistryConfig();
|
||||
var dir = _directoryHelper.GetOutputDirectory(config);
|
||||
var rawFile = Path.Combine(dir, rawName);
|
||||
var status = _jobService.ReadStatus(ini);
|
||||
|
||||
if (status == PrintStatus.Resumed)
|
||||
{
|
||||
var job = _jobService.CreateJob(ini, rawFile);
|
||||
var isJobValid = IsJobValid(job);
|
||||
|
||||
if (!isJobValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessFile(rawFile, ini);
|
||||
}
|
||||
if (status == PrintStatus.Canceled)
|
||||
{
|
||||
DeleteFiles(ini, dir, rawFile);
|
||||
}
|
||||
|
||||
var jobStatus = _jobService.ReadJobStatus(ini);
|
||||
if (jobStatus == JobStatus.Completed || jobStatus == JobStatus.Failed)
|
||||
{
|
||||
DeleteFiles(ini, dir, rawFile);
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteFiles([NotNull]string ini, [NotNull]string outputDir, [NotNull]string rawFile)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ini))
|
||||
{
|
||||
throw new ArgumentException("Value cannot be null or whitespace.", nameof(ini));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(outputDir))
|
||||
{
|
||||
throw new ArgumentException("Value cannot be null or whitespace.", nameof(outputDir));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(rawFile))
|
||||
{
|
||||
throw new ArgumentException("Value cannot be null or whitespace.", nameof(rawFile));
|
||||
}
|
||||
|
||||
var pdfFile = Path.Combine(outputDir, $"{Path.GetFileNameWithoutExtension(ini)}.pdf");
|
||||
var tiffFile = Path.Combine(outputDir, $"{Path.GetFileNameWithoutExtension(ini)}.tif");
|
||||
|
||||
if (File.Exists(pdfFile) && !IsFileLocked(pdfFile))
|
||||
{
|
||||
File.Delete(pdfFile);
|
||||
}
|
||||
|
||||
if (File.Exists(tiffFile) && !IsFileLocked(tiffFile))
|
||||
{
|
||||
File.Delete(tiffFile);
|
||||
}
|
||||
|
||||
File.Delete(ini);
|
||||
File.Delete(rawFile);
|
||||
}
|
||||
|
||||
private bool IsFileLocked(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
using(var stream = File.Open(filePath, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
stream.Close();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
private IExConfig GetRegistryConfig()
|
||||
{
|
||||
return _registryRepository.GetRegistryConfig();
|
||||
}
|
||||
|
||||
private bool IsJobValid([CanBeNull]IJob job)
|
||||
{
|
||||
if (job == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(job.JobInfo.DomainName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(job.JobInfo.MachineName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(job.JobInfo.UserName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(job.SessionInfo.Sid))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ProcessFile(string filePath, string iniFile)
|
||||
{
|
||||
var thread = new Thread(obj =>
|
||||
{
|
||||
var tuple = (Tuple<string, string>) obj;
|
||||
var rawFile = tuple.Item1;
|
||||
var ini = tuple.Item2;
|
||||
|
||||
var job = _jobService.CreateJob(ini,
|
||||
rawFile);
|
||||
|
||||
try
|
||||
{
|
||||
var userConfig = _registryRepository.GetUserRegistryConfig(job.SessionInfo.Sid);
|
||||
_jobProcessor.Process(job, userConfig);
|
||||
|
||||
LogDebug($"Converted '{rawFile}'!");
|
||||
_jobService.Finish(job);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LogError(exception,
|
||||
"Failed to process file. Job: {@job}",
|
||||
job);
|
||||
}
|
||||
});
|
||||
|
||||
thread.SetApartmentState(ApartmentState.STA);
|
||||
thread.Start(Tuple.Create(filePath, iniFile));
|
||||
}
|
||||
|
||||
private void LogError(Exception exception, string message, params object[] args)
|
||||
{
|
||||
_logger.Error(exception, message, args);
|
||||
}
|
||||
|
||||
private void LogError(string message, params object[] args)
|
||||
{
|
||||
_logger.Error(message, args);
|
||||
}
|
||||
|
||||
private void LogDebug(string message, params object[] args)
|
||||
{
|
||||
_logger.Debug(message, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Common/VirtualPrinter.Agent.Lib/Model/ProgressUpdateArgs.cs
Normal file
22
Common/VirtualPrinter.Agent.Lib/Model/ProgressUpdateArgs.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
using VirtualPrinter.Agent.Core.Interfaces;
|
||||
|
||||
namespace VirtualPrinter.Agent.Lib.Model
|
||||
{
|
||||
public class ProgressUpdateArgs : EventArgs
|
||||
{
|
||||
public ProgressUpdateArgs([NotNull] IJob job, uint val)
|
||||
{
|
||||
Job = job;
|
||||
Value = val;
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
public IJob Job { get; }
|
||||
|
||||
public uint Value { get; }
|
||||
}
|
||||
}
|
||||
32
Common/VirtualPrinter.Agent.Lib/Properties/AssemblyInfo.cs
Normal file
32
Common/VirtualPrinter.Agent.Lib/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
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.Agent.Lib")]
|
||||
[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("3d3f946d-c8dc-4518-b464-75e73cbad734")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
100
Common/VirtualPrinter.Agent.Lib/VirtualPrinter.Agent.Lib.csproj
Normal file
100
Common/VirtualPrinter.Agent.Lib/VirtualPrinter.Agent.Lib.csproj
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
<?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>{94E8105F-5001-403B-B9F1-B0B0B236AD65}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>VirtualPrinter.Agent.Lib</RootNamespace>
|
||||
<AssemblyName>VirtualPrinter.Agent.Lib</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<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' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\..\Files\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Misc\GhostScriptConverter.cs" />
|
||||
<Compile Include="Misc\JobProcessor.cs" />
|
||||
<Compile Include="Misc\JobRedirector.cs" />
|
||||
<Compile Include="Misc\Job.cs" />
|
||||
<Compile Include="Misc\JobFactory.cs" />
|
||||
<Compile Include="Misc\JobService.cs" />
|
||||
<Compile Include="Misc\VirtualTcpInputPrinter.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="VirtualPrinterService.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.IO.Compression" />
|
||||
<Reference Include="System.Printing" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Transactions" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="WindowsBase" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Agent\VirtualPrinter.Delivery\VirtualPrinter.Delivery.csproj">
|
||||
<Project>{74fa80b3-7cf1-4b68-8aa3-4c3d37bbe855}</Project>
|
||||
<Name>VirtualPrinter.Delivery</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Installer\VirtualPrinter.SetupDriver\VirtualPrinter.SetupDriver.csproj">
|
||||
<Project>{12402f90-a2ae-4549-9142-f90650e2082a}</Project>
|
||||
<Name>VirtualPrinter.SetupDriver</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\UI\VirtualPrinter.ProgressInfo.Core\VirtualPrinter.ProgressInfo.Core.csproj">
|
||||
<Project>{24d28558-c825-43e6-85d2-7c59f4a97698}</Project>
|
||||
<Name>VirtualPrinter.ProgressInfo.Core</Name>
|
||||
</ProjectReference>
|
||||
<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>
|
||||
<ProjectReference Include="..\VirtualPrinter.Utils\VirtualPrinter.Utils.csproj">
|
||||
<Project>{cd1c8e9d-5335-41ac-b0c0-88fd7c7c55f3}</Project>
|
||||
<Name>VirtualPrinter.Utils</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autofac" Version="6.0.0" />
|
||||
<PackageReference Include="Cassia" Version="3.0.0-alpha.9" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0-rc.2.20475.5" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="5.0.0-rc.2.20475.5" />
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
27
Common/VirtualPrinter.Agent.Lib/VirtualPrinterService.cs
Normal file
27
Common/VirtualPrinter.Agent.Lib/VirtualPrinterService.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using JetBrains.Annotations;
|
||||
|
||||
using VirtualPrinter.Agent.Core;
|
||||
|
||||
namespace VirtualPrinter.Agent.Lib
|
||||
{
|
||||
public class VirtualPrinterService : IVirtualPrinterService
|
||||
{
|
||||
[NotNull]
|
||||
private readonly IVirtualPrinter _printer;
|
||||
|
||||
public VirtualPrinterService([NotNull]IVirtualPrinter printer)
|
||||
{
|
||||
_printer = printer;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_printer.Init();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_printer.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
81
Common/VirtualPrinter.Logging/IVirtualPrinterLogger.cs
Normal file
81
Common/VirtualPrinter.Logging/IVirtualPrinterLogger.cs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
using System;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace VirtualPrinter.Logging
|
||||
{
|
||||
// ReSharper disable once UnusedTypeParameter
|
||||
public interface IVirtualPrinterLogger<out T> : IVirtualPrinterLogger
|
||||
{ }
|
||||
|
||||
public interface IVirtualPrinterLogger
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name of the logger.
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A value of true if logging is enabled for the Debug level, otherwise it returns false.
|
||||
/// </summary>
|
||||
bool IsDebugEnabled { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A value of true if logging is enabled for the Trace level, otherwise it returns false.
|
||||
/// </summary>
|
||||
bool IsTraceEnabled { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Writes the exception at the <c>Error</c> level.
|
||||
/// </summary>
|
||||
/// <param name="exception">An exception to be logged.</param>
|
||||
void Error([CanBeNull]Exception exception);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the diagnostic message and exception at the <c>Error</c> level.
|
||||
/// </summary>
|
||||
/// <param name="exception">An exception to be logged.</param>
|
||||
/// <param name="message">A <see langword="string" /> to be written.</param>
|
||||
/// <param name="args">Arguments to format.</param>
|
||||
void Error([CanBeNull]Exception exception, [CanBeNull]string message, [CanBeNull, ItemCanBeNull]params object[] args);
|
||||
|
||||
/// <summary>
|
||||
/// Something failed; application may or may not continue
|
||||
/// Writes the diagnostic message and exception at the <c>Error</c> level.
|
||||
/// </summary>
|
||||
/// <param name="message">A <see langword="string" /> to be written.</param>
|
||||
/// <param name="args">Arguments to format.</param>
|
||||
void Error([CanBeNull]string message, [CanBeNull, ItemCanBeNull]params object[] args);
|
||||
|
||||
/// <summary>
|
||||
/// Something unexpected; application will continue
|
||||
/// Writes the diagnostic message at the <c>Warn</c> level using the specified parameters.
|
||||
/// </summary>
|
||||
/// <param name="message">A <see langword="string" /> containing format items.</param>
|
||||
/// <param name="args">Arguments to format.</param>
|
||||
void Warn([CanBeNull]string message, [CanBeNull, ItemCanBeNull]params object[] args);
|
||||
|
||||
/// <summary>
|
||||
/// Normal behavior like mail sent, user updated profile etc.
|
||||
/// Writes the diagnostic message at the <c>Info</c> level using the specified parameters.
|
||||
/// </summary>
|
||||
/// <param name="message">A <see langword="string" /> containing format items.</param>
|
||||
/// <param name="args">Arguments to format.</param>
|
||||
void Info([CanBeNull]string message, [CanBeNull, ItemCanBeNull]params object[] args);
|
||||
|
||||
/// <summary>
|
||||
/// For debugging; executed query, user authenticated, session expired
|
||||
/// Writes the diagnostic message at the <c>Debug</c> level using the specified parameters.
|
||||
/// </summary>
|
||||
/// <param name="message">A <see langword="string" /> containing format items.</param>
|
||||
/// <param name="args">Arguments to format.</param>
|
||||
void Debug([CanBeNull]string message, [CanBeNull, ItemCanBeNull]params object[] args);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the diagnostic message at the <c>Trace</c> level using the specified parameters.
|
||||
/// </summary>
|
||||
/// <param name="message">A <see langword="string" /> containing format items.</param>
|
||||
/// <param name="args">Arguments to format.</param>
|
||||
void Trace([CanBeNull]string message, [CanBeNull, ItemCanBeNull]params object[] args);
|
||||
}
|
||||
}
|
||||
17
Common/VirtualPrinter.Logging/LoggerModule.cs
Normal file
17
Common/VirtualPrinter.Logging/LoggerModule.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
using Autofac;
|
||||
using Autofac.Extras.NLog;
|
||||
|
||||
namespace VirtualPrinter.Logging
|
||||
{
|
||||
public class LoggerModule : Module
|
||||
{
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
builder.RegisterModule<NLogModule>();
|
||||
builder.RegisterInstance(NLog.LogManager.GetCurrentClassLogger()).As<NLog.ILogger>().SingleInstance();
|
||||
builder.RegisterGeneric(typeof(VirtualPrinterLogger<>))
|
||||
.As(typeof(IVirtualPrinterLogger<>))
|
||||
.SingleInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Common/VirtualPrinter.Logging/NLog.config
Normal file
25
Common/VirtualPrinter.Logging/NLog.config
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
|
||||
autoReload="true"
|
||||
throwExceptions="false"
|
||||
internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log">
|
||||
|
||||
<variable name="log_title" value="${processname}"/>
|
||||
|
||||
<targets>
|
||||
<target name="console" xsi:type="ColoredConsole" layout="${longdate} ${level} ${message} ${exception:format=ToString}"/>
|
||||
<target xsi:type="EventLog"
|
||||
name="eventlog"
|
||||
log ="Application"
|
||||
source="${var:log_title}"
|
||||
layout="${message}${newline}${exception:format=ToString}">
|
||||
</target>
|
||||
</targets>
|
||||
|
||||
<rules>
|
||||
<logger name="*" minlevel="Debug" writeTo="console" />
|
||||
<logger name="*" minlevel="Info" writeTo="eventlog" />
|
||||
</rules>
|
||||
</nlog>
|
||||
35
Common/VirtualPrinter.Logging/Properties/AssemblyInfo.cs
Normal file
35
Common/VirtualPrinter.Logging/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.Logging")]
|
||||
[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("aa25364d-22d5-44b0-86a5-6fb14c686308")]
|
||||
|
||||
// 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")]
|
||||
71
Common/VirtualPrinter.Logging/VirtualPrinter.Logging.csproj
Normal file
71
Common/VirtualPrinter.Logging/VirtualPrinter.Logging.csproj
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?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>{AA25364D-22D5-44B0-86A5-6FB14C686308}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>VirtualPrinter.Logging</RootNamespace>
|
||||
<AssemblyName>VirtualPrinter.Logging</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
</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="System" />
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.IO.Compression" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Transactions" />
|
||||
<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="IVirtualPrinterLogger.cs" />
|
||||
<Compile Include="LoggerModule.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="VirtualPrinterLogger.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="NLog.config">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autofac" Version="6.0.0" />
|
||||
<PackageReference Include="Autofac.Extras.NLog" Version="4.0.0" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0-rc.2.20475.5" />
|
||||
<PackageReference Include="NLog" Version="4.6.1" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="5.0.0-rc.2.20475.5" />
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
103
Common/VirtualPrinter.Logging/VirtualPrinterLogger.cs
Normal file
103
Common/VirtualPrinter.Logging/VirtualPrinterLogger.cs
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
using System;
|
||||
using System.CodeDom;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.IO;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
using NLog;
|
||||
|
||||
namespace VirtualPrinter.Logging
|
||||
{
|
||||
public class VirtualPrinterLogger<T> : VirtualPrinterLogger, IVirtualPrinterLogger<T>
|
||||
{
|
||||
public VirtualPrinterLogger() : base(ReadableTypeName.Generate(typeof(T)))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static class ReadableTypeName
|
||||
{
|
||||
[NotNull]
|
||||
public static string Generate([NotNull]Type type)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
}
|
||||
|
||||
var provider = CodeDomProvider.CreateProvider("C#");
|
||||
var typeReferenceExpression = new CodeTypeReferenceExpression(type);
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
provider.GenerateCodeFromExpression(typeReferenceExpression, writer, new CodeGeneratorOptions());
|
||||
return writer.GetStringBuilder().ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class VirtualPrinterLogger : IVirtualPrinterLogger
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public VirtualPrinterLogger([NotNull]string loggerName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(loggerName))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(loggerName));
|
||||
}
|
||||
|
||||
_logger = LogManager.GetLogger(loggerName);
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return _logger.Name; }
|
||||
}
|
||||
|
||||
public bool IsDebugEnabled
|
||||
{
|
||||
get { return _logger.IsDebugEnabled; }
|
||||
}
|
||||
|
||||
public bool IsTraceEnabled
|
||||
{
|
||||
get { return _logger.IsTraceEnabled; }
|
||||
}
|
||||
|
||||
public void Error(Exception exception)
|
||||
{
|
||||
_logger.Error(exception);
|
||||
}
|
||||
|
||||
public void Error(Exception exception, string message, params object[] args)
|
||||
{
|
||||
_logger.Error(exception, message, args);
|
||||
}
|
||||
|
||||
public void Error(string message, params object[] args)
|
||||
{
|
||||
_logger.Error(message, args);
|
||||
}
|
||||
|
||||
public void Warn(string message, params object[] args)
|
||||
{
|
||||
_logger.Warn(message, args);
|
||||
}
|
||||
|
||||
public void Info(string message, params object[] args)
|
||||
{
|
||||
_logger.Info(message, args);
|
||||
}
|
||||
|
||||
public void Debug(string message, params object[] args)
|
||||
{
|
||||
_logger.Debug(message, args);
|
||||
}
|
||||
|
||||
public void Trace(string message, params object[] args)
|
||||
{
|
||||
_logger.Trace(message, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
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