Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b76367f73a | ||
|
|
76ea3513ac | ||
|
|
07b197958d | ||
|
|
470c6e09e5 | ||
|
|
20b19775b1 | ||
|
|
f13a836ebd |
@@ -2,6 +2,22 @@
|
|||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
[v1.1.0.2][v1.1.0.2] (2026-08-11) {#v1.1.0.2}
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
### Neue Funktionen {#v1.1.0.2-features}
|
||||||
|
|
||||||
|
* Es ist nun möglich zwischen dem Senden von E-Mail einige Sekunden zu warten (Konfigurationsdatei -> `[smtp]` -> `wait = 0.5`). (76ea3513ac)
|
||||||
|
|
||||||
|
### Behobene Fehler {#v1.1.0.2-bugfixes}
|
||||||
|
|
||||||
|
* Beim Drucken von Dokumenten waren die Seitenränder nicht korrekt. (f13a836ebd, 20b19775b1, 470c6e09e5, 07b197958d)
|
||||||
|
|
||||||
|
[v1.1.0.2]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.0.2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[v1.1.0.1][v1.1.0.1] (2026-08-05) {#v1.1.0.1}
|
[v1.1.0.1][v1.1.0.1] (2026-08-05) {#v1.1.0.1}
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -9,7 +9,7 @@
|
|||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||||
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
|
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
|
||||||
<Version>1.1.0.1</Version>
|
<Version>1.1.0.2</Version>
|
||||||
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<ApplicationManifest>App.manifest</ApplicationManifest>
|
<ApplicationManifest>App.manifest</ApplicationManifest>
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="bblanchon.PDFium.Win32" Version="153.0.7988" />
|
<PackageReference Include="bblanchon.PDFium.Win32" Version="153.0.7999" />
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||||
<PackageReference Include="itext" Version="9.7.0" />
|
<PackageReference Include="itext" Version="9.7.0" />
|
||||||
<PackageReference Include="itext.bouncy-castle-adapter" Version="9.7.0" />
|
<PackageReference Include="itext.bouncy-castle-adapter" Version="9.7.0" />
|
||||||
|
|||||||
@@ -57,9 +57,10 @@ namespace Elwig.Helpers {
|
|||||||
public string? SmtpUsername = null;
|
public string? SmtpUsername = null;
|
||||||
public string? SmtpPassword = null;
|
public string? SmtpPassword = null;
|
||||||
public string? SmtpFrom = null;
|
public string? SmtpFrom = null;
|
||||||
public (string Host, int Port, string Mode, string Username, string Password, string From)? Smtp =>
|
public double SmtpWait = 0;
|
||||||
|
public (string Host, int Port, string Mode, string Username, string Password, string From, double Wait)? Smtp =>
|
||||||
SmtpHost == null || SmtpPort == null || SmtpMode == null || SmtpUsername == null || SmtpPassword == null || SmtpFrom == null ?
|
SmtpHost == null || SmtpPort == null || SmtpMode == null || SmtpUsername == null || SmtpPassword == null || SmtpFrom == null ?
|
||||||
null : (SmtpHost, (int)SmtpPort, SmtpMode, SmtpUsername, SmtpPassword, SmtpFrom);
|
null : (SmtpHost, (int)SmtpPort, SmtpMode, SmtpUsername, SmtpPassword, SmtpFrom, SmtpWait);
|
||||||
|
|
||||||
public IList<ScaleConfig> Scales;
|
public IList<ScaleConfig> Scales;
|
||||||
private readonly List<ScaleConfig> ScaleList = [];
|
private readonly List<ScaleConfig> ScaleList = [];
|
||||||
@@ -92,6 +93,7 @@ namespace Elwig.Helpers {
|
|||||||
SmtpUsername = config["smtp:username"];
|
SmtpUsername = config["smtp:username"];
|
||||||
SmtpPassword = config["smtp:password"];
|
SmtpPassword = config["smtp:password"];
|
||||||
SmtpFrom = config["smtp:from"];
|
SmtpFrom = config["smtp:from"];
|
||||||
|
SmtpWait = double.TryParse(config["smtp:wait"], out var res) ? res : 0;
|
||||||
|
|
||||||
var scales = config.AsEnumerable().Where(i => i.Key.StartsWith("scale.")).GroupBy(i => i.Key.Split(':')[0][6..]).Select(i => i.Key).Order();
|
var scales = config.AsEnumerable().Where(i => i.Key.StartsWith("scale.")).GroupBy(i => i.Key.Split(':')[0][6..]).Select(i => i.Key).Order();
|
||||||
ScaleList.Clear();
|
ScaleList.Clear();
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Elwig.Services;
|
using Elwig.Services;
|
||||||
using Elwig.Windows;
|
using Elwig.Windows;
|
||||||
using System;
|
using System;
|
||||||
using System.Drawing.Printing;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Elwig.Helpers.Printing {
|
namespace Elwig.Helpers.Printing {
|
||||||
@@ -32,20 +31,10 @@ namespace Elwig.Helpers.Printing {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task Print(string path, int copies = 1, bool doublePaged = false) {
|
public static Task Print(string path, int copies = 1, bool doublePaged = false) {
|
||||||
await Print(path, new() {
|
|
||||||
Copies = (short)copies,
|
|
||||||
Collate = true,
|
|
||||||
Duplex = doublePaged ? Duplex.Vertical : Duplex.Simplex,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Task Print(string path, PrinterSettings settings) {
|
|
||||||
try {
|
try {
|
||||||
using var printDoc = new PdfPrintDocument(path) {
|
var printer = new PdfPrinter();
|
||||||
PrinterSettings = settings,
|
printer.Print(path, copies, doublePaged);
|
||||||
};
|
|
||||||
printDoc.Print();
|
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
InteractionService.ShowException("Fehler beim Drucken", "Beim Drucken ist ein Fehler aufgetreten", exc);
|
InteractionService.ShowException("Fehler beim Drucken", "Beim Drucken ist ein Fehler aufgetreten", exc);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,102 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Drawing.Imaging;
|
|
||||||
using System.Drawing.Printing;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Elwig.Helpers.Printing {
|
|
||||||
public class PdfPrintDocument : PrintDocument {
|
|
||||||
|
|
||||||
private readonly IntPtr _handle;
|
|
||||||
private readonly int _pageCount;
|
|
||||||
private readonly double _dpi;
|
|
||||||
|
|
||||||
private int _currentPage;
|
|
||||||
|
|
||||||
public PdfPrintDocument(string path, string? password = null, double dpi = 300.0) :
|
|
||||||
base() {
|
|
||||||
_handle = PdfiumNative.FPDF_LoadDocument(path, password);
|
|
||||||
_pageCount = PdfiumNative.FPDF_GetPageCount(_handle);
|
|
||||||
_dpi = dpi;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing) {
|
|
||||||
PdfiumNative.FPDF_CloseDocument(_handle);
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnBeginPrint(PrintEventArgs evt) {
|
|
||||||
_currentPage = (PrinterSettings.FromPage != 0) ? (PrinterSettings.FromPage - 1) : 0;
|
|
||||||
base.OnBeginPrint(evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnPrintPage(PrintPageEventArgs evt) {
|
|
||||||
if (_currentPage < _pageCount) {
|
|
||||||
IntPtr page = PdfiumNative.FPDF_LoadPage(_handle, _currentPage);
|
|
||||||
double width = PdfiumNative.FPDF_GetPageWidth(page);
|
|
||||||
double height = PdfiumNative.FPDF_GetPageHeight(page);
|
|
||||||
int pixelWidth = (int)(width / 72.0 * _dpi);
|
|
||||||
int pixelHeight = (int)(height / 72.0 * _dpi);
|
|
||||||
|
|
||||||
IntPtr bitmap = PdfiumNative.FPDFBitmap_Create(pixelWidth, pixelHeight, 1);
|
|
||||||
PdfiumNative.FPDF_RenderPageBitmap(bitmap, page, 0, 0, pixelWidth, pixelHeight, 0, 0);
|
|
||||||
|
|
||||||
IntPtr buffer = PdfiumNative.FPDFBitmap_GetBuffer(bitmap);
|
|
||||||
int stride = PdfiumNative.FPDFBitmap_GetStride(bitmap);
|
|
||||||
using (var bmp = new Bitmap(pixelWidth, pixelHeight, stride, PixelFormat.Format32bppArgb, buffer)) {
|
|
||||||
evt.Graphics?.DrawImage(bmp, evt.PageBounds);
|
|
||||||
}
|
|
||||||
_currentPage++;
|
|
||||||
|
|
||||||
PdfiumNative.FPDFBitmap_Destroy(bitmap);
|
|
||||||
PdfiumNative.FPDF_ClosePage(page);
|
|
||||||
}
|
|
||||||
evt.HasMorePages = _currentPage < ((PrinterSettings.ToPage == 0) ? _pageCount : Math.Min(PrinterSettings.ToPage, _pageCount));
|
|
||||||
base.OnPrintPage(evt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal partial class PdfiumNative {
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial void FPDF_InitLibrary();
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial void FPDF_DestroyLibrary();
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll", StringMarshalling = StringMarshalling.Utf8)]
|
|
||||||
public static partial IntPtr FPDF_LoadDocument(string filePath, string? password);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial void FPDF_CloseDocument(IntPtr document);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial int FPDF_GetPageCount(IntPtr document);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial IntPtr FPDF_LoadPage(IntPtr document, int pageIndex);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial void FPDF_ClosePage(IntPtr page);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial double FPDF_GetPageWidth(IntPtr page);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial double FPDF_GetPageHeight(IntPtr page);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial IntPtr FPDFBitmap_Create(int width, int height, int alpha);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial void FPDFBitmap_Destroy(IntPtr bitmap);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial IntPtr FPDFBitmap_GetBuffer(IntPtr bitmap);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial int FPDFBitmap_GetStride(IntPtr bitmap);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial void FPDF_RenderPageBitmap(IntPtr bitmap, IntPtr page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Printing;
|
||||||
|
|
||||||
|
namespace Elwig.Helpers.Printing {
|
||||||
|
public class PdfPrinter {
|
||||||
|
|
||||||
|
public string PrinterName { get; init; }
|
||||||
|
|
||||||
|
public PdfPrinter(string? printerName = null) {
|
||||||
|
PrinterName = printerName ?? GetDefaultPrinterName() ?? throw new InvalidOperationException("No default Windows printer is configured.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Print(string pdfPath, int copies = 1, bool doublePaged = false) {
|
||||||
|
if (!File.Exists(pdfPath)) throw new FileNotFoundException("PDF file not found.", pdfPath);
|
||||||
|
|
||||||
|
IntPtr document = PdfiumNative.FPDF_LoadDocument(pdfPath, null);
|
||||||
|
if (document == IntPtr.Zero) throw new InvalidOperationException("PDFium could not open the PDF.");
|
||||||
|
|
||||||
|
try {
|
||||||
|
int pageCount = PdfiumNative.FPDF_GetPageCount(document);
|
||||||
|
if (pageCount <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using var printer = new Win32Printer.Printer(PrinterName);
|
||||||
|
printer.TrySetDuplex(doublePaged ? Duplexing.TwoSidedLongEdge : Duplexing.OneSided);
|
||||||
|
for (int i = 0; i < copies; i++) {
|
||||||
|
printer.StartDocument(Path.GetFileName(pdfPath));
|
||||||
|
bool documentStarted = true;
|
||||||
|
try {
|
||||||
|
for (int j = 0; j < pageCount; j++) {
|
||||||
|
PrintPage(document, printer, j);
|
||||||
|
}
|
||||||
|
printer.EndDocument();
|
||||||
|
documentStarted = false;
|
||||||
|
} finally {
|
||||||
|
if (documentStarted) printer.AbortDocument();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
PdfiumNative.FPDF_CloseDocument(document);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PrintPage(IntPtr document, Win32Printer.Printer printer, int pageIndex) {
|
||||||
|
if (!PdfiumNative.FPDF_GetPageSizeByIndex(document, pageIndex, out double pageWidthPt, out double pageHeightPt)) {
|
||||||
|
throw new InvalidOperationException($"Unable to obtain PDF page {pageIndex} size.");
|
||||||
|
}
|
||||||
|
|
||||||
|
IntPtr page = PdfiumNative.FPDF_LoadPage(document, pageIndex);
|
||||||
|
if (page == IntPtr.Zero)
|
||||||
|
throw new InvalidOperationException($"Unable to load PDF page {pageIndex}.");
|
||||||
|
|
||||||
|
try {
|
||||||
|
int renderWidth = (int)Math.Round(pageWidthPt / 72.0 * printer.DpiX);
|
||||||
|
int renderHeight = (int)Math.Round(pageHeightPt / 72.0 * printer.DpiY);
|
||||||
|
int offsetX = (printer.PrintableWidth - renderWidth) / 2;
|
||||||
|
int offsetY = (printer.PrintableHeight - renderHeight) / 2;
|
||||||
|
|
||||||
|
printer.StartPage();
|
||||||
|
try {
|
||||||
|
PdfiumNative.FPDF_RenderPage(printer.Hdc, page, offsetX, offsetY, renderWidth, renderHeight, 0, PdfiumNative.FPDF_PRINTING | PdfiumNative.FPDF_ANNOT);
|
||||||
|
} finally {
|
||||||
|
printer.EndPage();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
PdfiumNative.FPDF_ClosePage(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? GetDefaultPrinterName() {
|
||||||
|
using var key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows NT\CurrentVersion\Windows");
|
||||||
|
string? printer = key?.GetValue("Device") as string;
|
||||||
|
if (string.IsNullOrWhiteSpace(printer))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Device has the form:
|
||||||
|
// Printer Name,winspool,PORT
|
||||||
|
int comma = printer.IndexOf(',');
|
||||||
|
return comma >= 0 ? printer[..comma] : printer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Elwig.Helpers.Printing {
|
||||||
|
internal partial class PdfiumNative {
|
||||||
|
|
||||||
|
public const int FPDF_ANNOT = 0x01;
|
||||||
|
public const int FPDF_PRINTING = 0x800;
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
public static partial void FPDF_InitLibrary();
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
public static partial void FPDF_DestroyLibrary();
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll", StringMarshalling = StringMarshalling.Utf8)]
|
||||||
|
public static partial IntPtr FPDF_LoadDocument(string filePath, string? password);
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
public static partial void FPDF_CloseDocument(IntPtr document);
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
public static partial int FPDF_GetPageCount(IntPtr document);
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
public static partial IntPtr FPDF_LoadPage(IntPtr document, int pageIndex);
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
public static partial void FPDF_ClosePage(IntPtr page);
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
public static partial bool FPDF_GetPageSizeByIndex(IntPtr document, int pageIndex, out double width, out double height);
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
public static partial void FPDF_RenderPage(IntPtr hdc, IntPtr page, int startX, int startY, int sizeX, int sizeY, int rotate, int flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Printing;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Elwig.Helpers.Printing {
|
||||||
|
public partial class Win32Printer {
|
||||||
|
|
||||||
|
private const int DM_OUT_BUFFER = 2;
|
||||||
|
|
||||||
|
private const int HORZRES = 8;
|
||||||
|
private const int VERTRES = 10;
|
||||||
|
private const int LOGPIXELSX = 88;
|
||||||
|
private const int LOGPIXELSY = 90;
|
||||||
|
private const int PHYSICALWIDTH = 110;
|
||||||
|
private const int PHYSICALHEIGHT = 111;
|
||||||
|
private const int PHYSICALOFFSETX = 112;
|
||||||
|
private const int PHYSICALOFFSETY = 113;
|
||||||
|
|
||||||
|
private const int DM_DUPLEX = 0x1000;
|
||||||
|
private const short DMDUP_SIMPLEX = 1;
|
||||||
|
private const short DMDUP_VERTICAL = 2;
|
||||||
|
private const short DMDUP_HORIZONTAL = 3;
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
private struct DOCINFO {
|
||||||
|
public int cbSize;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.LPWStr)]
|
||||||
|
public string? lpszDocName;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.LPWStr)]
|
||||||
|
public string? lpszOutput;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.LPWStr)]
|
||||||
|
public string? lpszDatatype;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
private struct DEVMODE {
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
||||||
|
public string dmDeviceName;
|
||||||
|
|
||||||
|
public short dmSpecVersion;
|
||||||
|
public short dmDriverVersion;
|
||||||
|
public short dmSize;
|
||||||
|
public short dmDriverExtra;
|
||||||
|
public int dmFields;
|
||||||
|
|
||||||
|
public short dmOrientation;
|
||||||
|
public short dmPaperSize;
|
||||||
|
public short dmPaperLength;
|
||||||
|
public short dmPaperWidth;
|
||||||
|
public short dmScale;
|
||||||
|
public short dmCopies;
|
||||||
|
public short dmDefaultSource;
|
||||||
|
public short dmPrintQuality;
|
||||||
|
public short dmColor;
|
||||||
|
public short dmDuplex;
|
||||||
|
public short dmYResolution;
|
||||||
|
public short dmTTOption;
|
||||||
|
public short dmCollate;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
||||||
|
public string dmFormName;
|
||||||
|
|
||||||
|
public short dmLogPixels;
|
||||||
|
public int dmBitsPerPel;
|
||||||
|
public int dmPelsWidth;
|
||||||
|
public int dmPelsHeight;
|
||||||
|
public int dmDisplayFlags;
|
||||||
|
public int dmDisplayFrequency;
|
||||||
|
public int dmICMMethod;
|
||||||
|
public int dmICMIntent;
|
||||||
|
public int dmMediaType;
|
||||||
|
public int dmDitherType;
|
||||||
|
public int dmReserved1;
|
||||||
|
public int dmReserved2;
|
||||||
|
public int dmPanningWidth;
|
||||||
|
public int dmPanningHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
private static extern bool OpenPrinter(string pPrinterName, out IntPtr phPrinter, IntPtr pDefault);
|
||||||
|
|
||||||
|
[DllImport("winspool.drv", SetLastError = true)]
|
||||||
|
private static extern bool ClosePrinter(IntPtr hPrinter);
|
||||||
|
|
||||||
|
[DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
private static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter, string pDeviceName, IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
private static extern IntPtr CreateDC(string? pDriver, string? pDevice, string? pOutput, IntPtr pInitData);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
|
private static extern bool DeleteDC(IntPtr hdc);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
|
private static extern int GetDeviceCaps(IntPtr hdc, int index);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
private static extern int StartDoc(IntPtr hdc, ref DOCINFO lpdi);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
|
private static extern int EndDoc(IntPtr hdc);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
|
private static extern int AbortDoc(IntPtr hdc);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
|
private static extern int StartPage(IntPtr hdc);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
|
private static extern int EndPage(IntPtr hdc);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
private static extern IntPtr GlobalAlloc(uint uFlags, UIntPtr dwBytes);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
private static extern IntPtr GlobalFree(IntPtr hMem);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
private static extern IntPtr GlobalLock(IntPtr hMem);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
private static extern bool GlobalUnlock(IntPtr hMem);
|
||||||
|
|
||||||
|
public class Printer : IDisposable {
|
||||||
|
private readonly string _printerName;
|
||||||
|
private readonly IntPtr _printerHandle;
|
||||||
|
private readonly IntPtr _devMode;
|
||||||
|
private readonly IntPtr _hdc;
|
||||||
|
|
||||||
|
public IntPtr Hdc => _hdc;
|
||||||
|
|
||||||
|
public int PrintableWidth => GetDeviceCaps(_hdc, HORZRES);
|
||||||
|
public int PrintableHeight => GetDeviceCaps(_hdc, VERTRES);
|
||||||
|
public int DpiX => GetDeviceCaps(_hdc, LOGPIXELSX);
|
||||||
|
public int DpiY => GetDeviceCaps(_hdc, LOGPIXELSY);
|
||||||
|
public int PhysicalWidth => GetDeviceCaps(_hdc, PHYSICALWIDTH);
|
||||||
|
public int PhysicalHeight => GetDeviceCaps(_hdc, PHYSICALHEIGHT);
|
||||||
|
public int PhysicalOffsetX => GetDeviceCaps(_hdc, PHYSICALOFFSETX);
|
||||||
|
public int PhysicalOffsetY => GetDeviceCaps(_hdc, PHYSICALOFFSETY);
|
||||||
|
|
||||||
|
public Printer(string printerName) {
|
||||||
|
_printerName = printerName;
|
||||||
|
|
||||||
|
if (!OpenPrinter(_printerName, out _printerHandle, IntPtr.Zero)) {
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error(), $"Unable to open printer '{printerName}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
_devMode = CreateDevMode();
|
||||||
|
_hdc = CreateDC(null, _printerName, null, _devMode);
|
||||||
|
if (_hdc == IntPtr.Zero)
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error(), $"Unable to create printer DC for '{_printerName}'.");
|
||||||
|
} catch {
|
||||||
|
if (_devMode != IntPtr.Zero) Marshal.FreeHGlobal(_devMode);
|
||||||
|
ClosePrinter(_printerHandle);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TrySetDuplex(Duplexing duplex) {
|
||||||
|
var devMode = Marshal.PtrToStructure<DEVMODE>(_devMode);
|
||||||
|
switch (duplex) {
|
||||||
|
case Duplexing.OneSided: devMode.dmDuplex = DMDUP_SIMPLEX; break;
|
||||||
|
case Duplexing.TwoSidedShortEdge: devMode.dmDuplex = DMDUP_HORIZONTAL; break;
|
||||||
|
case Duplexing.TwoSidedLongEdge: devMode.dmDuplex = DMDUP_VERTICAL; break;
|
||||||
|
}
|
||||||
|
if ((devMode.dmFields & DM_DUPLEX) != 0) {
|
||||||
|
Marshal.StructureToPtr(devMode, _devMode, false);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
devMode.dmFields |= DM_DUPLEX;
|
||||||
|
Marshal.StructureToPtr(devMode, _devMode, false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntPtr CreateDevMode() {
|
||||||
|
int size = DocumentProperties(IntPtr.Zero, _printerHandle, _printerName, IntPtr.Zero, IntPtr.Zero, 0);
|
||||||
|
if (size <= 0)
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "DocumentProperties failed.");
|
||||||
|
|
||||||
|
IntPtr devMode = Marshal.AllocHGlobal(size);
|
||||||
|
int result = DocumentProperties(IntPtr.Zero, _printerHandle, _printerName, devMode, IntPtr.Zero, DM_OUT_BUFFER);
|
||||||
|
if (result < 0) {
|
||||||
|
Marshal.FreeHGlobal(devMode);
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "Unable to obtain printer DEVMODE.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return devMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartDocument(string documentName) {
|
||||||
|
var docInfo = new DOCINFO {
|
||||||
|
cbSize = Marshal.SizeOf<DOCINFO>(),
|
||||||
|
lpszDocName = documentName,
|
||||||
|
lpszDatatype = null,
|
||||||
|
lpszOutput = null
|
||||||
|
};
|
||||||
|
|
||||||
|
if (StartDoc(_hdc, ref docInfo) <= 0)
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "StartDoc failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartPage() {
|
||||||
|
if (Win32Printer.StartPage(_hdc) <= 0)
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "StartPage failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EndPage() {
|
||||||
|
if (Win32Printer.EndPage(_hdc) <= 0)
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "EndPage failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EndDocument() {
|
||||||
|
if (EndDoc(_hdc) <= 0)
|
||||||
|
throw new Win32Exception( Marshal.GetLastWin32Error(), "EndDoc failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AbortDocument() {
|
||||||
|
AbortDoc(_hdc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
if (_hdc != IntPtr.Zero)
|
||||||
|
DeleteDC(_hdc);
|
||||||
|
|
||||||
|
if (_devMode != IntPtr.Zero)
|
||||||
|
Marshal.FreeHGlobal(_devMode);
|
||||||
|
|
||||||
|
if (_printerHandle != IntPtr.Zero)
|
||||||
|
ClosePrinter(_printerHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -516,7 +516,7 @@ namespace Elwig.Helpers {
|
|||||||
public static async Task<SmtpClient?> GetSmtpClient() {
|
public static async Task<SmtpClient?> GetSmtpClient() {
|
||||||
if (App.Config.Smtp == null)
|
if (App.Config.Smtp == null)
|
||||||
return null;
|
return null;
|
||||||
var (host, port, mode, username, password, _) = App.Config.Smtp.Value;
|
var (host, port, mode, username, password, _, _) = App.Config.Smtp.Value;
|
||||||
var client = new SmtpClient();
|
var client = new SmtpClient();
|
||||||
await client.ConnectAsync(host, port, mode == "starttls" ? SecureSocketOptions.StartTls : SecureSocketOptions.None);
|
await client.ConnectAsync(host, port, mode == "starttls" ? SecureSocketOptions.StartTls : SecureSocketOptions.None);
|
||||||
await client.AuthenticateAsync(username, password);
|
await client.AuthenticateAsync(username, password);
|
||||||
|
|||||||
@@ -958,6 +958,7 @@ namespace Elwig.Windows {
|
|||||||
m.EmailAddresses.OrderBy(a => a.Nr).Select(a => a.Address).ToArray(),
|
m.EmailAddresses.OrderBy(a => a.Nr).Select(a => a.Address).ToArray(),
|
||||||
subject, docs.Select(d => d.Title).ToArray()
|
subject, docs.Select(d => d.Title).ToArray()
|
||||||
)]);
|
)]);
|
||||||
|
await Task.Delay((int)(App.Config.SmtpWait * 1000));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ auto = true
|
|||||||
;username = ""
|
;username = ""
|
||||||
;password = ""
|
;password = ""
|
||||||
;from = mail@wg.at
|
;from = mail@wg.at
|
||||||
|
;wait = 0.5
|
||||||
|
|
||||||
;[scale.1]
|
;[scale.1]
|
||||||
;type = SysTec-IT
|
;type = SysTec-IT
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ About
|
|||||||
**Product:** Elwig
|
**Product:** Elwig
|
||||||
**Description:** Electronic Management for Vintners' Cooperatives
|
**Description:** Electronic Management for Vintners' Cooperatives
|
||||||
**Type:** ERP system
|
**Type:** ERP system
|
||||||
**Version:** 1.1.0.1 ([Changelog](./CHANGELOG.md))
|
**Version:** 1.1.0.2 ([Changelog](./CHANGELOG.md))
|
||||||
**License:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
|
**License:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
|
||||||
**Website:** https://elwig.at/
|
**Website:** https://elwig.at/
|
||||||
**Source code:** https://git.necronda.net/winzer/elwig
|
**Source code:** https://git.necronda.net/winzer/elwig
|
||||||
@@ -33,7 +33,7 @@ Packaging: [WiX Toolset](https://www.firegiant.com/wixtoolset/)
|
|||||||
**Produkt:** Elwig
|
**Produkt:** Elwig
|
||||||
**Beschreibung:** Elektronische Winzergenossenschaftsverwaltung
|
**Beschreibung:** Elektronische Winzergenossenschaftsverwaltung
|
||||||
**Typ:** Warenwirtschaftssystem (ERP-System)
|
**Typ:** Warenwirtschaftssystem (ERP-System)
|
||||||
**Version:** 1.1.0.1 ([Änderungsprotokoll](./CHANGELOG.md))
|
**Version:** 1.1.0.2 ([Änderungsprotokoll](./CHANGELOG.md))
|
||||||
**Lizenz:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
|
**Lizenz:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
|
||||||
**Website:** https://elwig.at/
|
**Website:** https://elwig.at/
|
||||||
**Quellcode:** https://git.necronda.net/winzer/elwig
|
**Quellcode:** https://git.necronda.net/winzer/elwig
|
||||||
|
|||||||
Reference in New Issue
Block a user