From 1151cbb42fec4b861d595f71b9e35f253ba1f27a Mon Sep 17 00:00:00 2001 From: zhuangkh Date: Tue, 28 Dec 2021 23:59:05 +0800 Subject: [PATCH] fix encoding filename --- PdfScribe/GhostScript64.cs | 10 +- PdfScribe/NativeMethods.cs | 19 +- PdfScribe/PdfScribe.csproj | 16 +- PdfScribe/Program.cs | 87 +++++++- PdfScribe/RegUtils.cs | 206 ++++++++++++++++++ PdfScribeCore/PdfScribeCore.csproj | 2 +- PdfScribeCore/PdfScribeInstaller.cs | 2 +- PdfScribeInstall/PdfScribeInstall.wixproj | 2 +- PdfScribeInstall/Product.wxs | 4 +- .../PdfScribeInstallCustomAction.csproj | 2 +- 10 files changed, 322 insertions(+), 28 deletions(-) create mode 100644 PdfScribe/RegUtils.cs diff --git a/PdfScribe/GhostScript64.cs b/PdfScribe/GhostScript64.cs index b9eba8e..432cbbf 100644 --- a/PdfScribe/GhostScript64.cs +++ b/PdfScribe/GhostScript64.cs @@ -18,16 +18,20 @@ namespace PdfScribe /// /// Calls the Ghostscript API with a collection of arguments to be passed to it /// - public static void CallAPI(string[] args) + public static void CallAPI(string[] argv) { // Get a pointer to an instance of the Ghostscript API and run the API with the current arguments IntPtr gsInstancePtr; lock (resourceLock) { NativeMethods.CreateAPIInstance(out gsInstancePtr, IntPtr.Zero); + IntPtr[] utf8argv = new IntPtr[argv.Length]; + for (int i = 0; i < utf8argv.Length; i++) + utf8argv[i] = NativeMethods.NativeUtf8FromString(argv[i]); try { - int result = NativeMethods.InitAPI(gsInstancePtr, args.Length, args); + NativeMethods.SetEncoding(gsInstancePtr, NativeMethods.GS_ARG_ENCODING_UTF8); + int result = NativeMethods.InitAPI(gsInstancePtr, argv.Length, utf8argv); if (result < 0) { @@ -36,6 +40,8 @@ namespace PdfScribe } finally { + for (int i = 0; i < utf8argv.Length; i++) + Marshal.FreeHGlobal(utf8argv[i]); Cleanup(gsInstancePtr); } } diff --git a/PdfScribe/NativeMethods.cs b/PdfScribe/NativeMethods.cs index 17dd90b..019e4ce 100644 --- a/PdfScribe/NativeMethods.cs +++ b/PdfScribe/NativeMethods.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel; using System.Runtime.InteropServices; +using System.Text; namespace PdfScribe { @@ -13,12 +14,18 @@ namespace PdfScribe https://github.com/mephraim/ghostscriptsharp */ + public const int GS_ARG_ENCODING_LOCAL = 0; + public const int GS_ARG_ENCODING_UTF8 = 1; + #region Hooks into Ghostscript DLL [DllImport("gsdll64.dll", EntryPoint = "gsapi_new_instance")] internal static extern int CreateAPIInstance(out IntPtr pinstance, IntPtr caller_handle); [DllImport("gsdll64.dll", EntryPoint = "gsapi_init_with_args")] - internal static extern int InitAPI(IntPtr instance, int argc, string[] argv); + internal static extern int InitAPI(IntPtr instance, int argc, IntPtr[] argv); + + [DllImport("gsdll64.dll", EntryPoint = "gsapi_set_arg_encoding")] + internal static extern int SetEncoding(IntPtr inst, int encoding); [DllImport("gsdll64.dll", EntryPoint = "gsapi_exit")] internal static extern int ExitAPI(IntPtr instance); @@ -29,5 +36,15 @@ namespace PdfScribe [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool SetDllDirectory(string lpPathName); + + public static IntPtr NativeUtf8FromString(string managedString) + { + int len = Encoding.UTF8.GetByteCount(managedString); + byte[] buffer = new byte[len + 1]; // null-terminator allocated + Encoding.UTF8.GetBytes(managedString, 0, managedString.Length, buffer, 0); + IntPtr nativeUtf8 = Marshal.AllocHGlobal(buffer.Length); + Marshal.Copy(buffer, 0, nativeUtf8, buffer.Length); + return nativeUtf8; + } } } diff --git a/PdfScribe/PdfScribe.csproj b/PdfScribe/PdfScribe.csproj index 0bef80a..0a8bf89 100644 --- a/PdfScribe/PdfScribe.csproj +++ b/PdfScribe/PdfScribe.csproj @@ -10,7 +10,7 @@ Properties PdfScribe PdfScribe - v4.6.1 + v4.5.2 512 @@ -87,6 +87,7 @@ + @@ -114,6 +115,7 @@ Settings.settings True + Form @@ -150,11 +152,11 @@ - \ No newline at end of file diff --git a/PdfScribe/Program.cs b/PdfScribe/Program.cs index 9b060b8..d1f150e 100644 --- a/PdfScribe/Program.cs +++ b/PdfScribe/Program.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; +using System.Text; using System.Text.RegularExpressions; using System.Windows.Forms; @@ -42,6 +43,7 @@ namespace PdfScribe [STAThread] static void Main(string[] args) { + //Debugger.Launch(); // Install the global exception handler AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(Application_UnhandledException); @@ -66,8 +68,10 @@ namespace PdfScribe File.Delete(outputFilename); // Only set absolute minimum parameters, let the postscript input // dictate as much as possible - String[] ghostScriptArguments = { "-dBATCH", "-dNOPAUSE", "-dSAFER", "-sDEVICE=pdfwrite", - String.Format("-sOutputFile={0}", outputFilename), standardInputFilename, + outputFilename = outputFilename.Replace("\\\\", "/"); + standardInputFilename = standardInputFilename.Replace("\\", "/"); + string[] ghostScriptArguments = {"gs", "-dBATCH", "-dNOPAUSE", "-dSAFER", "-sDEVICE=pdfwrite", + string.Format("-sOutputFile={0}", outputFilename), standardInputFilename, "-c", @"[/Creator(PdfScribe 1.1.0 (PSCRIPT5)) /DOCINFO pdfmark", "-f"}; GhostScript64.CallAPI(ghostScriptArguments); @@ -229,23 +233,82 @@ namespace PdfScribe } - private static void GetPathFormTitle(ref String outputFilename, - String standardInputFilename) + private static void GetPathFormTitle(ref String outputFilename, string standardInputFilename) { - const String titlePrefix = "%%Title: "; - using (var fs = new FileStream(standardInputFilename, FileMode.Open, FileAccess.Read)) - using (var sr = new StreamReader(fs)) + string path = RegUtils.GetRegistryValue("Software\\PDF Scribe uBIM_Customization", "OutputFile"); + if (path != "0000") { - string line = String.Empty; - while ((line = sr.ReadLine()) != null) + var dir = path.Substring(0, path.LastIndexOf("\\") + 1); + var file = path.Substring(path.LastIndexOf("\\") + 1); + file = MakeValidFileName(file); + outputFilename = dir + file; + RegUtils.SetRegistryKey("HKEY_CURRENT_USER", "Software\\PDF Scribe uBIM_Customization", "OutputFile", "0000"); + } + + if (string.IsNullOrEmpty(outputFilename)) + { + const String titlePrefix = "%%Title: "; + using (var fs = new FileStream(standardInputFilename, FileMode.Open, FileAccess.Read)) + using (var sr = new StreamReader(fs)) { - if (line.StartsWith(titlePrefix)) + string line = String.Empty; + while ((line = sr.ReadLine()) != null) { - outputFilename = line.Substring(titlePrefix.Length); - break; + if (line.StartsWith(titlePrefix)) + { + var file = line.Substring(titlePrefix.Length); + if (file.StartsWith("<")) + { + file = file.Trim('<', '>'); + var length = file.Length; + var count = file.Length / 2; + for (int i = 1; i <= count; i++) + { + file = file.Insert(length - i * 2, "%"); + } + file = System.Web.HttpUtility.UrlDecode(file, Encoding.GetEncoding("gb2312")); + } + file = file.Trim('(', ')'); + if (file.Contains(@"\\")) + { + file = file.Replace(@"\\", @"//"); + var oldStr = Regex.Matches(file, @"\\[0-9]{1,3}"); + if (oldStr.Count > 0) + { + foreach (Match str in oldStr) + { + var num = str.Value.Trim('\\'); + var hex = $"%{Convert.ToInt32(num, 8).ToString("X")}"; + file = file.Replace(str.Value, hex); + } + file = System.Web.HttpUtility.UrlDecode(file, Encoding.GetEncoding("gb2312")); + } + file = file.Replace(@"//", @"\\"); + } + if (!string.IsNullOrEmpty(Path.GetExtension(file))) + { + var dir = file.Substring(0, file.LastIndexOf("\\") + 1); + file = file.Substring(file.LastIndexOf("\\") + 1); + file = MakeValidFileName(file); + outputFilename = dir + file; + } + break; + } } } } + + } + + private static string MakeValidFileName(string outputFilename, char replaceChar = '_') + { + var invalidChars = System.IO.Path.GetInvalidFileNameChars(); + foreach (var invalidChar in invalidChars) + { + outputFilename = outputFilename.Replace(invalidChar, replaceChar); + } + + return outputFilename; } private static String GetOutputFilename() diff --git a/PdfScribe/RegUtils.cs b/PdfScribe/RegUtils.cs new file mode 100644 index 0000000..63b0d46 --- /dev/null +++ b/PdfScribe/RegUtils.cs @@ -0,0 +1,206 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; +using Microsoft.Win32; + +namespace PdfScribe +{ + public static class RegUtils + { + static readonly IntPtr HKEY_CLASSES_ROOT = new IntPtr(unchecked((int)0x80000000)); + static readonly IntPtr HKEY_CURRENT_USER = new IntPtr(unchecked((int)0x80000001)); + static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(unchecked((int)0x80000002)); + static readonly IntPtr HKEY_USERS = new IntPtr(unchecked((int)0x80000003)); + static readonly IntPtr HKEY_PERFORMANCE_DATA = new IntPtr(unchecked((int)0x80000004)); + static readonly IntPtr HKEY_CURRENT_CONFIG = new IntPtr(unchecked((int)0x80000005)); + static readonly IntPtr HKEY_DYN_DATA = new IntPtr(unchecked((int)0x80000006)); + + // 获取操作Key值句柄 + [DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern int RegOpenKeyEx(IntPtr hKey, string lpSubKey, uint ulOptions, int samDesired, out IntPtr phkResult); + + //创建或打开Key值 + [DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern int RegCreateKeyEx(IntPtr hKey, string lpSubKey, int reserved, string type, int dwOptions, int REGSAM, IntPtr lpSecurityAttributes, out IntPtr phkResult, + out int lpdwDisposition); + + //关闭注册表转向(禁用特定项的注册表反射) + [DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern int RegDisableReflectionKey(IntPtr hKey); + + //使能注册表转向(开启特定项的注册表反射) + [DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern int RegEnableReflectionKey(IntPtr hKey); + + //获取Key值(即:Key值句柄所标志的Key对象的值) + [DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern int RegQueryValueEx(IntPtr hKey, string lpValueName, int lpReserved, out uint lpType, StringBuilder lpData, ref uint lpcbData); + + //设置Key值 + [DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern int RegSetValueEx(IntPtr hKey, string lpValueName, uint unReserved, uint unType, byte[] lpData, uint dataCount); + + //关闭Key值 + [DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern int RegCloseKey(IntPtr hKey); + + public static IntPtr TransferKeyName(string keyName) + { + IntPtr ret = IntPtr.Zero; + switch (keyName) + { + case "HKEY_CLASSES_ROOT": + ret = HKEY_CLASSES_ROOT; + break; + case "HKEY_CURRENT_USER": + ret = HKEY_CURRENT_USER; + break; + case "HKEY_LOCAL_MACHINE": + ret = HKEY_LOCAL_MACHINE; + break; + case "HKEY_USERS": + ret = HKEY_USERS; + break; + case "HKEY_PERFORMANCE_DATA": + ret = HKEY_PERFORMANCE_DATA; + break; + case "HKEY_CURRENT_CONFIG": + ret = HKEY_CURRENT_CONFIG; + break; + case "HKEY_DYN_DATA": + ret = HKEY_DYN_DATA; + break; + default: + ret = HKEY_LOCAL_MACHINE; + break; + } + return ret; + } + + /// + /// 设置64位注册表 + /// + /// + /// + /// + /// + /// + public static int Set64BitRegistryKey(string key, string subKey, string name, string value) + { + int STANDARD_RIGHTS_ALL = 0x001F0000; + int KEY_QUERY_VALUE = 0x0001; + int KEY_SET_VALUE = 0x0002; + int KEY_CREATE_SUB_KEY = 0x0004; + int KEY_ENUMERATE_SUB_KEYS = 0x0008; + int KEY_NOTIFY = 0x0010; + int KEY_CREATE_LINK = 0x0020; + int SYNCHRONIZE = 0x00100000; + int KEY_WOW64_64KEY = 0x0100; + int REG_OPTION_NON_VOLATILE = 0x00000000; + int KEY_ALL_ACCESS = (STANDARD_RIGHTS_ALL | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS + | KEY_NOTIFY | KEY_CREATE_LINK) & ~SYNCHRONIZE; + + int ret = 0; + try + { + //将Windows注册表主键名转化成为不带正负号的整形句柄(与平台是32或者64位有关) + IntPtr hKey = TransferKeyName(key); + + //声明将要获取Key值的句柄 + IntPtr pHKey = IntPtr.Zero; + + //获得操作Key值的句柄 + int lpdwDisposition = 0; + ret = RegCreateKeyEx(hKey, subKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | KEY_WOW64_64KEY, IntPtr.Zero, out pHKey, out lpdwDisposition); + if (ret != 0) + { + //Log2.Log(string.Format("Unable to create key {0} - {1}: {2}!", key, subKey, ret)); + return ret; + } + + //关闭注册表转向(禁止特定项的注册表反射) + RegDisableReflectionKey(pHKey); + + //设置访问的Key值 + uint REG_SZ = 1; + byte[] data = Encoding.Unicode.GetBytes(value); + + RegSetValueEx(pHKey, name, 0, REG_SZ, data, (uint)data.Length); + + //打开注册表转向(开启特定项的注册表反射) + RegEnableReflectionKey(pHKey); + + RegCloseKey(pHKey); + } + catch (Exception ex) + { + //Log2.Log(ex.ToString()); + return -1; + } + + return ret; + } + + public static void SetRegistryKey(string key, string subKey, string name, string value) + { + //Log2.Log("SetRegistryKey start."); + if (IntPtr.Size == 8) + { + // 写SOFTWARE\Huawei\VirtualDesktopAgent,需要关闭注册表重定向,再写64位路径的注册表 + int ret = Set64BitRegistryKey(key, subKey, name, value); + if (ret != 0) + { + //Log2.Log(string.Format("Failed to write Reg {0}\\{1}\\{2},return {3}", key, subKey, name, ret)); + } + } + + try + { + Registry.SetValue(key + "\\" + subKey, name, value); + } + catch (Exception ex) + { + MessageBox.Show(ex.ToString()); + //Log2.Log(ex.ToString()); + } + + //Log2.Log("SetRegistryKey exit."); + } + + public static string GetRegistryValue(string path, string key) + { + RegistryKey regkey = null; + try + { + regkey = Registry.CurrentUser.OpenSubKey(path); + if (regkey == null) + { + //Log2.Log("Cannot find Registry path:" + path); + return null; + } + + object val = regkey.GetValue(key); + if (val == null) + { + //Log2.Log("Cannot find Registry key:" + key); + return null; + } + + return val.ToString(); + } + catch (Exception ex) + { + //Log2.Log(ex.ToString()); + return null; + } + finally + { + if (regkey != null) + { + regkey.Close(); + } + } + } + } +} diff --git a/PdfScribeCore/PdfScribeCore.csproj b/PdfScribeCore/PdfScribeCore.csproj index 884d20c..028bc1d 100644 --- a/PdfScribeCore/PdfScribeCore.csproj +++ b/PdfScribeCore/PdfScribeCore.csproj @@ -10,7 +10,7 @@ Properties PdfScribeCore PdfScribeCore - v4.6.1 + v4.5.2 512 diff --git a/PdfScribeCore/PdfScribeInstaller.cs b/PdfScribeCore/PdfScribeInstaller.cs index 2256694..b26e316 100644 --- a/PdfScribeCore/PdfScribeInstaller.cs +++ b/PdfScribeCore/PdfScribeInstaller.cs @@ -38,7 +38,7 @@ namespace PdfScribeCore private readonly String logEventSourceNameDefault = "PdfScribeCore"; const string ENVIRONMENT_64 = "Windows x64"; - const string PRINTERNAME = "PDF Scribe"; + const string PRINTERNAME = "PDF Scribe uBIM_Customization"; const string DRIVERNAME = "PDF Scribe Virtual Printer"; const string HARDWAREID = "PDFScribe_Driver0101"; const string PORTMONITOR = "PDFSCRIBE"; diff --git a/PdfScribeInstall/PdfScribeInstall.wixproj b/PdfScribeInstall/PdfScribeInstall.wixproj index 64e1dfc..ec42d74 100644 --- a/PdfScribeInstall/PdfScribeInstall.wixproj +++ b/PdfScribeInstall/PdfScribeInstall.wixproj @@ -6,7 +6,7 @@ 3.7 {3c255536-a7f1-4913-9c7f-966dffee01bc} 2.0 - PdfScribeInstall_1.1 + PdfScribeInstall_1.1.2.413 Package $(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets diff --git a/PdfScribeInstall/Product.wxs b/PdfScribeInstall/Product.wxs index 9fb32c5..ac9790f 100644 --- a/PdfScribeInstall/Product.wxs +++ b/PdfScribeInstall/Product.wxs @@ -1,11 +1,11 @@ - + Properties PdfScribeInstallCustomAction PdfScribeInstallCustomAction - v4.6.1 + v4.5.2 512 $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.CA.targets