Implemented VirtualPrinterDriver project

This commit is contained in:
Marco Batzinger 2020-10-19 17:44:50 +02:00
parent f29c84821b
commit 5c87967c3f
125 changed files with 8191 additions and 0 deletions

View file

@ -0,0 +1,8 @@
namespace VirtualPrinter.Agent.Core.Enums
{
public enum IntermediateFormat
{
Ps,
Xps
}
}

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

View file

@ -0,0 +1,7 @@
namespace VirtualPrinter.Agent.Core
{
public interface IDirectoryHelper
{
string GetOutputDirectory(IExConfig config);
}
}

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

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

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

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

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

View file

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

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

View file

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

View file

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

View file

@ -0,0 +1,11 @@
namespace VirtualPrinter.Agent.Core
{
public interface ISessionInfo
{
int Id { get; set; }
string Desktop { get; set; }
string Sid { get; set; }
}
}

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

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

View file

@ -0,0 +1,12 @@
using System;
namespace VirtualPrinter.Agent.Core
{
public interface IVirtualPrinter : IDisposable
{
/// <summary>
/// Initialize the virtual printer.
/// </summary>
void Init();
}
}

View file

@ -0,0 +1,8 @@
namespace VirtualPrinter.Agent.Core
{
public interface IVirtualPrinterService
{
void Start();
void Stop();
}
}

View file

@ -0,0 +1,9 @@
namespace VirtualPrinter.Agent.Core
{
public enum JobStatus
{
Completed,
Failed,
InProgress
}
}

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

View file

@ -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)
{
}
}
}

View file

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

View file

@ -0,0 +1,8 @@
namespace VirtualPrinter.Agent.Core
{
public struct PostScriptRenderPdfOptions
{
public bool Enabled { set; get; }
public bool Archivable { get; set; }
}
}

View file

@ -0,0 +1,7 @@
namespace VirtualPrinter.Agent.Core
{
public struct PostScriptRenderTiffOptions
{
public bool Enabled { set; get; }
}
}

View 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();
}
}
}

View file

@ -0,0 +1,15 @@
namespace VirtualPrinter.Agent.Core
{
public enum PrintStatus
{
Undefined = 0,
Paused,
Resumed,
Complete,
Canceled
}
}

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

View 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());
}
}
}

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

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

View 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")]

View file

@ -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>