This commit is contained in:
Bruce
2026-01-11 11:40:21 +08:00
parent 3ab9761705
commit 2e6214a35a
69 changed files with 6519 additions and 13232 deletions

View File

@@ -44,6 +44,22 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "priformatcli", "priformatcl
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Update", "Update\Update.csproj", "{512BF866-1AA0-4169-A7D6-D2776B5D731E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrivateInit", "PrivateInit\PrivateInit.csproj", "{8E708D9A-6325-4AA9-B5A5-D1B5ECA8EEF7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppxPackage", "AppxPackage\AppxPackage.csproj", "{BD681A4F-EB60-4BB8-90B5-65968FC7DA59}"
ProjectSection(ProjectDependencies) = postProject
{8EAC0230-4990-4E41-8E0F-D641D1561396} = {8EAC0230-4990-4E41-8E0F-D641D1561396}
{33D91B58-1981-4A3C-B4D1-86EE406CDE12} = {33D91B58-1981-4A3C-B4D1-86EE406CDE12}
{A7753282-AA16-43D9-8ACA-7065239DD702} = {A7753282-AA16-43D9-8ACA-7065239DD702}
{EF4012D4-EF08-499C-B803-177739350B2D} = {EF4012D4-EF08-499C-B803-177739350B2D}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataUtils", "DataUtils\DataUtils.csproj", "{FFD3FD52-37A8-4F43-883C-DE8D996CB0E0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bridge", "Bridge\Bridge.csproj", "{3C2F5446-33F0-41D5-813A-64A94AA474AF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WAShell", "WAShell\WAShell.csproj", "{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -174,6 +190,66 @@ Global
{512BF866-1AA0-4169-A7D6-D2776B5D731E}.Release|x64.Build.0 = Release|Any CPU
{512BF866-1AA0-4169-A7D6-D2776B5D731E}.Release|x86.ActiveCfg = Release|Any CPU
{512BF866-1AA0-4169-A7D6-D2776B5D731E}.Release|x86.Build.0 = Release|Any CPU
{8E708D9A-6325-4AA9-B5A5-D1B5ECA8EEF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8E708D9A-6325-4AA9-B5A5-D1B5ECA8EEF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E708D9A-6325-4AA9-B5A5-D1B5ECA8EEF7}.Debug|x64.ActiveCfg = Debug|Any CPU
{8E708D9A-6325-4AA9-B5A5-D1B5ECA8EEF7}.Debug|x64.Build.0 = Debug|Any CPU
{8E708D9A-6325-4AA9-B5A5-D1B5ECA8EEF7}.Debug|x86.ActiveCfg = Debug|Any CPU
{8E708D9A-6325-4AA9-B5A5-D1B5ECA8EEF7}.Debug|x86.Build.0 = Debug|Any CPU
{8E708D9A-6325-4AA9-B5A5-D1B5ECA8EEF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E708D9A-6325-4AA9-B5A5-D1B5ECA8EEF7}.Release|Any CPU.Build.0 = Release|Any CPU
{8E708D9A-6325-4AA9-B5A5-D1B5ECA8EEF7}.Release|x64.ActiveCfg = Release|Any CPU
{8E708D9A-6325-4AA9-B5A5-D1B5ECA8EEF7}.Release|x64.Build.0 = Release|Any CPU
{8E708D9A-6325-4AA9-B5A5-D1B5ECA8EEF7}.Release|x86.ActiveCfg = Release|Any CPU
{8E708D9A-6325-4AA9-B5A5-D1B5ECA8EEF7}.Release|x86.Build.0 = Release|Any CPU
{BD681A4F-EB60-4BB8-90B5-65968FC7DA59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD681A4F-EB60-4BB8-90B5-65968FC7DA59}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD681A4F-EB60-4BB8-90B5-65968FC7DA59}.Debug|x64.ActiveCfg = Debug|Any CPU
{BD681A4F-EB60-4BB8-90B5-65968FC7DA59}.Debug|x64.Build.0 = Debug|Any CPU
{BD681A4F-EB60-4BB8-90B5-65968FC7DA59}.Debug|x86.ActiveCfg = Debug|x86
{BD681A4F-EB60-4BB8-90B5-65968FC7DA59}.Debug|x86.Build.0 = Debug|x86
{BD681A4F-EB60-4BB8-90B5-65968FC7DA59}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD681A4F-EB60-4BB8-90B5-65968FC7DA59}.Release|Any CPU.Build.0 = Release|Any CPU
{BD681A4F-EB60-4BB8-90B5-65968FC7DA59}.Release|x64.ActiveCfg = Release|Any CPU
{BD681A4F-EB60-4BB8-90B5-65968FC7DA59}.Release|x64.Build.0 = Release|Any CPU
{BD681A4F-EB60-4BB8-90B5-65968FC7DA59}.Release|x86.ActiveCfg = Release|x86
{BD681A4F-EB60-4BB8-90B5-65968FC7DA59}.Release|x86.Build.0 = Release|x86
{FFD3FD52-37A8-4F43-883C-DE8D996CB0E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FFD3FD52-37A8-4F43-883C-DE8D996CB0E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FFD3FD52-37A8-4F43-883C-DE8D996CB0E0}.Debug|x64.ActiveCfg = Debug|Any CPU
{FFD3FD52-37A8-4F43-883C-DE8D996CB0E0}.Debug|x64.Build.0 = Debug|Any CPU
{FFD3FD52-37A8-4F43-883C-DE8D996CB0E0}.Debug|x86.ActiveCfg = Debug|Any CPU
{FFD3FD52-37A8-4F43-883C-DE8D996CB0E0}.Debug|x86.Build.0 = Debug|Any CPU
{FFD3FD52-37A8-4F43-883C-DE8D996CB0E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FFD3FD52-37A8-4F43-883C-DE8D996CB0E0}.Release|Any CPU.Build.0 = Release|Any CPU
{FFD3FD52-37A8-4F43-883C-DE8D996CB0E0}.Release|x64.ActiveCfg = Release|Any CPU
{FFD3FD52-37A8-4F43-883C-DE8D996CB0E0}.Release|x64.Build.0 = Release|Any CPU
{FFD3FD52-37A8-4F43-883C-DE8D996CB0E0}.Release|x86.ActiveCfg = Release|Any CPU
{FFD3FD52-37A8-4F43-883C-DE8D996CB0E0}.Release|x86.Build.0 = Release|Any CPU
{3C2F5446-33F0-41D5-813A-64A94AA474AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3C2F5446-33F0-41D5-813A-64A94AA474AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C2F5446-33F0-41D5-813A-64A94AA474AF}.Debug|x64.ActiveCfg = Debug|Any CPU
{3C2F5446-33F0-41D5-813A-64A94AA474AF}.Debug|x64.Build.0 = Debug|Any CPU
{3C2F5446-33F0-41D5-813A-64A94AA474AF}.Debug|x86.ActiveCfg = Debug|Any CPU
{3C2F5446-33F0-41D5-813A-64A94AA474AF}.Debug|x86.Build.0 = Debug|Any CPU
{3C2F5446-33F0-41D5-813A-64A94AA474AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C2F5446-33F0-41D5-813A-64A94AA474AF}.Release|Any CPU.Build.0 = Release|Any CPU
{3C2F5446-33F0-41D5-813A-64A94AA474AF}.Release|x64.ActiveCfg = Release|Any CPU
{3C2F5446-33F0-41D5-813A-64A94AA474AF}.Release|x64.Build.0 = Release|Any CPU
{3C2F5446-33F0-41D5-813A-64A94AA474AF}.Release|x86.ActiveCfg = Release|Any CPU
{3C2F5446-33F0-41D5-813A-64A94AA474AF}.Release|x86.Build.0 = Release|Any CPU
{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}.Debug|x64.ActiveCfg = Debug|Any CPU
{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}.Debug|x64.Build.0 = Debug|Any CPU
{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}.Debug|x86.ActiveCfg = Debug|Any CPU
{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}.Debug|x86.Build.0 = Debug|Any CPU
{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}.Release|Any CPU.Build.0 = Release|Any CPU
{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}.Release|x64.ActiveCfg = Release|Any CPU
{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}.Release|x64.Build.0 = Release|Any CPU
{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}.Release|x86.ActiveCfg = Release|Any CPU
{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" 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>{BD681A4F-EB60-4BB8-90B5-65968FC7DA59}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>AppxPackage</RootNamespace>
<AssemblyName>AppxPackage</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>..\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<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.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="PkgMgrNative.cs" />
<Compile Include="PkgReadNative.cs" />
<Compile Include="PriFileNative.cs" />
<Compile Include="PriReader.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

189
AppxPackage/PkgMgrNative.cs Normal file
View File

@@ -0,0 +1,189 @@
// PackageManageHelper.cs
// P/Invoke wrapper for pkgmgr.dll (x86).
//
// 说明:此文件兼容 .NET Framework 4。
// - 将项目 Platform target 设置为 x86。
// - pkgmgr.dll 提供 PackageManagerFreeString 来释放它返回的字符串,请务必使用它释放由 pkgmgr 返回的 LPWSTR。
using System;
using System.Runtime.InteropServices;
namespace NativeWrappers
{
using DWORD = System.UInt32;
using HRESULT = System.Int32;
using BOOL = System.Int32;
using UINT64 = System.UInt64;
public static class PackageManageHelper
{
private const string DllName = "pkgmgr.dll";
private const CallingConvention CallConv = CallingConvention.Cdecl;
[UnmanagedFunctionPointer (CallConv)]
public delegate void PKGMRR_PROGRESSCALLBACK (DWORD dwProgress, IntPtr pCustom);
[UnmanagedFunctionPointer (CallConv)]
public delegate void PKGMGR_FINDENUMCALLBACK (IntPtr pNowItem, IntPtr pCustom);
[StructLayout (LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct REGISTER_PACKAGE_DEFENDENCIES
{
public DWORD dwSize;
public IntPtr alpDepUris; // tail array
}
[StructLayout (LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct FIND_PACKAGE_ID
{
public UINT64 qwVersion;
public ushort wProcessArchitecture;
[MarshalAs (UnmanagedType.ByValArray, SizeConst = 3)]
public ushort [] wPadding;
public IntPtr lpName;
public IntPtr lpFullName;
public IntPtr lpFamilyName;
public IntPtr lpPublisher;
public IntPtr lpPublisherId;
public IntPtr lpResourceId;
}
[StructLayout (LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct FIND_PACKAGE_PROPERTIES
{
public IntPtr lpDisplayName;
public IntPtr lpDescription;
public IntPtr lpPublisher;
public IntPtr lpLogoUri;
[MarshalAs (UnmanagedType.Bool)]
public bool bIsFramework;
[MarshalAs (UnmanagedType.Bool)]
public bool bIsResourcePackage;
[MarshalAs (UnmanagedType.Bool)]
public bool bIsBundle;
[MarshalAs (UnmanagedType.Bool)]
public bool bIsDevelopmentMode;
}
[StructLayout (LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct FIND_PACKAGE_INFO
{
public FIND_PACKAGE_ID piIdentity;
public FIND_PACKAGE_PROPERTIES piProperties;
public IntPtr lpInstallLocation;
public IntPtr lpUsers;
public IntPtr lpSIDs;
public DWORD dwDependencesSize;
public DWORD dwPadding;
public UINT64 ullBuffer;
}
// ========== Functions ==========
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT AddAppxPackageFromPath (string lpPkgPath, IntPtr alpDepUrlList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT AddAppxPackageFromURI (string lpFileUri, IntPtr alpDepFullNameList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT GetAppxPackages (PKGMGR_FINDENUMCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT RemoveAppxPackage (string lpPkgFullName, PKGMRR_PROGRESSCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT CleanupAppxPackage (string lpPkgName, string lpUserSID, PKGMRR_PROGRESSCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT RegisterAppxPackageByPath (string lpManifestPath, IntPtr alpDependencyUriList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT RegisterAppxPackageByUri (string lpManifestUri, IntPtr alpDependencyUriList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT RegisterAppxPackageByFullName (string lpPackageFullName, IntPtr alpDepFullNameList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT SetAppxPackageStatus (string lpPackageFullName, DWORD dwStatus, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT StageAppxPackageFromURI (string lpFileUri, IntPtr alpDepUriList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT StageAppxPackageFromPath (string lpFileUri, IntPtr alpDepUriList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT StageAppxUserData (string lpPackageFullName, PKGMRR_PROGRESSCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT UpdateAppxPackageFromPath (string lpPkgPath, IntPtr alpDepUrlList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT UpdateAppxPackageFromURI (string lpFileUri, IntPtr alpDepFullNameList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT FindAppxPackage (string lpPackageFullName, PKGMGR_FINDENUMCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetPackageManagerLastErrorCode ();
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetPackageManagerLastErrorDetailMessage ();
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT ActivateAppxApplication (string lpAppUserId, out DWORD pdwProcessId);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT FindAppxPackagesByIdentity (string lpPkgName, string lpPkgPublisher, PKGMGR_FINDENUMCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT FindAppxPackagesByFamilyName (string lpPkgFamilyName, PKGMGR_FINDENUMCALLBACK pfCallback, IntPtr pCustom, out IntPtr pErrorCode, out IntPtr pDetailMsg);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern void PackageManagerFreeString (IntPtr lpString);
// ========== 托管辅助 ==========
public static string PtrToStringAndFree (IntPtr nativePtr)
{
if (nativePtr == IntPtr.Zero) return null;
string s = Marshal.PtrToStringUni (nativePtr);
try
{
PackageManagerFreeString (nativePtr);
}
catch
{
}
return s;
}
public static FIND_PACKAGE_INFO PtrToFindPackageInfo (IntPtr pInfo)
{
if (pInfo == IntPtr.Zero) return default (FIND_PACKAGE_INFO);
object boxed = Marshal.PtrToStructure (pInfo, typeof (FIND_PACKAGE_INFO));
return (FIND_PACKAGE_INFO)boxed;
}
public static string GetDisplayNameFromFindPackageInfo (IntPtr pInfo)
{
FIND_PACKAGE_INFO info = PtrToFindPackageInfo (pInfo);
if (info.piProperties.lpDisplayName == IntPtr.Zero) return null;
return Marshal.PtrToStringUni (info.piProperties.lpDisplayName);
}
public static string [] ReadRegisterPackageDependencies (IntPtr pReg)
{
if (pReg == IntPtr.Zero) return new string [0];
uint size = (uint)Marshal.ReadInt32 (pReg);
if (size == 0) return new string [0];
string [] result = new string [size];
int offset = Marshal.SizeOf (typeof (uint));
for (int i = 0; i < size; i++)
{
IntPtr pStr = Marshal.ReadIntPtr (pReg, offset + i * IntPtr.Size);
result [i] = pStr == IntPtr.Zero ? null : Marshal.PtrToStringUni (pStr);
}
return result;
}
}
}

View File

@@ -0,0 +1,301 @@
// PackageReadHelper.cs
// P/Invoke wrapper for pkgread.dll (x86).
//
// 说明:此文件兼容 .NET Framework 4。
// - 将项目 Platform target 设置为 x86因为你只编译了 x86 的本机 DLL
// - pkgread.dll 返回了很多需由调用者释放的 LPWSTR 指针header 中未提供通用释放函数,示例中调用 CRT 的 freemsvcrt.dll来释放。
// 如果能修改 pkgread.dll 并导出专用释放函数(如 PackageReadFreeString那是更安全的做法。
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace NativeWrappers
{
// 本机类型别名(便于阅读)
using BOOL = System.Int32;
using WORD = System.UInt16;
using DWORD = System.UInt32;
using UINT16 = System.UInt16;
using UINT64 = System.UInt64;
using HRESULT = System.Int32;
using ULONG = System.UInt32;
public static class PackageReadHelper
{
private const string DllName = "pkgread.dll";
private const CallingConvention CallConv = CallingConvention.Cdecl;
[StructLayout (LayoutKind.Sequential)]
public struct VERSION
{
public ushort major;
public ushort minor;
public ushort build;
public ushort revision;
}
[StructLayout (LayoutKind.Sequential)]
public struct PAIR_PVOID
{
public IntPtr lpKey;
public IntPtr lpValue;
}
[StructLayout (LayoutKind.Sequential)]
public struct DEPENDENCY_INFO
{
public VERSION verMin;
public IntPtr lpName; // LPWSTR
public IntPtr lpPublisher; // LPWSTR
}
[StructLayout (LayoutKind.Sequential)]
public struct LIST_DEPINFO
{
public DWORD dwSize;
public IntPtr aDepInfo; // tail array
}
// Delegates
[UnmanagedFunctionPointer (CallConv)]
public delegate void PKGMRR_PROGRESSCALLBACK (DWORD dwProgress, IntPtr pCustom);
// ========== P/Invoke ==========
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr CreatePackageReader ();
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
[return: MarshalAs (UnmanagedType.Bool)]
public static extern bool LoadPackageFromFile (IntPtr hReader, string lpFilePath);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern void DestroyPackageReader (IntPtr hReader);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern ushort GetPackageType (IntPtr hReader);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
[return: MarshalAs (UnmanagedType.Bool)]
public static extern bool IsPackageValid (IntPtr hReader);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern ushort GetPackageRole (IntPtr hReader);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetPackageIdentityStringValue (IntPtr hReader, uint dwName);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
[return: MarshalAs (UnmanagedType.Bool)]
public static extern bool GetPackageIdentityVersion (IntPtr hReader, out VERSION pVersion, [MarshalAs (UnmanagedType.Bool)] bool bGetSubPkgVer);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
[return: MarshalAs (UnmanagedType.Bool)]
public static extern bool GetPackageIdentityArchitecture (IntPtr hReader, out DWORD pdwArchi);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetPackagePropertiesStringValue (IntPtr hReader, string lpName);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern HRESULT GetPackagePropertiesBoolValue (IntPtr hReader, string lpName, out BOOL pRet);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
[return: MarshalAs (UnmanagedType.Bool)]
public static extern bool AddPackageApplicationItemGetName (string lpName);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
[return: MarshalAs (UnmanagedType.Bool)]
public static extern bool RemovePackageApplicationItemGetName (string lpName);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetAllApplicationItemsName ();
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern void DestroyApplicationItemsName (IntPtr hList);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetPackageApplications (IntPtr hReader);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr ApplicationsToMap (IntPtr hEnumerator);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern void DestroyApplicationsMap (IntPtr hEnumerator);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern void DestroyPackageApplications (IntPtr hEnumerator);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetResourcesLanguages (IntPtr hReader);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetResourcesLanguagesToLcid (IntPtr hReader);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetResourcesScales (IntPtr hReader);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern DWORD GetResourcesDxFeatureLevels (IntPtr hReader);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern void DestroyResourcesLanguagesList (IntPtr hList);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern void DestroyResourcesLanguagesLcidList (IntPtr hList);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern void DestroyUInt32List (IntPtr hList);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetDependencesInfoList (IntPtr hReader);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern void DestroyDependencesInfoList (IntPtr hList);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetCapabilitiesList (IntPtr hReader);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetDeviceCapabilitiesList (IntPtr hReader);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern void DestroyWStringList (IntPtr hList);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
[return: MarshalAs (UnmanagedType.Bool)]
public static extern bool GetPackagePrerequisite (IntPtr hReader, string lpName, out VERSION pVerRet);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetPackagePrerequistieSystemVersionName (IntPtr hReader, string lpName);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetAppxFileFromAppxPackage (IntPtr hReader, string lpFileName);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetAppxBundlePayloadPackageFile (IntPtr hReader, string lpFileName);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetAppxPriFileStream (IntPtr hReader);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetFileFromPayloadPackage (IntPtr hPackageStream, string lpFileName);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetPriFileFromPayloadPackage (IntPtr hPackageStream);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
[return: MarshalAs (UnmanagedType.Bool)]
public static extern bool GetSuitablePackageFromBundle (IntPtr hReader, out IntPtr pStreamForLang, out IntPtr pStreamForScale);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern ULONG DestroyAppxFileStream (IntPtr hFileStream);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr StreamToBase64W (IntPtr hFileStream, StringBuilder lpMimeBuf, DWORD dwCharCount, out IntPtr lpBase64Head);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetAppxBundleApplicationPackageFile (IntPtr hReader);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern IntPtr GetPackageCapabilityDisplayName (string lpCapabilityName);
// CRT free当 header 指示用 free 释放)
[DllImport ("msvcrt.dll", CallingConvention = CallConv, EntryPoint = "free")]
private static extern void crt_free (IntPtr ptr);
// ========== 托管辅助方法 ==========
public static string GetStringAndFreeFromPkgRead (IntPtr nativePtr)
{
if (nativePtr == IntPtr.Zero) return null;
string s = Marshal.PtrToStringUni (nativePtr);
try
{
crt_free (nativePtr);
}
catch
{
// 忽略释放失败(注意可能的 CRT 不匹配风险)
}
return s;
}
public static string PtrToStringNoFree (IntPtr nativePtr)
{
if (nativePtr == IntPtr.Zero) return null;
return Marshal.PtrToStringUni (nativePtr);
}
// 解析 HLIST_PVOID (字符串列表)
public static string [] ReadWStringList (IntPtr hList)
{
if (hList == IntPtr.Zero) return new string [0];
uint size = (uint)Marshal.ReadInt32 (hList);
if (size == 0) return new string [0];
string [] result = new string [size];
int offset = Marshal.SizeOf (typeof (uint)); // typically 4 on x86
for (int i = 0; i < size; i++)
{
IntPtr pSlot = Marshal.ReadIntPtr (hList, offset + i * IntPtr.Size);
result [i] = pSlot == IntPtr.Zero ? null : Marshal.PtrToStringUni (pSlot);
}
return result;
}
public static uint [] ReadUInt32List (IntPtr hList)
{
if (hList == IntPtr.Zero) return new uint [0];
uint size = (uint)Marshal.ReadInt32 (hList);
if (size == 0) return new uint [0];
uint [] result = new uint [size];
int offset = Marshal.SizeOf (typeof (uint));
for (int i = 0; i < size; i++)
{
result [i] = (uint)Marshal.ReadInt32 (hList, offset + i * 4);
}
return result;
}
public static int [] ReadLcidList (IntPtr hList)
{
if (hList == IntPtr.Zero) return new int [0];
uint size = (uint)Marshal.ReadInt32 (hList);
if (size == 0) return new int [0];
int [] result = new int [size];
int offset = Marshal.SizeOf (typeof (uint));
for (int i = 0; i < size; i++)
{
result [i] = Marshal.ReadInt32 (hList, offset + i * 4);
}
return result;
}
public static DEPENDENCY_INFO [] ReadDependencyInfoList (IntPtr hList)
{
if (hList == IntPtr.Zero) return new DEPENDENCY_INFO [0];
uint size = (uint)Marshal.ReadInt32 (hList);
if (size == 0) return new DEPENDENCY_INFO [0];
DEPENDENCY_INFO [] result = new DEPENDENCY_INFO [size];
int baseOffset = Marshal.SizeOf (typeof (uint));
int structSize = Marshal.SizeOf (typeof (DEPENDENCY_INFO));
for (int i = 0; i < size; i++)
{
IntPtr pItem = IntPtr.Add (hList, baseOffset + i * structSize);
object boxed = Marshal.PtrToStructure (pItem, typeof (DEPENDENCY_INFO));
result [i] = (DEPENDENCY_INFO)boxed;
}
return result;
}
public static void FreePkgReadMemory (IntPtr nativePtr)
{
if (nativePtr == IntPtr.Zero) return;
try
{
crt_free (nativePtr);
}
catch
{
}
}
}
}

View File

@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using PCSPRIFILE = System.IntPtr;
using PCOISTREAM = System.IntPtr;
namespace AppxPackage
{
public static class PriFileHelper
{
private const string DLL = "PriFormatCli.dll"; // 改成你的 DLL 名称
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern PCSPRIFILE CreatePriFileInstanceFromStream (PCOISTREAM pStream);
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void DestroyPriFileInstance (PCSPRIFILE pFilePri);
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GetPriStringResource (PCSPRIFILE pFilePri, [MarshalAs (UnmanagedType.LPWStr)] string lpswUri);
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GetPriPathResource (PCSPRIFILE pFilePri, [MarshalAs (UnmanagedType.LPWStr)] string lpswFilePath);
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern PCSPRIFILE CreatePriFileInstanceFromPath ([MarshalAs (UnmanagedType.LPWStr)] string lpswFilePath);
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs (UnmanagedType.LPWStr)]
public static extern string PriFileGetLastError ();
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void FindPriStringResource (PCSPRIFILE pFilePri, ref LPCWSTRLIST hUriList);
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void FindPriPathResource (PCSPRIFILE pFilePri, ref LPCWSTRLIST hPathList);
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void ClearPriCacheData ();
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GetPriResource (PCSPRIFILE pFilePri, [MarshalAs (UnmanagedType.LPWStr)] string lpswResId);
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void FindPriResource (PCSPRIFILE pFilePri, ref LPCWSTRLIST hUriList);
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs (UnmanagedType.Bool)]
public static extern bool IsMsResourcePrefix ([MarshalAs (UnmanagedType.LPWStr)] string pResName);
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs (UnmanagedType.Bool)]
public static extern bool IsMsResourceUriFull ([MarshalAs (UnmanagedType.LPWStr)] string pResUri);
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs (UnmanagedType.Bool)]
public static extern bool IsMsResourceUri ([MarshalAs (UnmanagedType.LPWStr)] string pResUri);
public static string PtrToString (IntPtr ptr)
{
if (ptr == IntPtr.Zero) return null;
string s = Marshal.PtrToStringUni (ptr);
Marshal.FreeHGlobal (ptr); // 如果 DLL 返回的内存要求 free
return s;
}
}
[StructLayout (LayoutKind.Sequential)]
public struct LPCWSTRLIST
{
public uint dwLength; // DWORD
[MarshalAs (UnmanagedType.ByValArray, SizeConst = 1)]
public IntPtr [] aswArray; // LPCWSTR*,数组
}
}

12
AppxPackage/PriReader.cs Normal file
View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AppxPackage
{
class PriReader
{
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("AppxPackage")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AppxPackage")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//将 ComVisible 设置为 false 将使此程序集中的类型
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible (true)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("bd681a4f-eb60-4bb8-90b5-65968fc7da59")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

80
Bridge/Bridge.csproj Normal file
View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" 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>{3C2F5446-33F0-41D5-813A-64A94AA474AF}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Bridge</RootNamespace>
<AssemblyName>Bridge</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.4\lib\net40\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="SysInit.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AppxPackage\AppxPackage.csproj">
<Project>{bd681a4f-eb60-4bb8-90b5-65968fc7da59}</Project>
<Name>AppxPackage</Name>
</ProjectReference>
<ProjectReference Include="..\DataUtils\DataUtils.csproj">
<Project>{ffd3fd52-37a8-4f43-883c-de8d996cb0e0}</Project>
<Name>DataUtils</Name>
</ProjectReference>
<ProjectReference Include="..\PrivateInit\PrivateInit.csproj">
<Project>{8e708d9a-6325-4aa9-b5a5-d1b5eca8eef7}</Project>
<Name>PrivateInit</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.manifest" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("Bridge")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Bridge")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//将 ComVisible 设置为 false 将使此程序集中的类型
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible (true)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("3c2f5446-33f0-41d5-813a-64a94aa474af")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

183
Bridge/SysInit.cs Normal file
View File

@@ -0,0 +1,183 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Win32;
using DataUtils;
using System.IO;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Windows.Forms;
using System.Drawing;
using Newtonsoft.Json;
namespace Bridge
{
public static class InitFileStore
{
public static readonly InitConfig Config;
static InitFileStore ()
{
try
{
string programRoot = GetProgramRootDirectory ();
string manifestPath = Path.Combine (programRoot, "config.ini");
Config = new InitConfig (manifestPath);
}
catch
{
Config = new InitConfig ();
}
}
public static string GetProgramRootDirectory ()
{
try
{
// Prefer the directory of the executing assembly
string codeBase = Assembly.GetExecutingAssembly ().Location;
if (!string.IsNullOrEmpty (codeBase))
{
string dir = Path.GetDirectoryName (codeBase);
if (!string.IsNullOrEmpty (dir)) return dir;
}
}
catch { }
try
{
return AppDomain.CurrentDomain.BaseDirectory ?? Environment.CurrentDirectory;
}
catch { }
return Environment.CurrentDirectory;
}
}
public static class ResXmlStore
{
public static readonly StringResXmlDoc StringRes;
static ResXmlStore ()
{
try
{
string programRoot = InitFileStore.GetProgramRootDirectory ();
string manifestPath = Path.Combine (programRoot, "locale\\resources.xml");
StringRes = new StringResXmlDoc (manifestPath);
}
catch
{
StringRes = new StringResXmlDoc ();
}
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_InitConfig
{
InitConfig Create (string filepath) => new InitConfig (filepath);
InitConfig GetConfig () => InitFileStore.Config;
InitConfig Current => InitFileStore.Config;
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_System
{
private readonly _I_Resources ires = new _I_Resources ();
private readonly _I_Locale ilocale = new _I_Locale ();
private readonly _I_UI ui;
public _I_Resources Resources { get { return ires; } }
public _I_Locale Locale { get { return ilocale; } }
public _I_UI UI => ui;
// Determines if the OS major version is 10 or greater.
// Uses RtlGetVersion for a reliable OS version.
public bool IsWindows10
{
get
{
try
{
OSVERSIONINFOEX info = new OSVERSIONINFOEX ();
info.dwOSVersionInfoSize = Marshal.SizeOf (typeof (OSVERSIONINFOEX));
int status = RtlGetVersion (ref info);
if (status == 0) // STATUS_SUCCESS
{
return info.dwMajorVersion >= 10;
}
}
catch
{
// fallback below
}
// Fallback: Environment.OSVersion (may be unreliable on some systems)
try
{
return Environment.OSVersion.Version.Major >= 10;
}
catch
{
return false;
}
}
}
#region Native interop (RtlGetVersion)
[StructLayout (LayoutKind.Sequential)]
private struct OSVERSIONINFOEX
{
public int dwOSVersionInfoSize;
public int dwMajorVersion;
public int dwMinorVersion;
public int dwBuildNumber;
public int dwPlatformId;
[MarshalAs (UnmanagedType.ByValTStr, SizeConst = 128)]
public string szCSDVersion;
public ushort wServicePackMajor;
public ushort wServicePackMinor;
public ushort wSuiteMask;
public byte wProductType;
public byte wReserved;
}
// RtlGetVersion returns NTSTATUS (0 = STATUS_SUCCESS)
[DllImport ("ntdll.dll", SetLastError = false)]
private static extern int RtlGetVersion (ref OSVERSIONINFOEX versionInfo);
#endregion
public _I_System (Form mainWnd)
{
ui = new _I_UI (mainWnd);
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_BridgeBase
{
protected readonly _I_String str = new _I_String ();
protected readonly _I_InitConfig conf = new _I_InitConfig ();
protected readonly _I_Storage stog = new _I_Storage ();
protected readonly _I_Window window;
protected readonly _I_System system;
protected readonly _I_IEFrame ieframe;
protected readonly _I_Process proc = new _I_Process ();
public _I_String String => str;
public _I_InitConfig Config => conf;
public _I_Storage Storage => stog;
public _I_Window Window => window;
public _I_IEFrame IEFrame => ieframe;
public _I_VisualElements VisualElements => new _I_VisualElements ();
public StringResXmlDoc StringResources => ResXmlStore.StringRes;
public string CmdArgs
{
get
{
return JsonConvert.SerializeObject (
Environment.GetCommandLineArgs ()
);
}
}
public _I_BridgeBase (Form wnd, IScriptBridge isc, IWebBrowserPageScale iwbps)
{
window = new _I_Window (isc);
system = new _I_System (wnd);
ieframe = new _I_IEFrame (iwbps);
}
}
}

75
Bridge/app.manifest Normal file
View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC 清单选项
如果想要更改 Windows 用户帐户控制级别,请使用
以下节点之一替换 requestedExecutionLevel 节点。n
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
指定 requestedExecutionLevel 元素将禁用文件和注册表虚拟化。
如果你的应用程序需要此虚拟化来实现向后兼容性,则删除此
元素。
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- 设计此应用程序与其一起工作且已针对此应用程序进行测试的
Windows 版本的列表。取消评论适当的元素Windows 将
自动选择最兼容的环境。 -->
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<!-- 指示该应用程序可以感知 DPI 且 Windows 在 DPI 较高时将不会对其进行
自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI无需
选择加入。选择加入此设置的 Windows 窗体应用程序(目标设定为 .NET Framework 4.6 )还应
在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。-->
<!--
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
-->
<!-- 启用 Windows 公共控件和对话框的主题(Windows XP 和更高版本) -->
<!--
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
-->
</assembly>

4
Bridge/packages.config Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="13.0.4" targetFramework="net40" />
</packages>

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" 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>{FFD3FD52-37A8-4F43-883C-DE8D996CB0E0}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DataUtils</RootNamespace>
<AssemblyName>DataUtils</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.4\lib\net40\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Download.cs" />
<Compile Include="HResult.cs" />
<Compile Include="IE.cs" />
<Compile Include="Locale.cs" />
<Compile Include="Process.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Resources.cs" />
<Compile Include="ResourceXml.cs" />
<Compile Include="Storage.cs" />
<Compile Include="String.cs" />
<Compile Include="SysInit.cs" />
<Compile Include="Taskbar.cs" />
<Compile Include="Theme.cs" />
<Compile Include="Utils.cs" />
<Compile Include="Version.cs" />
<Compile Include="VisualElements.cs" />
<Compile Include="WebBrowser.cs" />
<Compile Include="Window.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

270
DataUtils/Download.cs Normal file
View File

@@ -0,0 +1,270 @@
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Reflection;
using System.Globalization;
using System.Runtime.InteropServices;
using Newtonsoft.Json;
namespace DataUtils
{
[ComVisible (false)]
public sealed class DownloadHelper
{
private static readonly object s_downloadLock = new object (); // mimic g_download_cs
// Public static entry (starts background thread)
public static void DownloadFile (string httpUrl, string savePath, object onProgress, object onComplete, object onError)
{
if (string.IsNullOrEmpty (httpUrl)) throw new ArgumentNullException ("httpUrl");
if (string.IsNullOrEmpty (savePath)) throw new ArgumentNullException ("savePath");
var helper = new DownloadHelper (httpUrl, savePath, onProgress, onComplete, onError);
Thread th = new Thread (helper.Worker);
th.IsBackground = true;
th.Start ();
}
// Instance members
private readonly string _url;
private readonly string _savePath;
private readonly object _cbProgress;
private readonly object _cbComplete;
private readonly object _cbError;
private DownloadHelper (string url, string savePath, object cbProgress, object cbComplete, object cbError)
{
_url = url;
_savePath = savePath;
_cbProgress = cbProgress;
_cbComplete = cbComplete;
_cbError = cbError;
}
private void Worker ()
{
// Single download at a time (mimic CreateScopedLock)
lock (s_downloadLock)
{
HttpWebRequest request = null;
HttpWebResponse response = null;
Stream responseStream = null;
FileStream fileStream = null;
try
{
request = (HttpWebRequest)WebRequest.Create (_url);
request.Method = "GET";
request.AllowAutoRedirect = true;
request.UserAgent = "Mozilla/5.0 (Windows NT 6.2; Win32; x86) AppInstallerUpdater/1.0";
request.Timeout = 60000; // 60s connect timeout
request.ReadWriteTimeout = 60000;
response = (HttpWebResponse)request.GetResponse ();
long contentLength = -1;
try { contentLength = response.ContentLength; } catch { contentLength = -1; }
responseStream = response.GetResponseStream ();
// create directory if needed
string dir = Path.GetDirectoryName (_savePath);
if (!string.IsNullOrEmpty (dir) && !Directory.Exists (dir))
Directory.CreateDirectory (dir);
fileStream = new FileStream (_savePath, FileMode.Create, FileAccess.Write, FileShare.Read);
byte [] buffer = new byte [8192];
int bytesRead;
long received = 0;
var lastCheck = DateTime.UtcNow;
long lastBytes = 0;
const double reportIntervalSeconds = 0.5;
while ((bytesRead = SafeRead (responseStream, buffer, 0, buffer.Length)) > 0)
{
fileStream.Write (buffer, 0, bytesRead);
received += bytesRead;
var now = DateTime.UtcNow;
double interval = (now - lastCheck).TotalSeconds;
long speed = -1;
if (interval >= reportIntervalSeconds)
{
long bytesInInterval = received - lastBytes;
if (interval > 0)
speed = (long)(bytesInInterval / interval); // B/s
lastCheck = now;
lastBytes = received;
}
ReportProgress (received, contentLength >= 0 ? contentLength : 0, speed);
}
// flush and close file
fileStream.Flush ();
ReportComplete (_savePath, received);
}
catch (WebException wex)
{
string reason = BuildWebExceptionReason (wex);
ReportError (_savePath, reason);
}
catch (Exception ex)
{
ReportError (_savePath, ex.Message ?? ex.ToString ());
}
finally
{
try { if (responseStream != null) responseStream.Close (); } catch { }
try { if (response != null) response.Close (); } catch { }
try { if (fileStream != null) fileStream.Close (); } catch { }
}
}
}
// Safe read wrapper to handle potential stream interruptions
private static int SafeRead (Stream s, byte [] buffer, int offset, int count)
{
try
{
return s.Read (buffer, offset, count);
}
catch
{
return 0;
}
}
// Build a user-friendly reason text from WebException (includes status / inner messages)
private static string BuildWebExceptionReason (WebException wex)
{
try
{
StringBuilder sb = new StringBuilder ();
sb.Append ("WebException: ");
sb.Append (wex.Status.ToString ());
if (wex.Response != null)
{
try
{
var resp = (HttpWebResponse)wex.Response;
sb.AppendFormat (CultureInfo.InvariantCulture, " (HTTP {0})", (int)resp.StatusCode);
}
catch { }
}
if (!string.IsNullOrEmpty (wex.Message))
{
sb.Append (" - ");
sb.Append (wex.Message);
}
return sb.ToString ();
}
catch
{
return wex.Message ?? "Unknown WebException";
}
}
// ---------- Reporting helpers (use Newtonsoft.Json) ----------
private void ReportProgress (long received, long total, long speed)
{
if (_cbProgress == null) return;
double progress = 0.0;
if (total > 0) progress = received / (double)total * 100.0;
var payload = new
{
received = received,
total = total,
speed = FormatSpeed (speed),
progress = progress
};
string json = JsonConvert.SerializeObject (payload);
CallJS (_cbProgress, json);
}
private void ReportComplete (string file, long size)
{
if (_cbComplete == null) return;
var payload = new
{
file = file ?? string.Empty,
status = "ok",
size = size
};
string json = JsonConvert.SerializeObject (payload);
CallJS (_cbComplete, json);
}
private void ReportError (string file, string reason)
{
if (_cbError == null) return;
var payload = new
{
file = file ?? string.Empty,
status = "failed",
reason = reason ?? string.Empty
};
string json = JsonConvert.SerializeObject (payload);
CallJS (_cbError, json);
}
// Call JS callback object: invoke its "call" method like original code: jsFunc.call(1, arg)
private void CallJS (object jsFunc, string arg)
{
if (jsFunc == null) return;
try
{
// Use reflection to invoke `call` method with (thisArg, arg)
jsFunc.GetType ().InvokeMember (
"call",
BindingFlags.InvokeMethod,
null,
jsFunc,
new object [] { 1, arg });
}
catch
{
// ignore errors in callback invocation
}
}
// Format speed like original: B/s, KB/s, MB/s, …
private string FormatSpeed (long speed)
{
if (speed < 0) return "--/s";
string [] units = new string [] { "B/s", "KB/s", "MB/s", "GB/s", "TB/s" };
double s = (double)speed;
int idx = 0;
while (s >= 1024.0 && idx < units.Length - 1)
{
s /= 1024.0;
idx++;
}
return string.Format (CultureInfo.InvariantCulture, "{0:0.##} {1}", s, units [idx]);
}
}
// Simple COM-visible wrapper class for JS/COM consumers
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_Download
{
// Keep method order and names similar to your C++/CLI _I_Download.WorkAsync
public void WorkAsync (string httpurl, string saveFilePath, object onComplete, object onError, object onProgress)
{
DownloadHelper.DownloadFile (httpurl, saveFilePath, onProgress, onComplete, onError);
}
}
}

101
DataUtils/HResult.cs Normal file
View File

@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace DataUtils
{
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_HResult
{
private int hr;
private string errorcode;
private string detailmsg;
public _I_HResult (int hres)
{
hr = hres;
errorcode = null;
detailmsg = HResultToMessage (hr) ?? string.Empty;
}
public _I_HResult (int hres, string error, string message)
{
hr = hres;
errorcode = error ?? string.Empty;
detailmsg = message ?? string.Empty;
}
// Properties (read-only as in your C++/CLI)
public int HResult
{
get { return hr; }
}
// If user provided an explicit error code string use it; otherwise return the hex form "0xXXXXXXXX"
public string ErrorCode
{
get
{
if (!string.IsNullOrEmpty (errorcode)) return errorcode;
return "0x" + hr.ToString ("X8", System.Globalization.CultureInfo.InvariantCulture);
}
}
public string Message
{
get { return detailmsg; }
}
public bool Succeeded
{
get { return hr >= 0; } // SUCCEEDED macro: hr >= 0
}
public bool Failed
{
get { return hr < 0; } // FAILED macro: hr < 0
}
public override string ToString ()
{
return string.Format (System.Globalization.CultureInfo.InvariantCulture,
"HResult={0}, ErrorCode={1}, Message={2}", hr, ErrorCode, Message);
}
// Try to obtain a user-friendly message for the HRESULT.
// First try Marshal.GetExceptionForHR, then fallback to FormatMessage.
private static string HResultToMessage (int hresult)
{
try
{
Exception ex = Marshal.GetExceptionForHR (hresult);
if (ex != null)
{
string msg = ex.Message;
if (!string.IsNullOrEmpty (msg)) return msg;
}
}
catch
{
}
string fmt = FormatMessageFromSystem (hresult);
if (!string.IsNullOrEmpty (fmt)) return fmt;
int win32Code = hresult & 0xFFFF;
fmt = FormatMessageFromSystem (win32Code);
if (!string.IsNullOrEmpty (fmt)) return fmt;
return string.Empty;
}
private static string FormatMessageFromSystem (int messageId)
{
const int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
const int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
int flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
StringBuilder sb = new StringBuilder (512);
int res = FormatMessage (flags, IntPtr.Zero, messageId, 0, sb, sb.Capacity, IntPtr.Zero);
if (res != 0)
{
// Trim trailing newlines that FormatMessage often appends
return sb.ToString ().TrimEnd ('\r', '\n', ' ');
}
return null;
}
[DllImport ("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int FormatMessage (int dwFlags, IntPtr lpSource, int dwMessageId, int dwLanguageId, [Out] StringBuilder lpBuffer, int nSize, IntPtr Arguments);
}
}

198
DataUtils/IE.cs Normal file
View File

@@ -0,0 +1,198 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using Newtonsoft.Json;
namespace DataUtils
{
public static class BrowserEmulation
{
// The emulation value used in original C++ (11001).
// 11001 typically corresponds to IE11 in edge mode for most hosts.
private const int EmulationValue = 11001;
/// <summary>
/// Set the browser emulation value for the current user and current executable.
/// Writes to HKCU\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION.
/// Creates the key if it does not exist.
/// </summary>
public static void SetWebBrowserEmulation ()
{
try
{
string exeName = GetCurrentProcessFileName ();
if (string.IsNullOrEmpty (exeName)) return;
// Registry path under HKCU (per-user setting)
const string subKey = @"Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION";
using (RegistryKey key = Registry.CurrentUser.CreateSubKey (subKey, RegistryKeyPermissionCheck.ReadWriteSubTree))
{
if (key == null) return;
// set DWORD value
key.SetValue (exeName, EmulationValue, RegistryValueKind.DWord);
}
}
catch
{
// ignore exceptions to match original "best-effort" behavior
}
}
/// <summary>
/// 获取系统安装的 Internet Explorer 主版本号(如 8、9、10、11
/// 会尝试从 64-bit registry view 和 32-bit registry view 读取HKLM\SOFTWARE\Microsoft\Internet Explorer
/// 返回 0 表示未能读取到版本信息。
/// </summary>
public static int GetInternetExplorerVersionMajor ()
{
const string ieKey = @"SOFTWARE\Microsoft\Internet Explorer";
string versionStr = null;
// Try RegistryView.Registry64 then Registry32 for robustness on WOW64 systems
foreach (RegistryView view in new [] { RegistryView.Registry64, RegistryView.Registry32 })
{
try
{
using (RegistryKey baseKey = RegistryKey.OpenBaseKey (RegistryHive.LocalMachine, view))
using (RegistryKey key = baseKey.OpenSubKey (ieKey))
{
if (key == null) continue;
object svcVersion = key.GetValue ("svcVersion");
if (svcVersion is string)
{
versionStr = (string)svcVersion;
}
else
{
object ver = key.GetValue ("Version");
if (ver is string) versionStr = (string)ver;
}
}
}
catch
{
// ignore and continue to next view
}
if (!string.IsNullOrEmpty (versionStr)) break;
}
if (string.IsNullOrEmpty (versionStr)) return 0;
// parse major number before first non-digit/dot
int major = 0;
try
{
// common version formats: "11.0.9600.16428" etc.
string [] parts = versionStr.Split (new char [] { '.' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length > 0 && int.TryParse (parts [0], out major))
{
return major;
}
// fallback: try to read first integer found
string num = "";
foreach (char c in versionStr)
{
if (char.IsDigit (c)) num += c;
else break;
}
if (!string.IsNullOrEmpty (num) && int.TryParse (num, out major)) return major;
}
catch
{
// ignore parsing errors
}
return 0;
}
public static int IEVersionMajor => GetInternetExplorerVersionMajor ();
public static bool IsInternetExplorer10 ()
{
return GetInternetExplorerVersionMajor () == 10;
}
public static bool IE10 => IsInternetExplorer10 ();
public static bool IsInternetExplorer11AndLater ()
{
return GetInternetExplorerVersionMajor () >= 11;
}
public static bool IE11 => IsInternetExplorer11AndLater ();
// Helper: get file name of current process executable, e.g. "myapp.exe"
private static string GetCurrentProcessFileName ()
{
try
{
string path = null;
try
{
// prefer process main module (may throw in some restricted environments)
path = Process.GetCurrentProcess ().MainModule.FileName;
}
catch
{
try
{
var asm = System.Reflection.Assembly.GetEntryAssembly ();
if (asm != null) path = asm.Location;
}
catch { }
}
if (string.IsNullOrEmpty (path))
{
path = AppDomain.CurrentDomain.FriendlyName;
}
if (string.IsNullOrEmpty (path)) return string.Empty;
return Path.GetFileName (path);
}
catch
{
return string.Empty;
}
}
}
[ComVisible (true)]
public interface IScriptBridge
{
/// <summary>
/// 调用程序窗口实例中的事件
/// </summary>
/// <param name="funcName">函数名</param>
/// <param name="e">事件参数</param>
/// <returns>调用结果</returns>
object CallEvent (string funcName, object e);
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_IEFrame
{
public int Version => BrowserEmulation.IEVersionMajor;
public string ParseHtmlColor (string color)
{
try
{
Color dcolor = ColorTranslator.FromHtml (color);
var obj = new
{
r = (ushort)dcolor.R,
g = (ushort)dcolor.G,
b = (ushort)dcolor.B,
a = (ushort)dcolor.A
};
return JsonConvert.SerializeObject (obj);
}
catch
{
return "{}";
}
}
private IWebBrowserPageScale iwbps;
public _I_IEFrame (IWebBrowserPageScale _iwbps)
{
iwbps = _iwbps;
}
public int Scale
{
get { return iwbps.PageScale; }
set { iwbps.PageScale = value; }
}
}
}

373
DataUtils/Locale.cs Normal file
View File

@@ -0,0 +1,373 @@
using System;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
namespace DataUtils
{
internal static class NativeMethods
{
// GetLocaleInfoW for LCID-based queries
[DllImport ("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int GetLocaleInfoW (int Locale, int LCType, [Out] StringBuilder lpLCData, int cchData);
// GetLocaleInfoEx for locale name based queries
[DllImport ("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int GetLocaleInfoEx (string lpLocaleName, int LCType, [Out] StringBuilder lpLCData, int cchData);
// LocaleNameToLCID - available on Vista+; fallback is to use CultureInfo
[DllImport ("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int LocaleNameToLCID (string lpName, uint dwFlags);
// LCIDToLocaleName (Vista+)
[DllImport ("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int LCIDToLocaleName (int Locale, [Out] StringBuilder lpName, int cchName, uint dwFlags);
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_Locale
{
// Current locale name like "en-US"
public string CurrentLocale
{
get
{
try
{
// prefer thread culture name which reflects user culture
string name = CultureInfo.CurrentCulture.Name;
if (string.IsNullOrEmpty (name))
name = CultureInfo.InstalledUICulture.Name;
return name ?? string.Empty;
}
catch
{
return string.Empty;
}
}
}
// Current LCID (int)
public int CurrentLCID
{
get
{
try
{
return CultureInfo.CurrentCulture.LCID;
}
catch
{
return CultureInfo.InvariantCulture.LCID;
}
}
}
// Convert LCID -> locale name (e.g. 1033 -> "en-US")
public string ToLocaleName (int lcid)
{
try
{
// Try managed first
var ci = new CultureInfo (lcid);
if (!string.IsNullOrEmpty (ci.Name))
return ci.Name;
}
catch
{
// try Win32 LCIDToLocaleName (Vista+)
try
{
StringBuilder sb = new StringBuilder (LOCALE_NAME_MAX_LENGTH);
int res = NativeMethods.LCIDToLocaleName (lcid, sb, sb.Capacity, 0);
if (res > 0) return sb.ToString ();
}
catch { }
}
return string.Empty;
}
// Convert locale name -> LCID
public int ToLCID (string localeName)
{
if (string.IsNullOrEmpty (localeName)) return CultureInfo.InvariantCulture.LCID;
try
{
// prefer managed creation
var ci = new CultureInfo (localeName);
return ci.LCID;
}
catch
{
// try Win32 LocaleNameToLCID (Vista+)
try
{
int lcid = NativeMethods.LocaleNameToLCID (localeName, 0);
if (lcid != 0) return lcid;
}
catch { }
}
// fallback: invariant culture
return CultureInfo.InvariantCulture.LCID;
}
// Return a locale info string for given LCID and LCTYPE. LCTYPE is the Win32 LOCALE_* constant.
// Returns a string (or empty string on failure).
public object LocaleInfo (int lcid, int lctype)
{
try
{
// First try mapping common LCTYPE values to managed properties for better correctness
// Some common LCTYPE values:
// LOCALE_SISO639LANGNAME = 0x59 (89) -> Two-letter ISO language name
// LOCALE_SISO3166CTRYNAME = 0x5A (90) -> Two-letter country/region name
// LOCALE_SNAME = 0x5c (92) -> locale name like "en-US" (Vista+)
// But we cannot rely on all values, so we fallback to native GetLocaleInfoW.
if (lctype == 0x59) // LOCALE_SISO639LANGNAME
{
try
{
var ci = new CultureInfo (lcid);
return ci.TwoLetterISOLanguageName ?? string.Empty;
}
catch { }
}
else if (lctype == 0x5A) // LOCALE_SISO3166CTRYNAME
{
try
{
var ci = new CultureInfo (lcid);
try
{
var ri = new RegionInfo (ci.Name);
return ri.TwoLetterISORegionName ?? string.Empty;
}
catch
{
// some cultures have no region; fallback to parsing name
var name = ci.Name;
if (!string.IsNullOrEmpty (name) && name.IndexOf ('-') >= 0)
{
return name.Split ('-') [1];
}
}
}
catch { }
}
else if (lctype == 0x5c) // LOCALE_SNAME
{
try
{
var ci = new CultureInfo (lcid);
return ci.Name ?? string.Empty;
}
catch { }
}
// Fallback to native GetLocaleInfoW
StringBuilder sb = new StringBuilder (256);
int ret = NativeMethods.GetLocaleInfoW (lcid, lctype, sb, sb.Capacity);
if (ret > 0)
return sb.ToString ();
return string.Empty;
}
catch
{
return string.Empty;
}
}
// LocaleInfoEx: query by locale name string and LCTYPE
// Returns string if available; otherwise returns the integer result code (as int) if string empty (mimic C++ behavior).
public object LocaleInfoEx (string localeName, int lctype)
{
if (string.IsNullOrEmpty (localeName))
{
// fall back to current culture name
localeName = CurrentLocale;
if (string.IsNullOrEmpty (localeName)) return 0;
}
try
{
// Try managed shortcuts for common types
if (lctype == 0x59) // LOCALE_SISO639LANGNAME
{
try
{
var ci = new CultureInfo (localeName);
return ci.TwoLetterISOLanguageName ?? string.Empty;
}
catch { }
}
else if (lctype == 0x5A) // LOCALE_SISO3166CTRYNAME
{
try
{
var ci = new CultureInfo (localeName);
var ri = new RegionInfo (ci.Name);
return ri.TwoLetterISORegionName ?? string.Empty;
}
catch
{
// try to split
var parts = localeName.Split (new char [] { '-', '_' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length >= 2) return parts [1];
}
}
else if (lctype == 0x5c) // LOCALE_SNAME
{
// localeName is probably already the name
return localeName;
}
// Fallback to GetLocaleInfoEx
StringBuilder sb = new StringBuilder (LOCALE_NAME_MAX_LENGTH);
int res = NativeMethods.GetLocaleInfoEx (localeName, lctype, sb, sb.Capacity);
if (res > 0)
{
string outStr = sb.ToString ();
if (!string.IsNullOrEmpty (outStr))
return outStr;
}
// if nothing returned, return the result code
return res;
}
catch
{
return 0;
}
}
// Helpers similar to the C++: restricted (language) and elaborated (region) codes
public string GetLocaleRestrictedCode (string localeName)
{
if (string.IsNullOrEmpty (localeName)) localeName = CurrentLocale;
try
{
var ci = new CultureInfo (localeName);
return ci.TwoLetterISOLanguageName ?? string.Empty;
}
catch
{
// fallback: parse name
var parts = localeName.Split (new char [] { '-', '_' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length >= 1) return parts [0];
return string.Empty;
}
}
public string GetLocaleElaboratedCode (string localeName)
{
if (string.IsNullOrEmpty (localeName)) localeName = CurrentLocale;
try
{
var ci = new CultureInfo (localeName);
// Region part from RegionInfo
try
{
var ri = new RegionInfo (ci.Name);
return ri.TwoLetterISORegionName ?? string.Empty;
}
catch
{
// fallback: parse
var parts = localeName.Split (new char [] { '-', '_' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length >= 2) return parts [1];
}
}
catch
{
var parts = localeName.Split (new char [] { '-', '_' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length >= 2) return parts [1];
}
return string.Empty;
}
// LCID -> combined code like "en-US" (with configurable separator)
public string LcidToLocaleCode (int lcid)
{
try
{
var ci = new CultureInfo (lcid);
if (!string.IsNullOrEmpty (ci.Name)) return ci.Name;
}
catch
{
try
{
var name = ToLocaleName (lcid);
if (!string.IsNullOrEmpty (name)) return name;
}
catch { }
}
return string.Empty;
}
// Get the user default locale name
public string GetUserDefaultLocaleName ()
{
try
{
// In .NET, CurrentCulture corresponds to user default
string name = CultureInfo.CurrentCulture.Name;
if (!string.IsNullOrEmpty (name)) return name;
}
catch { }
return LcidToLocaleCode (CultureInfo.CurrentCulture.LCID);
}
// Get system default locale name (machine)
public string GetSystemDefaultLocaleName ()
{
try
{
// InstalledUICulture / Invariant fallback
string name = CultureInfo.InstalledUICulture.Name;
if (!string.IsNullOrEmpty (name)) return name;
}
catch { }
return LcidToLocaleCode (CultureInfo.InstalledUICulture.LCID);
}
// Get computer locale code similar to C++ approach
public string GetComputerLocaleCode ()
{
try
{
// Thread culture -> user -> system
string threadName = System.Threading.Thread.CurrentThread.CurrentCulture.Name;
if (!string.IsNullOrEmpty (threadName)) return threadName;
string user = GetUserDefaultLocaleName ();
if (!string.IsNullOrEmpty (user)) return user;
string system = GetSystemDefaultLocaleName ();
if (!string.IsNullOrEmpty (system)) return system;
}
catch { }
// fallback to invariant
return CultureInfo.InvariantCulture.Name ?? string.Empty;
}
// Compare two locale names; returns true if equal by name or LCID
public bool LocaleNameCompare (string left, string right)
{
if (string.Equals (left, right, StringComparison.OrdinalIgnoreCase)) return true;
try
{
int l = ToLCID (left);
int r = ToLCID (right);
return l == r && l != CultureInfo.InvariantCulture.LCID;
}
catch
{
return false;
}
}
// Constants
private const int LOCALE_NAME_MAX_LENGTH = 85; // defined by Windows
}
}

201
DataUtils/Process.cs Normal file
View File

@@ -0,0 +1,201 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
using Newtonsoft.Json;
using System.Windows.Forms;
using System.Threading;
namespace DataUtils
{
public static class ProcessHelper
{
public static int ExecuteProgram (
string cmdline,
string file,
int wndShowMode,
bool wait,
string execDir = "")
{
try
{
var psi = new ProcessStartInfo
{
FileName = string.IsNullOrEmpty (file) ? cmdline : file,
Arguments = string.IsNullOrEmpty (file) ? "" : cmdline,
WorkingDirectory = string.IsNullOrEmpty (execDir) ? null : execDir,
UseShellExecute = false,
CreateNoWindow = false,
WindowStyle = (ProcessWindowStyle)wndShowMode
};
using (var p = Process.Start (psi))
{
if (wait && p != null)
p.WaitForExit ();
}
return 0;
}
catch (Exception ex)
{
return Marshal.GetHRForException (ex);
}
}
public static bool KillProcessByFilePath (
string filepath,
bool multiple = false,
bool isOnlyName = false)
{
if (string.IsNullOrEmpty (filepath)) return false;
bool killed = false;
string targetName = isOnlyName ? Path.GetFileName (filepath) : null;
foreach (var p in Process.GetProcesses ())
{
try
{
bool match = false;
if (isOnlyName)
{
match = string.Equals (p.ProcessName + ".exe", targetName,
StringComparison.OrdinalIgnoreCase);
}
else
{
string fullPath = p.MainModule.FileName;
match = string.Equals (fullPath, filepath,
StringComparison.OrdinalIgnoreCase);
}
if (match)
{
p.Kill ();
killed = true;
if (!multiple) break;
}
}
catch { }
}
return killed;
}
public static string GetFileVersionAsJson (string filePath)
{
try
{
var info = FileVersionInfo.GetVersionInfo (filePath);
var obj = new
{
info.CompanyName,
info.FileDescription,
info.FileVersion,
info.InternalName,
info.OriginalFilename,
info.ProductName,
info.ProductVersion,
info.LegalCopyright,
FileVersionRaw = info.FileMajorPart + "." +
info.FileMinorPart + "." +
info.FileBuildPart + "." +
info.FilePrivatePart
};
return JsonConvert.SerializeObject (obj);
}
catch (Exception ex)
{
return JsonConvert.SerializeObject (new { error = ex.Message });
}
}
public static int ExploreSaveFile (
IWin32Window owner,
List<string> results,
string filter = "Windows Store App Package (*.appx; *.appxbundle)|*.appx;*.appxbundle",
string defExt = "appx",
string title = "Please select the file to save:",
string initDir = null)
{
results.Clear ();
using (var dlg = new SaveFileDialog ())
{
dlg.Filter = filter;
dlg.DefaultExt = defExt;
dlg.Title = title;
dlg.InitialDirectory = initDir;
if (dlg.ShowDialog (owner) == DialogResult.OK)
{
results.Add (dlg.FileName);
}
}
return results.Count;
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_Process
{
public int Run (
string cmdline,
string filepath,
int wndtype,
bool wait,
string runpath)
{
return ProcessHelper.ExecuteProgram (cmdline, filepath, wndtype, wait, runpath);
}
public void RunAsync (
string cmdline,
string filepath,
int wndtype,
string runpath,
object callback)
{
var worker = new ProcessWorker (this)
{
CmdLine = cmdline,
FilePath = filepath,
WndType = wndtype,
RunPath = runpath,
Callback = callback
};
var th = new Thread (worker.Work)
{
IsBackground = true
};
th.Start ();
}
public bool Kill (string filename, bool allproc, bool onlyname)
{
return ProcessHelper.KillProcessByFilePath (filename, allproc, onlyname);
}
private class ProcessWorker
{
private readonly _I_Process parent;
public string CmdLine;
public string FilePath;
public int WndType;
public string RunPath;
public object Callback;
public ProcessWorker (_I_Process parent)
{
this.parent = parent;
}
public void Work ()
{
int ret = parent.Run (CmdLine, FilePath, WndType, true, RunPath);
if (Callback != null)
{
try
{
Callback.GetType ().InvokeMember (
"call",
System.Reflection.BindingFlags.InvokeMethod,
null,
Callback,
new object [] { 1, ret }
);
}
catch { }
}
}
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("DataUtils")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DataUtils")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//将 ComVisible 设置为 false 将使此程序集中的类型
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible (true)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("ffd3fd52-37a8-4f43-883c-de8d996cb0e0")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

272
DataUtils/ResourceXml.cs Normal file
View File

@@ -0,0 +1,272 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
namespace DataUtils
{
public class FileResXmlDoc: IDisposable
{
private string _filepath;
private XmlDocument _doc;
private bool _available;
public FileResXmlDoc (string xmlpath)
{
Create (xmlpath);
}
public bool Create (string xmlpath)
{
Destroy ();
if (string.IsNullOrEmpty (xmlpath) || !File.Exists (xmlpath))
{
_available = false;
return false;
}
try
{
_doc = new XmlDocument ();
_doc.Load (xmlpath);
_filepath = xmlpath;
_available = true;
}
catch
{
_available = false;
}
return _available;
}
public void Destroy ()
{
if (!_available) return;
_doc = null;
_available = false;
_filepath = null;
}
public void Dispose ()
{
Destroy ();
}
// Returns the chosen absolute (or resolved) path string or empty if none found
public string Get (string id)
{
if (!_available || _doc == null) return string.Empty;
if (string.IsNullOrEmpty (id)) return string.Empty;
XmlNode root = _doc.DocumentElement;
if (root == null) return string.Empty;
foreach (XmlNode node in root.ChildNodes)
{
var attr = node.Attributes? ["id"];
if (attr == null) continue;
if (!string.Equals (attr.Value, id, StringComparison.OrdinalIgnoreCase)) continue;
// Build dpi -> path map
var map = new Dictionary<int, string> ();
foreach (XmlNode child in node.ChildNodes)
{
var dpiAttr = child.Attributes? ["dpi"];
string dpiStr = dpiAttr != null ? dpiAttr.Value : "default";
string text = child.InnerText ?? string.Empty;
int dpiKey = 0;
if (string.Equals (dpiStr, "default", StringComparison.OrdinalIgnoreCase))
{
dpiKey = 0;
}
else
{
int parsed;
if (int.TryParse (dpiStr, out parsed)) dpiKey = parsed;
else dpiKey = 0;
}
// Resolve relative path relative to xml file directory
string candidate = text;
if (!Path.IsPathRooted (candidate) && !string.IsNullOrEmpty (_filepath))
{
string dir = Path.GetDirectoryName (_filepath);
if (!string.IsNullOrEmpty (dir))
candidate = Path.Combine (dir, candidate);
}
// Normalize
try { candidate = Path.GetFullPath (candidate); } catch { /* ignore */ }
// Insert/overwrite by key (keep last if duplicate)
map [dpiKey] = candidate;
}
// Convert map to list and sort by string value (to mimic original)
var list = map.Select (kv => new KeyValuePair<int, string> (kv.Key, kv.Value)).ToList ();
list.Sort ((a, b) => string.CompareOrdinal (a.Value, b.Value));
// Keep only those whose file exists
var existList = new List<KeyValuePair<int, string>> ();
foreach (var kv in list)
{
if (!string.IsNullOrEmpty (kv.Value) && File.Exists (kv.Value))
existList.Add (kv);
}
int dpiPercent = UITheme.GetDPI (); // uses earlier helper
// Find first with dpi >= dpiPercent
foreach (var kv in existList)
{
if (kv.Key >= dpiPercent) return kv.Value;
}
// otherwise return first existing candidate
if (existList.Count > 0) return existList [0].Value;
return string.Empty;
}
return string.Empty;
}
// Overloads for convenience
//public string Get (System.String idAsString) { return Get (idAsString); }
}
public class StringResXmlDoc: IDisposable
{
private XmlDocument doc;
private bool isValid;
public bool IsValid
{
get { return isValid; }
}
public StringResXmlDoc () { }
public StringResXmlDoc (string filePath)
{
Create (filePath);
}
public bool Create (string filePath)
{
Destroy ();
if (string.IsNullOrEmpty (filePath) || !File.Exists (filePath))
return false;
try
{
doc = new XmlDocument ();
doc.Load (filePath);
isValid = true;
return true;
}
catch
{
Destroy ();
return false;
}
}
public void Destroy ()
{
doc = null;
isValid = false;
}
public void Dispose ()
{
Destroy ();
GC.SuppressFinalize (this);
}
public string Get (string id)
{
if (!isValid || doc == null || string.IsNullOrEmpty (id))
return string.Empty;
XmlElement root = doc.DocumentElement;
if (root == null)
return string.Empty;
foreach (XmlNode node in root.ChildNodes)
{
if (node.Attributes == null)
continue;
XmlAttribute idAttr = node.Attributes ["id"];
if (idAttr == null)
continue;
if (!StringEqualsNormalized (idAttr.Value, id))
continue;
Dictionary<string, string> langValues =
new Dictionary<string, string> (StringComparer.OrdinalIgnoreCase);
foreach (XmlNode sub in node.ChildNodes)
{
if (sub.Attributes == null)
continue;
XmlAttribute langAttr = sub.Attributes ["name"];
if (langAttr == null)
continue;
string lang = langAttr.Value;
if (!string.IsNullOrEmpty (lang))
{
langValues [lang] = sub.InnerText;
}
}
return GetSuitableLanguageValue (langValues);
}
return string.Empty;
}
public string this [string id]
{
get { return Get (id); }
}
private static bool StringEqualsNormalized (string a, string b)
{
return string.Equals (
a != null ? a.Trim () : null,
b != null ? b.Trim () : null,
StringComparison.OrdinalIgnoreCase
);
}
private static string GetSuitableLanguageValue (
Dictionary<string, string> values)
{
if (values == null || values.Count == 0)
return string.Empty;
CultureInfo culture = CultureInfo.CurrentUICulture;
string val;
if (values.TryGetValue (culture.Name, out val))
return val;
if (values.TryGetValue (culture.TwoLetterISOLanguageName, out val))
return val;
if (values.TryGetValue ("en", out val))
return val;
foreach (string v in values.Values)
return v;
return string.Empty;
}
}
}

84
DataUtils/Resources.cs Normal file
View File

@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace DataUtils
{
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_Resources
{
// Flags for LoadLibraryEx
private const uint LOAD_LIBRARY_AS_DATAFILE = 0x00000002;
private const uint LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020;
[DllImport ("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr LoadLibraryEx (string lpFileName, IntPtr hFile, uint dwFlags);
[DllImport ("kernel32.dll", SetLastError = true)]
[return: MarshalAs (UnmanagedType.Bool)]
private static extern bool FreeLibrary (IntPtr hModule);
[DllImport ("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr GetModuleHandle (string lpModuleName);
[DllImport ("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int LoadString (IntPtr hInstance, uint uID, StringBuilder lpBuffer, int nBufferMax);
/// <summary>
/// Load a string resource from another module (DLL/EXE) identified by file path, or from the current module if filepath is null/empty.
/// </summary>
/// <param name="filepath">Path to the module file. If null/empty, use current process module.</param>
/// <param name="resid">Resource ID to load.</param>
/// <returns>The resource string, or empty string if not found or on error.</returns>
public string GetFromOthers (string filepath, uint resid)
{
IntPtr hModule = IntPtr.Zero;
bool needFree = false;
try
{
if (!string.IsNullOrWhiteSpace (filepath))
{
// Load as datafile + image resource so we can access resources without executing DllMain of the module.
hModule = LoadLibraryEx (filepath, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
if (hModule == IntPtr.Zero)
{
// Failed to load; return empty string
return string.Empty;
}
needFree = true;
}
else
{
// Get handle of current process module (exe)
hModule = GetModuleHandle (null);
if (hModule == IntPtr.Zero)
return string.Empty;
}
// Prepare buffer. Typical string resources are not huge; 4096 should be enough.
const int BUFFER_SIZE = 4096;
StringBuilder sb = new StringBuilder (BUFFER_SIZE);
int copied = LoadString (hModule, resid, sb, sb.Capacity);
if (copied > 0)
{
// LoadString returns number of characters copied (excluding terminating null)
return sb.ToString (0, copied);
}
return string.Empty;
}
finally
{
if (needFree && hModule != IntPtr.Zero)
{
try { FreeLibrary (hModule); }
catch { /* ignore */ }
}
}
}
}
}

519
DataUtils/Storage.cs Normal file
View File

@@ -0,0 +1,519 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace DataUtils
{
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_Path
{
public string Current
{
get
{
try { return Directory.GetCurrentDirectory (); }
catch { return string.Empty; }
}
set
{
try
{
if (!string.IsNullOrEmpty (value)) Directory.SetCurrentDirectory (value);
}
catch { /* ignore */ }
}
}
public string Program
{
get { return Utilities.GetCurrentProgramPath (); }
}
public string Root
{
get
{
try
{
string prog = Utilities.GetCurrentProgramPath ();
return Path.GetDirectoryName (prog) ?? string.Empty;
}
catch { return string.Empty; }
}
}
public string Combine (string l, string r)
{
if (string.IsNullOrEmpty (l)) return r ?? string.Empty;
if (string.IsNullOrEmpty (r)) return l ?? string.Empty;
try { return Path.Combine (l, r); }
catch { return l + Path.DirectorySeparatorChar + r; }
}
public string GetName (string path)
{
if (string.IsNullOrEmpty (path)) return string.Empty;
try
{
return Path.GetFileName (path);
}
catch { return string.Empty; }
}
public string GetDirectory (string path)
{
if (string.IsNullOrEmpty (path)) return string.Empty;
try
{
return Path.GetDirectoryName (path) ?? string.Empty;
}
catch { return string.Empty; }
}
public string GetDir (string path) { return GetDirectory (path); }
public bool Exist (string path)
{
if (string.IsNullOrEmpty (path)) return false;
return File.Exists (path) || Directory.Exists (path);
}
public bool FileExist (string filepath)
{
if (string.IsNullOrEmpty (filepath)) return false;
return File.Exists (filepath);
}
public bool DirectoryExist (string dirpath)
{
if (string.IsNullOrEmpty (dirpath)) return false;
return Directory.Exists (dirpath);
}
public bool DirExist (string dirpath) { return DirectoryExist (dirpath); }
public string GetEnvironmentString (string str)
{
if (string.IsNullOrEmpty (str)) return string.Empty;
try
{
return Environment.ExpandEnvironmentVariables (str);
}
catch { return str; }
}
// Valid Windows filename?
public bool ValidName (string filename)
{
if (string.IsNullOrEmpty (filename)) return false;
char [] invalid = Path.GetInvalidFileNameChars ();
return filename.IndexOfAny (invalid) < 0;
}
// filter may be e.g. "*.txt;*.md" or using "\" separators per legacy code
public string EnumFilesToJson (string dir, string filter, bool withpath, bool sort, bool includesub)
{
var arr = EnumFiles (dir, filter, withpath, sort, includesub);
return Utilities.StringArrayToJson (arr);
}
public string EnumDirsToJson (string dir, bool withpath, bool sort, bool includesub)
{
var arr = EnumDirs (dir, withpath, sort, includesub);
return Utilities.StringArrayToJson (arr);
}
public string EnumSubDirsToJson (string dir, bool withpath)
{
var arr = EnumSubDirs (dir, withpath);
return Utilities.StringArrayToJson (arr);
}
public string [] EnumFiles (string dir, string filter, bool withpath, bool sort, bool includesub)
{
if (string.IsNullOrEmpty (dir)) return new string [0];
var patterns = Utilities.SplitFilters (filter);
var list = new List<string> (100);
try
{
var searchOption = includesub ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
foreach (var pat in patterns)
{
try
{
foreach (var f in Directory.EnumerateFiles (dir, pat, searchOption))
{
list.Add (withpath ? f : Path.GetFileName (f));
}
}
catch (UnauthorizedAccessException) { /* skip */ }
catch (DirectoryNotFoundException) { /* skip */ }
catch (IOException) { /* skip */ }
}
if (sort)
{
list.Sort (StringComparer.OrdinalIgnoreCase);
}
}
catch
{
// fallback: empty
}
return list.ToArray ();
}
public string [] EnumDirs (string dir, bool withpath, bool sort, bool includesub)
{
if (string.IsNullOrEmpty (dir)) return new string [0];
var list = new List<string> (100);
try
{
var searchOption = includesub ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
foreach (var d in Directory.EnumerateDirectories (dir, "*", searchOption))
{
list.Add (withpath ? d : Path.GetFileName (d));
}
if (sort) list.Sort (StringComparer.OrdinalIgnoreCase);
}
catch { }
return list.ToArray ();
}
public string [] EnumSubDirs (string dir, bool withpath)
{
return EnumDirs (dir, withpath, true, true);
}
public string CommonPrefix (string path1, string path2)
{
if (string.IsNullOrEmpty (path1) || string.IsNullOrEmpty (path2)) return string.Empty;
try
{
string a = Utilities.NormalizeFullPath (path1);
string b = Utilities.NormalizeFullPath (path2);
string [] asplit = a.Split (new char [] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
string [] bsplit = b.Split (new char [] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
int min = Math.Min (asplit.Length, bsplit.Length);
var sb = new StringBuilder ();
for (int i = 0; i < min; i++)
{
if (!string.Equals (asplit [i], bsplit [i], StringComparison.OrdinalIgnoreCase)) break;
sb.Append (asplit [i]);
sb.Append (Path.DirectorySeparatorChar);
}
return sb.ToString ().TrimEnd (Path.DirectorySeparatorChar);
}
catch { return string.Empty; }
}
public string EnsureDirSlash (string dir)
{
if (string.IsNullOrEmpty (dir)) return string.Empty;
try
{
if (!dir.EndsWith (Path.DirectorySeparatorChar.ToString ()))
dir += Path.DirectorySeparatorChar;
return dir;
}
catch { return dir; }
}
public string Normalize (string path)
{
if (string.IsNullOrEmpty (path)) return string.Empty;
try { return Path.GetFullPath (path); }
catch { return path; }
}
public string FullPathName (string path) { return Normalize (path); }
public string FullPath (string path) { return FullPathName (path); }
public string Expand (string path) { return GetEnvironmentString (path); }
// GetFolder via SHGetFolderPath (preserves the original csidl param usage)
public string GetFolder (int csidl)
{
try
{
// try P/Invoke to SHGetFolderPath
return ShellHelpers.GetFolderPath (csidl);
}
catch
{
return string.Empty;
}
}
// KnownFolder by GUID string (wraps SHGetKnownFolderPath)
public string KnownFolder (string guidString)
{
if (string.IsNullOrWhiteSpace (guidString)) return string.Empty;
Guid guid;
try
{
guid = new Guid (guidString);
}
catch
{
return string.Empty;
}
try
{
return ShellHelpers.GetKnownFolderPath (guid);
}
catch
{
return string.Empty;
}
}
public bool PEquals (string l, string r)
{
if (l == null && r == null) return true;
if (l == null || r == null) return false;
string a = Utilities.NormalizeFullPath (l);
string b = Utilities.NormalizeFullPath (r);
return string.Equals (a, b, StringComparison.OrdinalIgnoreCase);
}
}
// Basic entry object
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_Entry
{
protected string path;
public _I_Entry (string path)
{
this.path = path ?? string.Empty;
}
public _I_Entry ()
{
this.path = string.Empty;
}
public virtual string Path
{
get { return path; }
set { path = value ?? string.Empty; }
}
public virtual string Name
{
get
{
try
{
return System.IO.Path.GetFileName (path) ?? string.Empty;
}
catch { return string.Empty; }
}
}
public virtual string Directory
{
get
{
try { return System.IO.Path.GetDirectoryName (path) ?? string.Empty; }
catch { return string.Empty; }
}
}
public virtual string Root { get { return Directory; } }
public virtual bool Exist
{
get
{
return File.Exists (path) || System.IO.Directory.Exists (path);
}
}
public virtual string Uri
{
get
{
try
{
Uri uri;
if (System.Uri.TryCreate (path, UriKind.Absolute, out uri))
{
return uri.AbsoluteUri;
}
else
{
Uri u = new Uri (System.IO.Path.GetFullPath (path));
return u.AbsoluteUri;
}
}
catch
{
return string.Empty;
}
}
}
public virtual string FullPath
{
get
{
try { return System.IO.Path.GetFullPath (path); }
catch { return path; }
}
}
// Return relative path from frontdir to this.Path; similar semantics to C++ code
public string RelativePath (string frontdir)
{
if (string.IsNullOrEmpty (path) || string.IsNullOrEmpty (frontdir)) return string.Empty;
try
{
string fullFile = System.IO.Path.GetFullPath (path);
string fullDir = System.IO.Path.GetFullPath (frontdir);
if (!fullDir.EndsWith (System.IO.Path.DirectorySeparatorChar.ToString ()))
fullDir += System.IO.Path.DirectorySeparatorChar;
if (!string.Equals (System.IO.Path.GetPathRoot (fullFile), System.IO.Path.GetPathRoot (fullDir), StringComparison.OrdinalIgnoreCase))
return string.Empty;
if (!fullFile.StartsWith (fullDir, StringComparison.OrdinalIgnoreCase)) return string.Empty;
return fullFile.Substring (fullDir.Length);
}
catch
{
return string.Empty;
}
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_File: _I_Entry
{
// last encoding used when reading
protected Encoding lastEncoding;
public _I_File () : base (string.Empty) { }
public _I_File (string filepath) : base (filepath) { }
// Read file contents; detect BOM if present by using StreamReader with detectEncodingFromByteOrderMarks = true
public string Get ()
{
if (string.IsNullOrEmpty (path)) return string.Empty;
try
{
using (FileStream fs = new FileStream (path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (StreamReader sr = new StreamReader (fs, Encoding.UTF8, true))
{
string text = sr.ReadToEnd ();
lastEncoding = sr.CurrentEncoding;
return text;
}
}
catch
{
return null;
}
}
public void Set (string content)
{
if (string.IsNullOrEmpty (path)) return;
try
{
string dir = System.IO.Path.GetDirectoryName (path);
if (!string.IsNullOrEmpty (dir) && !System.IO.Directory.Exists (dir))
{
System.IO.Directory.CreateDirectory (dir);
}
Encoding enc = lastEncoding ?? Encoding.UTF8;
using (FileStream fs = new FileStream (path, FileMode.Create, FileAccess.Write, FileShare.Read))
using (StreamWriter sw = new StreamWriter (fs, enc))
{
sw.Write (content ?? string.Empty);
sw.Flush ();
}
}
catch
{
// ignore write errors
}
}
public string Content
{
get { return Get (); }
set { Set (value); }
}
public override bool Exist
{
get { return File.Exists (path); }
}
public string FilePath
{
get { return this.Path; }
set { this.Path = value; }
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_Directory: _I_Entry
{
public _I_Directory () : base (string.Empty) { }
public _I_Directory (string dirpath) : base (dirpath) { }
public _I_Directory (_I_Entry file) : base (file != null ? file.Directory : string.Empty) { }
public string DirectoryPath
{
get { return this.Path; }
set { this.Path = value; }
}
public string DirPath { get { return DirectoryPath; } set { DirectoryPath = value; } }
public override bool Exist { get { return System.IO.Directory.Exists (path); } }
public string EnumFilesToJson (string filter, bool withpath, bool sort, bool includesub)
{
_I_Path p = new _I_Path ();
string [] arr = p.EnumFiles (DirPath, filter, withpath, sort, includesub);
return Utilities.StringArrayToJson (arr);
}
public string EnumDirsToJson (bool withpath, bool sort, bool includesub)
{
_I_Path p = new _I_Path ();
string [] arr = p.EnumDirs (DirPath, withpath, sort, includesub);
return Utilities.StringArrayToJson (arr);
}
public string EnumSubDirsToJson (bool withpath)
{
_I_Path p = new _I_Path ();
string [] arr = p.EnumSubDirs (DirPath, withpath);
return Utilities.StringArrayToJson (arr);
}
public string [] EnumFiles (string filter, bool withpath, bool sort, bool includesub)
{
_I_Path p = new _I_Path ();
return p.EnumFiles (DirPath, filter, withpath, sort, includesub);
}
public string [] EnumDirs (bool withpath, bool sort, bool includesub)
{
_I_Path p = new _I_Path ();
return p.EnumDirs (DirPath, withpath, sort, includesub);
}
public string [] EnumSubDirs (bool withpath)
{
_I_Path p = new _I_Path ();
return p.EnumSubDirs (DirPath, withpath);
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_Storage
{
protected _I_Path path = new _I_Path ();
public _I_Path Path { get { return path; } }
public _I_File GetFile (string path) { return new _I_File (path); }
public _I_Directory GetDirectory (string path) { return new _I_Directory (path); }
public _I_Directory GetDir (string path) { return GetDirectory (path); }
}
// Small shell helpers that P/Invoke for folder retrieval using CSIDL or Known Folder GUIDs
internal static class ShellHelpers
{
[System.Runtime.InteropServices.DllImport ("shell32.dll")]
private static extern int SHGetFolderPathW (IntPtr hwndOwner, int nFolder, IntPtr hToken, uint dwFlags, [System.Runtime.InteropServices.MarshalAs (System.Runtime.InteropServices.UnmanagedType.LPWStr)] StringBuilder pszPath);
public static string GetFolderPath (int csidl)
{
StringBuilder sb = new StringBuilder (260);
int hr = SHGetFolderPathW (IntPtr.Zero, csidl, IntPtr.Zero, 0, sb);
if (hr == 0) return sb.ToString ();
return string.Empty;
}
[System.Runtime.InteropServices.DllImport ("shell32.dll")]
private static extern int SHGetKnownFolderPath ([System.Runtime.InteropServices.MarshalAs (System.Runtime.InteropServices.UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, IntPtr hToken, out IntPtr ppszPath);
[System.Runtime.InteropServices.DllImport ("ole32.dll")]
private static extern void CoTaskMemFree (IntPtr pv);
public static string GetKnownFolderPath (Guid guid)
{
IntPtr pathPtr;
int hr = SHGetKnownFolderPath (guid, 0, IntPtr.Zero, out pathPtr);
if (hr != 0 || pathPtr == IntPtr.Zero) return string.Empty;
try
{
string path = Marshal.PtrToStringUni (pathPtr);
return path ?? string.Empty;
}
finally
{
if (pathPtr != IntPtr.Zero) CoTaskMemFree (pathPtr);
}
}
}
}

115
DataUtils/String.cs Normal file
View File

@@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace DataUtils
{
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_String
{
// Nested normalization helper
[ComVisible (true)]
public class _I_NString
{
// Normalize strings: Trim, apply Unicode normalization form KD, and to-lower invariant.
private static string Normalize (string s)
{
if (s == null) return string.Empty;
s = s.Trim ();
return s.ToLowerInvariant ();
}
// Compare normalized equality
public bool NEquals (string l, string r)
{
return string.Equals (Normalize (l), Normalize (r), StringComparison.Ordinal);
}
// Is normalized empty
public bool Empty (string l)
{
string n = Normalize (l);
return string.IsNullOrEmpty (n);
}
// Compare normalized strings with ordinal comparison (returns -1/0/1)
public int Compare (string l, string r)
{
string nl = Normalize (l);
string nr = Normalize (r);
return string.CompareOrdinal (nl, nr);
}
// Get length of normalized string (in characters)
public int Length (string l)
{
string nl = Normalize (l);
return nl.Length;
}
}
private _I_NString nstr = new _I_NString ();
public _I_NString NString { get { return nstr; } }
public string Trim (string src)
{
if (src == null) return string.Empty;
return src.Trim ();
}
public string ToLower (string src)
{
if (src == null) return null;
return src.ToLower (CultureInfo.InvariantCulture);
}
public string ToUpper (string src)
{
if (src == null) return null;
return src.ToUpper (CultureInfo.InvariantCulture);
}
public string Format (string fmt, params object [] args)
{
return Utilities.FormatString (fmt, args);
}
// FormatInnerHTML: escape format string to inner xml, and escape each argument to inner xml wrapped in <span>...</span>
public string FormatInnerHTML (string fmt, params object [] args)
{
if (fmt == null) fmt = string.Empty;
string escapedFormat = Utilities.EscapeToInnerXml (fmt);
if (args == null || args.Length == 0) return escapedFormat;
object [] newArgs = new object [args.Length];
for (int i = 0; i < args.Length; i++)
{
string argText = args [i] != null ? args [i].ToString () : string.Empty;
string esc = Utilities.EscapeToInnerXml (argText);
newArgs [i] = string.Format ("<span>{0}</span>", esc);
}
try
{
// We used an escaped format string, but its indices are the same.
return string.Format (CultureInfo.InvariantCulture, escapedFormat, newArgs);
}
catch
{
// fallback: simple concatenation
StringBuilder sb = new StringBuilder ();
sb.Append (escapedFormat);
sb.Append (" ");
for (int i = 0; i < newArgs.Length; i++)
{
if (i > 0) sb.Append (", ");
sb.Append (newArgs [i]);
}
return sb.ToString ();
}
}
public string StringArrayToJson (string [] strs)
{
return Utilities.StringArrayToJson (strs);
}
public static string FormatDateTime (string fmt, string jsDate)
{
DateTime dt = Convert.ToDateTime (jsDate);
return string.Format (fmt, dt);
}
}
}

274
DataUtils/SysInit.cs Normal file
View File

@@ -0,0 +1,274 @@
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
namespace DataUtils
{
internal static class VisualElementsStore
{
// Publicly accessible instances for internal use
public static readonly VisualElementManifest Vemanifest;
public static readonly FileResXmlDoc ScaleResources;
static VisualElementsStore ()
{
try
{
string programRoot = GetProgramRootDirectory ();
// manifest path: VisualElementsManifest.xml in program root
string manifestPath = Path.Combine (programRoot, "VisualElementsManifest.xml");
// scale xml candidate: VisualElements\scale.xml
string scaleCandidate = Path.Combine (programRoot, "VisualElements", "scale.xml");
// If scale.xml exists use it, otherwise fall back to VisualElementsManifest.xml
string scalePath = File.Exists (scaleCandidate) ? scaleCandidate : manifestPath;
// Initialize (constructors will attempt to load)
Vemanifest = new VisualElementManifest ();
if (File.Exists (manifestPath))
{
// Use Create to ensure we reflect true load status
Vemanifest.Create (manifestPath);
}
FileResXmlDoc tmp = null;
if (File.Exists (scalePath))
{
tmp = new FileResXmlDoc (scalePath);
}
else
{
// if both missing, try manifest as last resort (ResXmlDoc handles manifest-style layout)
if (File.Exists (manifestPath))
tmp = new FileResXmlDoc (manifestPath);
}
ScaleResources = tmp;
}
catch
{
// swallow exceptions; leave fields null if initialization fails
Vemanifest = new VisualElementManifest ();
ScaleResources = null;
}
}
private static string GetProgramRootDirectory ()
{
try
{
// Prefer the directory of the executing assembly
string codeBase = Assembly.GetExecutingAssembly ().Location;
if (!string.IsNullOrEmpty (codeBase))
{
string dir = Path.GetDirectoryName (codeBase);
if (!string.IsNullOrEmpty (dir)) return dir;
}
}
catch { }
try
{
return AppDomain.CurrentDomain.BaseDirectory ?? Environment.CurrentDirectory;
}
catch { }
return Environment.CurrentDirectory;
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_VisualElement
{
private string _appid;
public _I_VisualElement ()
{
_appid = "App";
}
public _I_VisualElement (string appid)
{
_appid = string.IsNullOrEmpty (appid) ? "App" : appid;
}
public string Id
{
get { return _appid; }
set { _appid = string.IsNullOrEmpty (value) ? "App" : value; }
}
public string DisplayName
{
get { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.DisplayName (_appid) : string.Empty; }
}
public string Logo
{
get { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.Logo (_appid) : string.Empty; }
}
public string SmallLogo
{
get { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.SmallLogo (_appid) : string.Empty; }
}
public string ForegroundText
{
get
{
if (VisualElementsStore.Vemanifest == null) return "dark";
var t = VisualElementsStore.Vemanifest.ForegroundText (_appid);
return t == ManifestTextColor.Light ? "light" : "dark";
}
}
public string Lnk32x32Logo
{
get { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.Lnk32x32Logo (_appid) : string.Empty; }
}
public string ItemDisplayLogo
{
get { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.ItemDisplayLogo (_appid) : string.Empty; }
}
public bool ShowNameOnTile
{
get { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.ShowNameOnTile (_appid) : false; }
}
public string BackgroundColor
{
get { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.BackgroundColor (_appid) : string.Empty; }
}
public string SplashScreenImage
{
get { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.SplashScreenImage (_appid) : string.Empty; }
}
public string SplashScreenBackgroundColor
{
get { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.SplashScreenBackgroundColor (_appid) : string.Empty; }
}
public string SplashScreenBackgroundColorDarkMode
{
get { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.SplashScreenBackgroundColorDarkMode (_appid) : string.Empty; }
}
// Indexer for script-friendly access: v["displayname"]
public object this [string propertyName]
{
get { return Get (propertyName); }
}
// Generic getter by property name (case-insensitive)
public object Get (string propertyName)
{
if (string.IsNullOrEmpty (propertyName)) return string.Empty;
string key = propertyName.Trim ().ToLowerInvariant ();
switch (key)
{
case "displayname": return DisplayName;
case "logo": return Logo;
case "smalllogo": return SmallLogo;
case "foregroundtext": return ForegroundText;
case "lnk32x32logo": return Lnk32x32Logo;
case "itemdisplaylogo": return ItemDisplayLogo;
case "shownameontile": return ShowNameOnTile;
case "backgroundcolor": return BackgroundColor;
case "splashscreenimage": return SplashScreenImage;
case "splashscreenbackgroundcolor": return SplashScreenBackgroundColor;
case "splashscreenbackgroundcolordarkmode": return SplashScreenBackgroundColorDarkMode;
default: return string.Empty;
}
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_VisualElements
{
public string [] GetIds ()
{
try
{
var list = VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.AppIds () : new System.Collections.Generic.List<string> () { "App" };
return list.ToArray ();
}
catch
{
return new string [] { "App" };
}
}
public string GetIdsToJson ()
{
var ids = GetIds ();
// Use Utilities.StringArrayToJson (which uses Newtonsoft.Json if available)
try
{
return Utilities.StringArrayToJson (ids);
}
catch
{
// fallback
return Newtonsoft.Json.JsonConvert.SerializeObject (ids);
}
}
public _I_VisualElement Get (string id)
{
return new _I_VisualElement (id);
}
public _I_VisualElement this [string id]
{
get { return Get (id); }
}
// Attribute-style methods
public string DisplayName (string appid) { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.DisplayName (string.IsNullOrEmpty (appid) ? "App" : appid) : string.Empty; }
public string Logo (string appid) { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.Logo (string.IsNullOrEmpty (appid) ? "App" : appid) : string.Empty; }
public string SmallLogo (string appid) { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.SmallLogo (string.IsNullOrEmpty (appid) ? "App" : appid) : string.Empty; }
public string ForegroundText (string appid)
{
if (VisualElementsStore.Vemanifest == null) return "dark";
var t = VisualElementsStore.Vemanifest.ForegroundText (string.IsNullOrEmpty (appid) ? "App" : appid);
return t == ManifestTextColor.Light ? "light" : "dark";
}
public string Lnk32x32Logo (string appid) { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.Lnk32x32Logo (string.IsNullOrEmpty (appid) ? "App" : appid) : string.Empty; }
public string ItemDisplayLogo (string appid) { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.ItemDisplayLogo (string.IsNullOrEmpty (appid) ? "App" : appid) : string.Empty; }
public bool ShowNameOnTile (string appid) { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.ShowNameOnTile (string.IsNullOrEmpty (appid) ? "App" : appid) : false; }
public string BackgroundColor (string appid) { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.BackgroundColor (string.IsNullOrEmpty (appid) ? "App" : appid) : string.Empty; }
public string SplashScreenImage (string appid) { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.SplashScreenImage (string.IsNullOrEmpty (appid) ? "App" : appid) : string.Empty; }
public string SplashScreenBackgroundColor (string appid) { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.SplashScreenBackgroundColor (string.IsNullOrEmpty (appid) ? "App" : appid) : string.Empty; }
public string SplashScreenBackgroundColorDarkMode (string appid) { return VisualElementsStore.Vemanifest != null ? VisualElementsStore.Vemanifest.SplashScreenBackgroundColorDarkMode (string.IsNullOrEmpty (appid) ? "App" : appid) : string.Empty; }
// Generic getter by attribute name
public object GetValue (string appid, string attributeName)
{
if (string.IsNullOrEmpty (attributeName)) return string.Empty;
string key = attributeName.Trim ().ToLowerInvariant ();
switch (key)
{
case "displayname": return DisplayName (appid);
case "logo": return Logo (appid);
case "smalllogo": return SmallLogo (appid);
case "foregroundtext": return ForegroundText (appid);
case "lnk32x32logo": return Lnk32x32Logo (appid);
case "itemdisplaylogo": return ItemDisplayLogo (appid);
case "shownameontile": return ShowNameOnTile (appid);
case "backgroundcolor": return BackgroundColor (appid);
case "splashscreenimage": return SplashScreenImage (appid);
case "splashscreenbackgroundcolor": return SplashScreenBackgroundColor (appid);
case "splashscreenbackgroundcolordarkmode": return SplashScreenBackgroundColorDarkMode (appid);
default: return string.Empty;
}
}
}
}

80
DataUtils/Taskbar.cs Normal file
View File

@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace DataUtils
{
public enum TBPFLAG
{
TBPF_NOPROGRESS = 0x0,
TBPF_INDETERMINATE = 0x1,
TBPF_NORMAL = 0x2,
TBPF_ERROR = 0x4,
TBPF_PAUSED = 0x8
}
[ComImport]
[Guid ("EA1AFB91-9E28-4B86-90E9-9E9F8A5EEA84")]
[InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
public interface ITaskbarList3
{
void HrInit ();
void AddTab (IntPtr hwnd);
void DeleteTab (IntPtr hwnd);
void ActivateTab (IntPtr hwnd);
void SetActiveAlt (IntPtr hwnd);
void MarkFullscreenWindow (IntPtr hwnd, [MarshalAs (UnmanagedType.Bool)] bool fFullscreen);
void SetProgressValue (IntPtr hwnd, ulong ullCompleted, ulong ullTotal);
void SetProgressState (IntPtr hwnd, TBPFLAG tbpFlags);
void RegisterTab (IntPtr hwndTab, IntPtr hwndMDI);
void UnregisterTab (IntPtr hwndTab);
void SetTabOrder (IntPtr hwndTab, IntPtr hwndInsertBefore);
void SetTabActive (IntPtr hwndTab, IntPtr hwndMDI, uint dwReserved);
void ThumbBarAddButtons (IntPtr hwnd, uint cButtons, IntPtr pButtons);
void ThumbBarUpdateButtons (IntPtr hwnd, uint cButtons, IntPtr pButtons);
void ThumbBarSetImageList (IntPtr hwnd, IntPtr himl);
void SetOverlayIcon (IntPtr hwnd, IntPtr hIcon, string pszDescription);
void SetThumbnailTooltip (IntPtr hwnd, string pszTip);
void SetThumbnailClip (IntPtr hwnd, ref RECT prcClip);
}
[ComImport]
[Guid ("56FDF344-FD6D-11d0-958A-006097C9A090")]
public class TaskbarList { }
[StructLayout (LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
public sealed class TaskbarProgress: IDisposable
{
private readonly ITaskbarList3 _taskbar;
private readonly IntPtr _hwnd;
public TaskbarProgress (IntPtr hwnd)
{
_hwnd = hwnd;
_taskbar = (ITaskbarList3)new TaskbarList ();
_taskbar.HrInit ();
}
public void SetState (TBPFLAG state)
{
_taskbar.SetProgressState (_hwnd, state);
}
public void SetValue (ulong completed, ulong total)
{
_taskbar.SetProgressValue (_hwnd, completed, total);
}
public void Clear ()
{
_taskbar.SetProgressState (_hwnd, TBPFLAG.TBPF_NOPROGRESS);
}
public void Dispose ()
{
Clear ();
Marshal.ReleaseComObject (_taskbar);
}
}
}

362
DataUtils/Theme.cs Normal file
View File

@@ -0,0 +1,362 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using Microsoft.Win32;
namespace DataUtils
{
public enum HighContrastTheme
{
None,
Black,
White,
Other
}
public static class UITheme
{
// --- P/Invoke & constants ---
private const int SPI_GETHIGHCONTRAST = 0x0042;
private const uint HCF_HIGHCONTRASTON = 0x00000001;
private const int COLOR_WINDOW = 5;
private const int COLOR_WINDOWTEXT = 8;
private const int LOGPIXELSX = 88; // GetDeviceCaps index for DPI X
// private const int HORZRES = 8; // not used now
private const int SM_CXSCREEN = 0;
private const int SM_CYSCREEN = 1;
[StructLayout (LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct HIGHCONTRAST
{
public int cbSize;
public uint dwFlags;
public IntPtr lpszDefaultScheme;
}
[DllImport ("user32.dll", SetLastError = true)]
private static extern bool SystemParametersInfo (int uiAction, int uiParam, ref HIGHCONTRAST pvParam, int fWinIni);
[DllImport ("user32.dll")]
private static extern int GetSysColor (int nIndex);
[DllImport ("user32.dll")]
private static extern int GetSystemMetrics (int nIndex);
[DllImport ("user32.dll")]
private static extern IntPtr GetDC (IntPtr hWnd);
[DllImport ("user32.dll")]
private static extern int ReleaseDC (IntPtr hWnd, IntPtr hDC);
[DllImport ("gdi32.dll")]
private static extern int GetDeviceCaps (IntPtr hdc, int nIndex);
// DwmGetColorizationColor
[DllImport ("dwmapi.dll", EntryPoint = "DwmGetColorizationColor", SetLastError = false)]
private static extern int DwmGetColorizationColor (out uint pcrColorization, out bool pfOpaqueBlend);
// --- Methods ---
public static bool IsHighContrastEnabled ()
{
try
{
HIGHCONTRAST hc = new HIGHCONTRAST ();
hc.cbSize = Marshal.SizeOf (typeof (HIGHCONTRAST));
if (SystemParametersInfo (SPI_GETHIGHCONTRAST, hc.cbSize, ref hc, 0))
{
return (hc.dwFlags & HCF_HIGHCONTRASTON) != 0;
}
}
catch
{
// ignore errors
}
return false;
}
public static bool IsHighContrast => IsHighContrastEnabled ();
public static HighContrastTheme GetHighContrastTheme ()
{
try
{
HIGHCONTRAST hc = new HIGHCONTRAST ();
hc.cbSize = Marshal.SizeOf (typeof (HIGHCONTRAST));
if (!SystemParametersInfo (SPI_GETHIGHCONTRAST, hc.cbSize, ref hc, 0))
return HighContrastTheme.None;
if ((hc.dwFlags & HCF_HIGHCONTRASTON) == 0)
return HighContrastTheme.None;
int bgColorRef = GetSysColor (COLOR_WINDOW);
int textColorRef = GetSysColor (COLOR_WINDOWTEXT);
int bgR = (bgColorRef & 0x0000FF);
int bgG = (bgColorRef & 0x00FF00) >> 8;
int bgB = (bgColorRef & 0xFF0000) >> 16;
int txtR = (textColorRef & 0x0000FF);
int txtG = (textColorRef & 0x00FF00) >> 8;
int txtB = (textColorRef & 0xFF0000) >> 16;
int brightnessBg = (bgR + bgG + bgB) / 3;
int brightnessText = (txtR + txtG + txtB) / 3;
if (brightnessBg < brightnessText) return HighContrastTheme.Black;
else if (brightnessBg > brightnessText) return HighContrastTheme.White;
else return HighContrastTheme.Other;
}
catch
{
return HighContrastTheme.None;
}
}
public static HighContrastTheme HighContrast => GetHighContrastTheme ();
// Returns DPI as percent (100 = normal 96 DPI)
public static int GetDPI ()
{
IntPtr hdc = IntPtr.Zero;
try
{
hdc = GetDC (IntPtr.Zero);
if (hdc == IntPtr.Zero) return 0;
int dpiX = GetDeviceCaps (hdc, LOGPIXELSX);
if (dpiX <= 0) return 0;
// convert to percentage of 96 DPI baseline
int percent = (int)Math.Round ((dpiX / 96.0) * 100.0);
return percent;
}
catch
{
return 0;
}
finally
{
if (hdc != IntPtr.Zero) ReleaseDC (IntPtr.Zero, hdc);
}
}
public static int DPI => GetDPI ();
public static double DPIDouble => GetDPI () * 0.01;
public static int GetScreenWidth ()
{
try { return GetSystemMetrics (SM_CXSCREEN); }
catch { return 0; }
}
public static int ScreenWidth => GetScreenWidth ();
public static int GetScreenHeight ()
{
try { return GetSystemMetrics (SM_CYSCREEN); }
catch { return 0; }
}
public static int ScreenHeight => GetScreenHeight ();
public static Color GetDwmThemeColor ()
{
try
{
uint color;
bool opaque;
int hr = DwmGetColorizationColor (out color, out opaque);
if (hr == 0) // S_OK
{
byte r = (byte)((color & 0x00FF0000) >> 16);
byte g = (byte)((color & 0x0000FF00) >> 8);
byte b = (byte)(color & 0x000000FF);
return Color.FromArgb (r, g, b);
}
}
catch
{
// ignored
}
// fallback default (matches original C++ fallback)
return Color.FromArgb (0, 120, 215);
}
public static Color ThemeColor => GetDwmThemeColor ();
public static string ColorToHtml (Color color)
{
// Return #RRGGBB
return string.Format ("#{0:X2}{1:X2}{2:X2}", color.R, color.G, color.B);
}
public static Color StringToColor (string colorStr)
{
if (string.IsNullOrWhiteSpace (colorStr)) return Color.Transparent;
string s = colorStr.Trim ();
// Named color
try
{
Color byName = Color.FromName (s);
if (byName.IsKnownColor || byName.IsNamedColor)
{
return byName;
}
}
catch { /* ignore */ }
// Hex: #RGB, #RRGGBB, #AARRGGBB
if (s.StartsWith ("#"))
{
string hex = s.Substring (1);
// Expand short forms (#RGB or #RGBA)
if (hex.Length == 3 || hex.Length == 4)
{
string expanded = "";
for (int i = 0; i < hex.Length; i++)
{
expanded += hex [i].ToString () + hex [i].ToString ();
}
hex = expanded;
}
uint argb;
try
{
argb = Convert.ToUInt32 (hex, 16);
}
catch
{
return Color.Transparent;
}
if (hex.Length == 6)
{
int r = (int)((argb >> 16) & 0xFF);
int g = (int)((argb >> 8) & 0xFF);
int b = (int)(argb & 0xFF);
return Color.FromArgb (r, g, b);
}
else if (hex.Length == 8)
{
int a = (int)((argb >> 24) & 0xFF);
int r = (int)((argb >> 16) & 0xFF);
int g = (int)((argb >> 8) & 0xFF);
int b = (int)(argb & 0xFF);
return Color.FromArgb (a, r, g, b);
}
else
{
return Color.Transparent;
}
}
// rgb()/rgba() functional notation
// Accept forms like: rgb(255,0,0) or rgba(255,0,0,0.5) or rgb(100%,0%,0%)
var m = Regex.Match (s, @"^(rgba?)\s*\(\s*([^\)]+)\s*\)$", RegexOptions.IgnoreCase);
if (m.Success)
{
string func = m.Groups [1].Value.ToLowerInvariant ();
string inside = m.Groups [2].Value;
string [] parts = inside.Split (new char [] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length >= 3)
{
try
{
Func<string, int> comp = (string v) => {
v = v.Trim ();
if (v.EndsWith ("%"))
{
// percentage
string num = v.TrimEnd ('%');
float p;
if (float.TryParse (num, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out p))
{
return (int)Math.Round (Math.Max (0, Math.Min (100, p)) * 255.0 / 100.0);
}
return 0;
}
else
{
int iv;
if (int.TryParse (v, out iv))
{
return Math.Max (0, Math.Min (255, iv));
}
// fallback parse float
float fv;
if (float.TryParse (v, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out fv))
{
return Math.Max (0, Math.Min (255, (int)Math.Round (fv)));
}
return 0;
}
};
int r = comp (parts [0]);
int g = comp (parts [1]);
int b = comp (parts [2]);
int a = 255;
if (func == "rgba" && parts.Length >= 4)
{
string av = parts [3].Trim ();
if (av.EndsWith ("%"))
{
string num = av.TrimEnd ('%');
float p;
if (float.TryParse (num, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out p))
{
a = (int)Math.Round (Math.Max (0, Math.Min (100, p)) * 255.0 / 100.0);
}
}
else
{
// alpha may be 0..1 or 0..255
float af;
if (float.TryParse (av, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out af))
{
if (af <= 1.0f) a = (int)Math.Round (Math.Max (0.0f, Math.Min (1.0f, af)) * 255.0f);
else a = (int)Math.Round (Math.Max (0.0f, Math.Min (255.0f, af)));
}
}
}
return Color.FromArgb (a, r, g, b);
}
catch
{
return Color.Transparent;
}
}
}
// fallback: try parse as known color again (case-insensitive)
try
{
Color named = Color.FromName (s);
if (named.IsKnownColor || named.IsNamedColor) return named;
}
catch { }
return Color.Transparent;
}
public static bool IsAppInDarkMode ()
{
try
{
// HKCU\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize\AppsUseLightTheme
object val = Registry.GetValue (
@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize",
"AppsUseLightTheme",
null);
if (val == null) return false; // default to light? original returned false
int intVal;
if (val is int) intVal = (int)val;
else
{
if (!int.TryParse (val.ToString (), out intVal)) return false;
}
// 0 => dark, 1 => light
return intVal == 0;
}
catch
{
return false;
}
}
public static bool AppDarkMode => IsAppInDarkMode ();
}
}

185
DataUtils/Utils.cs Normal file
View File

@@ -0,0 +1,185 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using Newtonsoft.Json;
namespace DataUtils
{
public static class Utilities
{
// Format string with args (compatible with your C++ FormatString wrapper)
public static string FormatString (string fmt, params object [] args)
{
if (fmt == null) return string.Empty;
if (args == null || args.Length == 0) return fmt;
try
{
return string.Format (System.Globalization.CultureInfo.InvariantCulture, fmt, args);
}
catch
{
// On format error, fallback to simple concat
try
{
StringBuilder sb = new StringBuilder ();
sb.Append (fmt);
sb.Append (" : ");
for (int i = 0; i < args.Length; i++)
{
if (i > 0) sb.Append (", ");
sb.Append (args [i] != null ? args [i].ToString () : "null");
}
return sb.ToString ();
}
catch
{
return fmt;
}
}
}
// Escape string to be used as InnerXml content (returns XML-escaped content)
public static string EscapeToInnerXml (string str)
{
if (str == null) return string.Empty;
var doc = new XmlDocument ();
// create a root element and use InnerText to perform escaping
var root = doc.CreateElement ("body");
root.InnerText = str;
return root.InnerXml;
}
// Returns the current process full path (exe)
public static string GetCurrentProgramPath ()
{
try
{
return System.Diagnostics.Process.GetCurrentProcess ().MainModule.FileName;
}
catch
{
try
{
return System.Reflection.Assembly.GetEntryAssembly ().Location;
}
catch
{
return AppDomain.CurrentDomain.BaseDirectory;
}
}
}
// JSON array builder using Newtonsoft.Json
public static string StringArrayToJson (string [] values)
{
if (values == null) return "[]";
try
{
return JsonConvert.SerializeObject (values);
}
catch
{
// Fallback to manual builder
StringBuilder sb = new StringBuilder ();
sb.Append ('[');
for (int i = 0; i < values.Length; i++)
{
if (i > 0) sb.Append (',');
sb.Append ('"');
sb.Append (JsonEscape (values [i] ?? string.Empty));
sb.Append ('"');
}
sb.Append (']');
return sb.ToString ();
}
}
public static string StringListToJson (System.Collections.Generic.List<string> list)
{
if (list == null) return "[]";
return StringArrayToJson (list.ToArray ());
}
// Minimal JSON string escaper (fallback)
private static string JsonEscape (string s)
{
if (string.IsNullOrEmpty (s)) return s ?? string.Empty;
StringBuilder sb = new StringBuilder (s.Length + 8);
foreach (char c in s)
{
switch (c)
{
case '"': sb.Append ("\\\""); break;
case '\\': sb.Append ("\\\\"); break;
case '\b': sb.Append ("\\b"); break;
case '\f': sb.Append ("\\f"); break;
case '\n': sb.Append ("\\n"); break;
case '\r': sb.Append ("\\r"); break;
case '\t': sb.Append ("\\t"); break;
default:
if (c < 32 || c == '\u2028' || c == '\u2029')
{
sb.AppendFormat ("\\u{0:X4}", (int)c);
}
else
{
sb.Append (c);
}
break;
}
}
return sb.ToString ();
}
// Helper: combine multiple filters split by ';' or '\' (legacy)
public static string [] SplitFilters (string filter)
{
if (string.IsNullOrEmpty (filter)) return new string [] { "*" };
// Accept ';' or '\' or '|' as separators (common)
string [] parts = filter.Split (new char [] { ';', '\\', '|' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < parts.Length; i++)
{
parts [i] = parts [i].Trim ();
if (parts [i].Length == 0) parts [i] = "*";
}
if (parts.Length == 0) return new string [] { "*" };
return parts;
}
// Normalize full path for comparisons
public static string NormalizeFullPath (string path)
{
if (string.IsNullOrEmpty (path)) return string.Empty;
try
{
return Path.GetFullPath (path).TrimEnd (Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
}
catch
{
return path.Trim ();
}
}
// 忽略大小写和首尾空的比较
public static bool NEquals (this string left, string right)
{
return (left ?? "")?.Trim ()?.ToLower ()?.Equals ((right ?? "")?.Trim ()?.ToLower ()) ?? false;
}
public static int NCompareTo (this string l, string r)
{
return (l ?? "")?.Trim ()?.ToLower ().CompareTo ((r ?? "")?.Trim ()?.ToLower ()) ?? 0;
}
public static bool NEmpty (this string l)
{
return (l ?? "")?.NEquals ("") ?? true;
}
public static int NLength (this string l)
{
return (l ?? "")?.Length ?? 0;
}
public static bool NNoEmpty (this string l) => !((l ?? "")?.NEmpty () ?? true);
public static string NNormalize (this string l) => (l ?? "")?.Trim ()?.ToLower () ?? "";
}
}

368
DataUtils/Version.cs Normal file
View File

@@ -0,0 +1,368 @@
using System;
using System.Globalization;
using System.Runtime.InteropServices;
namespace DataUtils
{
/// <summary>
/// Compact version type that encodes 4 x 16-bit parts into a 64-bit value:
/// bits 48..63 = major, 32..47 = minor, 16..31 = build, 0..15 = revision.
/// </summary>
[ComVisible (true)]
public class Version: IComparable<Version>, IEquatable<Version>
{
// Backing fields
private ushort major;
private ushort minor;
private ushort build;
private ushort revision;
public ushort Major
{
get { return major; }
set { major = value; }
}
public ushort Minor
{
get { return minor; }
set { minor = value; }
}
public ushort Build
{
get { return build; }
set { build = value; }
}
public ushort Revision
{
get { return revision; }
set { revision = value; }
}
public Version ()
{
major = minor = build = revision = 0;
}
public Version (ushort major, ushort minor, ushort build, ushort revision)
{
this.major = major;
this.minor = minor;
this.build = build;
this.revision = revision;
}
public Version (ushort major, ushort minor, ushort build) : this (major, minor, build, 0) { }
public Version (ushort major, ushort minor) : this (major, minor, 0, 0) { }
public Version (ushort major) : this (major, 0, 0, 0) { }
public Version (ulong packed)
{
FromUInt64 (packed);
}
public Version (string versionString)
{
ParseInto (versionString);
}
public Version (Version other)
{
if (other == null) throw new ArgumentNullException ("other");
major = other.major;
minor = other.minor;
build = other.build;
revision = other.revision;
}
public ulong ToUInt64 ()
{
// cast to ulong before shifting
return (((ulong)major) << 48) | (((ulong)minor) << 32) | (((ulong)build) << 16) | ((ulong)revision);
}
public void FromUInt64 (ulong value)
{
major = (ushort)((value >> 48) & 0xFFFFUL);
minor = (ushort)((value >> 32) & 0xFFFFUL);
build = (ushort)((value >> 16) & 0xFFFFUL);
revision = (ushort)(value & 0xFFFFUL);
}
public ulong Data { get { return ToUInt64 (); } set { FromUInt64 (value); } }
public override string ToString ()
{
// use string.Format to be compatible with older compilers
return string.Format (CultureInfo.InvariantCulture, "{0}.{1}.{2}.{3}", major, minor, build, revision);
}
public string ToShortString ()
{
// omit trailing zeros if desired: e.g. "1.2" or "1.2.3"
if (revision != 0)
return ToString ();
if (build != 0)
return string.Format (CultureInfo.InvariantCulture, "{0}.{1}.{2}", major, minor, build);
if (minor != 0)
return string.Format (CultureInfo.InvariantCulture, "{0}.{1}", major, minor);
return string.Format (CultureInfo.InvariantCulture, "{0}", major);
}
private void ParseInto (string s)
{
if (string.IsNullOrEmpty (s))
{
major = minor = build = revision = 0;
return;
}
char [] separators = new char [] { '.', ',' };
string [] parts = s.Split (separators, StringSplitOptions.RemoveEmptyEntries);
ushort [] values = new ushort [4];
for (int i = 0; i < values.Length && i < parts.Length; i++)
{
ushort v = 0;
try
{
int parsed = int.Parse (parts [i].Trim (), NumberStyles.Integer, CultureInfo.InvariantCulture);
if (parsed < 0) parsed = 0;
if (parsed > 0xFFFF) parsed = 0xFFFF;
v = (ushort)parsed;
}
catch
{
v = 0;
}
values [i] = v;
}
major = values [0];
minor = values [1];
build = values [2];
revision = values [3];
}
public string Expression { get { return this.ToString (); } set { this.ParseInto (value); } }
public static Version Parse (string s)
{
if (s == null) throw new ArgumentNullException ("s");
return new Version (s);
}
public static bool TryParse (string s, out Version result)
{
result = null;
if (s == null) return false;
try
{
result = new Version (s);
return true;
}
catch
{
result = null;
return false;
}
}
public bool IsEmpty
{
get { return (major == 0 && minor == 0 && build == 0 && revision == 0); }
}
public bool Equals (Version other)
{
if (object.ReferenceEquals (other, null)) return false;
return (this.major == other.major
&& this.minor == other.minor
&& this.build == other.build
&& this.revision == other.revision);
}
public bool Equals (ulong ver) { return this == new Version (ver); }
public override bool Equals (object obj)
{
Version v = obj as Version;
return Equals (v);
}
public override int GetHashCode ()
{
// derive from packed ulong but return int
ulong packed = ToUInt64 ();
// combine high and low 32 bits for a reasonable hash
return ((int)(packed & 0xFFFFFFFF)) ^ ((int)((packed >> 32) & 0xFFFFFFFF));
}
public int CompareTo (Version other)
{
if (object.ReferenceEquals (other, null)) return 1;
// Compare by packed value (same semantics as C++ compare())
ulong a = this.ToUInt64 ();
ulong b = other.ToUInt64 ();
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
public int CompareTo (ulong another) { return this.CompareTo (new Version (another)); }
public long Compare (Version other)
{
if (other == null) throw new ArgumentNullException ("other");
// return signed difference of packed values using long
long diff = (long)this.ToUInt64 () - (long)other.ToUInt64 ();
return diff;
}
public long Compare (ulong another) { return this.Compare (new Version (another)); }
public static bool operator == (Version a, Version b)
{
if (object.ReferenceEquals (a, b)) return true;
if (object.ReferenceEquals (a, null) || object.ReferenceEquals (b, null)) return false;
return a.Equals (b);
}
public static bool operator != (Version a, Version b)
{
return !(a == b);
}
public static bool operator < (Version a, Version b)
{
if (object.ReferenceEquals (a, null))
return !object.ReferenceEquals (b, null); // null < non-null
return a.CompareTo (b) < 0;
}
public static bool operator > (Version a, Version b)
{
if (object.ReferenceEquals (a, null))
return false;
return a.CompareTo (b) > 0;
}
public static bool operator <= (Version a, Version b)
{
if (object.ReferenceEquals (a, b)) return true;
if (object.ReferenceEquals (a, null)) return true; // null <= anything
return a.CompareTo (b) <= 0;
}
public static bool operator >= (Version a, Version b)
{
if (object.ReferenceEquals (a, b)) return true;
if (object.ReferenceEquals (a, null)) return false;
return a.CompareTo (b) >= 0;
}
public static explicit operator ulong (Version v)
{
if (v == null) return 0UL;
return v.ToUInt64 ();
}
public static explicit operator Version (ulong value)
{
return new Version (value);
}
public static Version Decode (ulong packed)
{
return new Version (packed);
}
public static ulong Encode (Version v)
{
if (v == null) return 0UL;
return v.ToUInt64 ();
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_Version
{
private Version inner;
public _I_Version ()
{
inner = new Version ();
}
public _I_Version (ushort p_ma, ushort p_mi, ushort p_b, ushort p_r)
{
inner = new Version (p_ma, p_mi, p_b, p_r);
}
public _I_Version (ushort p_ma, ushort p_mi, ushort p_b) : this (p_ma, p_mi, p_b, 0) { }
public _I_Version (ushort p_ma, ushort p_mi) : this (p_ma, p_mi, 0, 0) { }
public _I_Version (ushort p_ma) : this (p_ma, 0, 0, 0) { }
public ushort Major
{
get { return inner.Major; }
set { inner.Major = value; }
}
public ushort Minor
{
get { return inner.Minor; }
set { inner.Minor = value; }
}
public ushort Build
{
get { return inner.Build; }
set { inner.Build = value; }
}
public ushort Revision
{
get { return inner.Revision; }
set { inner.Revision = value; }
}
public ushort [] Data
{
get
{
return new ushort [] { inner.Major, inner.Minor, inner.Build, inner.Revision };
}
set
{
if (value == null)
{
inner.Major = inner.Minor = inner.Build = inner.Revision = 0;
return;
}
if (value.Length > 0) inner.Major = value [0];
else inner.Major = 0;
if (value.Length > 1) inner.Minor = value [1];
else inner.Minor = 0;
if (value.Length > 2) inner.Build = value [2];
else inner.Build = 0;
if (value.Length > 3) inner.Revision = value [3];
else inner.Revision = 0;
}
}
public string DataStr
{
get { return Stringify (); }
set { Parse (value); }
}
public _I_Version Parse (string ver)
{
if (string.IsNullOrEmpty (ver))
{
inner = new Version ();
return this;
}
char [] separators = new char [] { '.', ',' };
string [] parts = ver.Split (separators, StringSplitOptions.RemoveEmptyEntries);
ushort [] vals = new ushort [4];
for (int i = 0; i < vals.Length && i < parts.Length; i++)
{
ushort v = 0;
try
{
int parsed = int.Parse (parts [i].Trim (), NumberStyles.Integer, CultureInfo.InvariantCulture);
if (parsed < 0) parsed = 0;
if (parsed > 0xFFFF) parsed = 0xFFFF;
v = (ushort)parsed;
}
catch
{
v = 0;
}
vals [i] = v;
}
inner.Major = vals [0];
inner.Minor = vals [1];
inner.Build = vals [2];
inner.Revision = vals [3];
return this;
}
public string Stringify ()
{
return inner.ToString ();
}
public override string ToString ()
{
return Stringify ();
}
public bool Valid ()
{
return inner.Major != 0 && inner.Minor != 0 && inner.Build != 0 && inner.Revision != 0;
}
public ulong ToPackedUInt64 ()
{
return inner.ToUInt64 ();
}
public void FromPackedUInt64 (ulong packed)
{
inner.FromUInt64 (packed);
}
public Version InnerVersion
{
get { return inner; }
set { inner = (value != null) ? new Version (value) : new Version (); }
}
}
}

280
DataUtils/VisualElements.cs Normal file
View File

@@ -0,0 +1,280 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Xml;
namespace DataUtils
{
public enum ManifestTextColor
{
Dark = 0x000000,
Light = 0xFFFFFF
}
[ComVisible (true)]
public class VisualElementManifest: IDisposable
{
private XmlDocument _doc;
private bool _available;
public VisualElementManifest ()
{
_available = false;
}
public VisualElementManifest (string filename)
{
Create (filename);
}
public VisualElementManifest (Stream stream)
{
Create (stream);
}
public bool Create (string filename)
{
Destroy ();
if (string.IsNullOrEmpty (filename) || !File.Exists (filename))
{
_available = false;
return false;
}
try
{
_doc = new XmlDocument ();
// Load using UTF-8/UTF-16 auto-detection
_doc.Load (filename);
_available = true;
}
catch
{
_available = false;
}
return _available;
}
public bool Create (Stream stream)
{
Destroy ();
if (stream == null) { _available = false; return false; }
try
{
_doc = new XmlDocument ();
_doc.Load (stream);
_available = true;
}
catch
{
_available = false;
}
return _available;
}
public void Destroy ()
{
if (!_available) return;
_doc = null;
_available = false;
}
public bool Valid { get { return _available; } }
// Helper: find VisualElements node for an app id (if root is <Applications> iterate <Application> children)
private XmlNode VisualElementNode (string id)
{
if (!_available || _doc == null) return null;
XmlElement root = _doc.DocumentElement;
if (root == null) return null;
string rootName = root.Name;
if (string.Equals (rootName, "Applications", StringComparison.OrdinalIgnoreCase))
{
foreach (XmlNode app in root.SelectNodes ("Application"))
{
var attr = app.Attributes? ["Id"];
if (attr != null && string.Equals (attr.Value, id, StringComparison.OrdinalIgnoreCase))
{
return app.SelectSingleNode ("VisualElements");
}
}
return null;
}
else if (string.Equals (rootName, "Application", StringComparison.OrdinalIgnoreCase))
{
return root.SelectSingleNode ("VisualElements");
}
return null;
}
// Utility to get attribute string safely
private static string Attr (XmlNode node, string attrName)
{
if (node == null || node.Attributes == null) return string.Empty;
var a = node.Attributes [attrName];
return a != null ? a.Value : string.Empty;
}
public string DisplayName (string id = "App")
{
var visual = VisualElementNode (id);
return visual != null ? Attr (visual, "DisplayName") : string.Empty;
}
public string Logo (string id = "App")
{
var visual = VisualElementNode (id);
if (visual == null) return string.Empty;
string logo = Attr (visual, "Logo");
if (!string.IsNullOrEmpty (logo)) return logo;
return Attr (visual, "Square150x150Logo") ?? string.Empty;
}
public string SmallLogo (string id = "App")
{
var visual = VisualElementNode (id);
if (visual == null) return string.Empty;
string small = Attr (visual, "SmallLogo");
if (!string.IsNullOrEmpty (small)) return small;
return Attr (visual, "Square70x70Logo") ?? string.Empty;
}
public ManifestTextColor ForegroundText (string id = "App")
{
var visual = VisualElementNode (id);
if (visual == null) return ManifestTextColor.Dark;
string fg = Attr (visual, "ForegroundText");
return string.Equals (fg, "light", StringComparison.OrdinalIgnoreCase) ? ManifestTextColor.Light : ManifestTextColor.Dark;
}
public string Lnk32x32Logo (string id = "App")
{
var visual = VisualElementNode (id);
return visual != null ? Attr (visual, "Lnk32x32Logo") : string.Empty;
}
public string ItemDisplayLogo (string id = "App")
{
var visual = VisualElementNode (id);
if (visual == null) return string.Empty;
string item = Attr (visual, "ItemDisplayLogo");
if (!string.IsNullOrEmpty (item)) return item;
item = Attr (visual, "Lnk32x32Logo");
if (!string.IsNullOrEmpty (item)) return item;
return Attr (visual, "Square44x44Logo") ?? string.Empty;
}
public bool ShowNameOnTile (string id = "App")
{
var visual = VisualElementNode (id);
if (visual == null) return false;
string val = Attr (visual, "ShowNameOnSquare150x150Logo");
return string.Equals (val, "on", StringComparison.OrdinalIgnoreCase);
}
public string BackgroundColor (string id = "App")
{
var visual = VisualElementNode (id);
return visual != null ? Attr (visual, "BackgroundColor") : string.Empty;
}
public string SplashScreenImage (string id = "App")
{
var visual = VisualElementNode (id);
if (visual == null) return string.Empty;
var splash = visual.SelectSingleNode ("SplashScreen");
return splash != null ? Attr (splash, "Image") : string.Empty;
}
public string SplashScreenBackgroundColor (string id = "App")
{
var visual = VisualElementNode (id);
if (visual == null) return string.Empty;
var splash = visual.SelectSingleNode ("SplashScreen");
string bg = splash != null ? Attr (splash, "BackgroundColor") : string.Empty;
if (!string.IsNullOrEmpty (bg)) return bg;
return Attr (visual, "BackgroundColor") ?? string.Empty;
}
public string SplashScreenBackgroundColorDarkMode (string id = "App")
{
var visual = VisualElementNode (id);
if (visual == null) return string.Empty;
var splash = visual.SelectSingleNode ("SplashScreen");
string bg = splash != null ? Attr (splash, "DarkModeBackgroundColor") : string.Empty;
if (!string.IsNullOrEmpty (bg)) return bg;
return Attr (visual, "DarkModeBackgroundColor") ?? string.Empty;
}
// Check if an app id exists in document
public bool IsAppIdExists (string id)
{
if (!_available || _doc == null) return false;
XmlElement root = _doc.DocumentElement;
if (root == null) return false;
if (string.Equals (root.Name, "Applications", StringComparison.OrdinalIgnoreCase))
{
foreach (XmlNode app in root.SelectNodes ("Application"))
{
var attr = app.Attributes? ["Id"];
if (attr != null && string.Equals (attr.Value, id, StringComparison.OrdinalIgnoreCase))
return true;
}
return false;
}
else if (string.Equals (root.Name, "Application", StringComparison.OrdinalIgnoreCase))
{
var attr = root.Attributes? ["Id"];
if (attr != null && string.Equals (attr.Value, id, StringComparison.OrdinalIgnoreCase)) return true;
}
return false;
}
// Get all application ids as a list
public List<string> AppIds ()
{
var output = new List<string> ();
if (!_available || _doc == null)
{
output.Add ("App");
return output;
}
XmlElement root = _doc.DocumentElement;
if (root == null)
{
output.Add ("App");
return output;
}
if (string.Equals (root.Name, "Applications", StringComparison.OrdinalIgnoreCase))
{
foreach (XmlNode app in root.SelectNodes ("Application"))
{
var attr = app.Attributes? ["Id"];
if (attr != null && !string.IsNullOrEmpty (attr.Value))
{
if (!output.Contains (attr.Value)) output.Add (attr.Value);
}
}
}
else if (string.Equals (root.Name, "Application", StringComparison.OrdinalIgnoreCase))
{
var attr = root.Attributes? ["Id"];
if (attr != null && !string.IsNullOrEmpty (attr.Value))
{
if (!output.Contains (attr.Value)) output.Add (attr.Value);
}
}
if (output.Count == 0) output.Add ("App");
return output;
}
public void Dispose ()
{
Destroy ();
}
}
}

40
DataUtils/WebBrowser.cs Normal file
View File

@@ -0,0 +1,40 @@
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace DataUtils
{
public enum OLECMDID
{
OLECMDID_OPTICAL_ZOOM = 63
}
public enum OLECMDEXECOPT
{
OLECMDEXECOPT_DODEFAULT = 0,
OLECMDEXECOPT_DONTPROMPTUSER = 2
}
[ComImport]
[Guid ("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E")]
[InterfaceType (ComInterfaceType.InterfaceIsIDispatch)]
public interface IWebBrowser2
{
[DispId (0x000001F4)]
void ExecWB (
OLECMDID cmdID,
OLECMDEXECOPT cmdexecopt,
ref object pvaIn,
ref object pvaOut
);
}
public static class WebBrowserHelper
{
public static IWebBrowser2 GetWebBrowser2 (WebBrowser browser)
{
return browser.ActiveXInstance as IWebBrowser2;
}
}
public interface IWebBrowserPageScale
{
int PageScale { get; set; }
}
}

73
DataUtils/Window.cs Normal file
View File

@@ -0,0 +1,73 @@
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace DataUtils
{
public class _I_UI_Size
{
private int m_width;
private int m_height;
public _I_UI_Size (int w, int h)
{
m_width = w;
m_height = h;
}
public int Width => m_width;
public int Height => m_height;
public int GetWidth () => m_width;
public int GetHeight () => m_height;
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_UI
{
private Form wndInst;
public _I_UI (Form wnd)
{
wndInst = wnd;
}
public int DPIPercent => UITheme.GetDPI ();
public double DPI => DPIPercent * 0.01;
public _I_UI_Size WndSize => new _I_UI_Size (wndInst.Width, wndInst.Height);
public _I_UI_Size ClientSize
{
get
{
var cs = wndInst.ClientSize;
return new _I_UI_Size (cs.Width, cs.Height);
}
}
public string ThemeColor => UITheme.ColorToHtml (UITheme.GetDwmThemeColor ());
public bool DarkMode => UITheme.IsAppInDarkMode ();
public string HighContrast
{
get
{
switch (UITheme.GetHighContrastTheme ())
{
case HighContrastTheme.None: return "none";
case HighContrastTheme.Black: return "black";
case HighContrastTheme.White: return "white";
case HighContrastTheme.Other: return "high";
default: return "none";
}
}
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_Window
{
private IScriptBridge iscrp;
public _I_Window (IScriptBridge _iscrp)
{
iscrp = _iscrp;
}
public object CallEvent (string name, params object [] args)
{
if (iscrp == null) return null;
object arg0 = (args != null && args.Length > 0) ? args [0] : null;
return iscrp.CallEvent (name, arg0);
}
}
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="13.0.4" targetFramework="net40" />
</packages>

Binary file not shown.

View File

@@ -1,3 +1,3 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
</configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/></startup></configuration>

236
PrivateInit/InitHelper.cs Normal file
View File

@@ -0,0 +1,236 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace InitFileHelper
{
public static class IniFile
{
[DllImport ("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern uint GetPrivateProfileStringA (string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, uint nSize, string lpFileName);
[DllImport ("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern uint GetPrivateProfileStringW (string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, uint nSize, string lpFileName);
[DllImport ("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern uint GetPrivateProfileSectionA (string lpAppName, byte [] lpReturnedString, uint nSize, string lpFileName);
[DllImport ("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern uint GetPrivateProfileSectionW (string lpAppName, char [] lpReturnedString, uint nSize, string lpFileName);
[DllImport ("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern uint GetPrivateProfileSectionNamesA (byte [] lpszReturnBuffer, uint nSize, string lpFileName);
[DllImport ("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern uint GetPrivateProfileSectionNamesW (char [] lpszReturnBuffer, uint nSize, string lpFileName);
[DllImport ("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern uint GetPrivateProfileIntA (string lpAppName, string lpKeyName, int nDefault, string lpFileName);
[DllImport ("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern uint GetPrivateProfileIntW (string lpAppName, string lpKeyName, int nDefault, string lpFileName);
[DllImport ("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern bool WritePrivateProfileStringA (string lpAppName, string lpKeyName, string lpString, string lpFileName);
[DllImport ("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern bool WritePrivateProfileStringW (string lpAppName, string lpKeyName, string lpString, string lpFileName);
[DllImport ("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern bool WritePrivateProfileSectionA (string lpAppName, string lpString, string lpFileName);
[DllImport ("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern bool WritePrivateProfileSectionW (string lpAppName, string lpString, string lpFileName);
[DllImport ("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern bool GetPrivateProfileStructA (string lpAppName, string lpKeyName, IntPtr lpStruct, uint uSize, string lpFileName);
[DllImport ("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern bool GetPrivateProfileStructW (string lpAppName, string lpKeyName, IntPtr lpStruct, uint uSize, string lpFileName);
[DllImport ("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern bool WritePrivateProfileStructA (string lpAppName, string lpKeyName, IntPtr lpStruct, uint uSize, string lpFileName);
[DllImport ("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern bool WritePrivateProfileStructW (string lpAppName, string lpKeyName, IntPtr lpStruct, uint uSize, string lpFileName);
public static string GetPrivateProfileStringA (string filePath, string section, string key, string defaultValue = "")
{
StringBuilder buf = new StringBuilder (32768);
GetPrivateProfileStringA (section, key, defaultValue, buf, (uint)buf.Capacity, filePath);
return buf.ToString ();
}
public static string GetPrivateProfileStringW (string filePath, string section, string key, string defaultValue = "")
{
StringBuilder buf = new StringBuilder (32768);
GetPrivateProfileStringW (section, key, defaultValue, buf, (uint)buf.Capacity, filePath);
return buf.ToString ();
}
public static uint GetPrivateProfileIntA (string filePath, string section, string key, int defaultValue = 0)
{
return GetPrivateProfileIntA (section, key, defaultValue, filePath);
}
public static uint GetPrivateProfileIntW (string filePath, string section, string key, int defaultValue = 0)
{
return GetPrivateProfileIntW (section, key, defaultValue, filePath);
}
public static bool WritePrivateProfileString (string filePath, string section, string key, string value)
{
return WritePrivateProfileStringW (section, key, value, filePath);
}
public static int GetPrivateProfileSectionA (string filePath, string section, List<string> output)
{
byte [] buf = new byte [32768];
uint len = GetPrivateProfileSectionA (section, buf, (uint)buf.Length, filePath);
output.Clear ();
if (len == 0) return 0;
int i = 0;
while (i < len)
{
int start = i;
while (i < len && buf [i] != 0) i++;
if (i > start) output.Add (Encoding.Default.GetString (buf, start, i - start));
i++;
}
return output.Count;
}
public static int GetPrivateProfileSectionW (string filePath, string section, List<string> output)
{
char [] buf = new char [32768];
uint len = GetPrivateProfileSectionW (section, buf, (uint)buf.Length, filePath);
output.Clear ();
if (len == 0) return 0;
int i = 0;
while (i < len)
{
int start = i;
while (i < len && buf [i] != '\0') i++;
if (i > start) output.Add (new string (buf, start, i - start));
i++;
}
return output.Count;
}
public static int GetPrivateProfileSectionNamesA (string filePath, List<string> output)
{
byte [] buf = new byte [32768];
uint len = GetPrivateProfileSectionNamesA (buf, (uint)buf.Length, filePath);
output.Clear ();
if (len == 0) return 0;
int i = 0;
while (i < len)
{
int start = i;
while (i < len && buf [i] != 0) i++;
if (i > start) output.Add (Encoding.Default.GetString (buf, start, i - start));
i++;
}
return output.Count;
}
public static int GetPrivateProfileSectionNamesW (string filePath, List<string> output)
{
char [] buf = new char [32768];
uint len = GetPrivateProfileSectionNamesW (buf, (uint)buf.Length, filePath);
output.Clear ();
if (len == 0) return 0;
int i = 0;
while (i < len)
{
int start = i;
while (i < len && buf [i] != '\0') i++;
if (i > start) output.Add (new string (buf, start, i - start));
i++;
}
return output.Count;
}
public static bool WritePrivateProfileSectionA (string filePath, string section, List<string> lines)
{
string buf = string.Join ("\0", lines) + "\0\0";
return WritePrivateProfileSectionA (section, buf, filePath);
}
public static bool WritePrivateProfileSectionW (string filePath, string section, List<string> lines)
{
string buf = string.Join ("\0", lines) + "\0\0";
return WritePrivateProfileSectionW (section, buf, filePath);
}
public static bool GetPrivateProfileStructA (string filePath, string section, string key, IntPtr output, uint size)
{
return GetPrivateProfileStructA (section, key, output, size, filePath);
}
public static bool GetPrivateProfileStructW (string filePath, string section, string key, IntPtr output, uint size)
{
return GetPrivateProfileStructW (section, key, output, size, filePath);
}
public static bool WritePrivateProfileStructA (string filePath, string section, string key, IntPtr data, uint size)
{
return WritePrivateProfileStructA (section, key, data, size, filePath);
}
public static bool WritePrivateProfileStructW (string filePath, string section, string key, IntPtr data, uint size)
{
return WritePrivateProfileStructW (section, key, data, size, filePath);
}
public static int GetPrivateProfileKeysA (string filePath, string section, List<string> keys)
{
List<string> lines = new List<string> ();
int count = GetPrivateProfileSectionA (filePath, section, lines);
keys.Clear ();
foreach (var line in lines)
{
int pos = line.IndexOf ('=');
if (pos != -1) keys.Add (line.Substring (0, pos));
}
return keys.Count;
}
public static int GetPrivateProfileKeysW (string filePath, string section, List<string> keys)
{
List<string> lines = new List<string> ();
int count = GetPrivateProfileSectionW (filePath, section, lines);
keys.Clear ();
foreach (var line in lines)
{
int pos = line.IndexOf ('=');
if (pos != -1) keys.Add (line.Substring (0, pos));
}
return keys.Count;
}
public static bool DeletePrivateProfileKeyA (string filePath, string section, string key)
{
return WritePrivateProfileStringA (section, key, null, filePath);
}
public static bool DeletePrivateProfileKeyW (string filePath, string section, string key)
{
return WritePrivateProfileStringW (section, key, null, filePath);
}
public static bool DeletePrivateProfileSectionA (string filePath, string section)
{
return WritePrivateProfileStringA (section, null, null, filePath);
}
public static bool DeletePrivateProfileSectionW (string filePath, string section)
{
return WritePrivateProfileStringW (section, null, null, filePath);
}
}
[ComVisible (true)]
public static class BoolHelper
{
public static readonly string [] trueValue =
{
"true", "zhen", "yes", "真", "1"
};
public static readonly string [] falseValue =
{
"false", "jia", "no", "假", "0"
};
public static bool ConvertToBool (string str)
{
if (str == null) throw new ArgumentNullException (nameof (str));
str = str.Trim ().ToLowerInvariant ();
if (trueValue.Any (s => s.ToLowerInvariant () == str)) return true;
if (falseValue.Any (s => s.ToLowerInvariant () == str)) return false;
throw new FormatException ($"Cannot convert '{str}' to bool.");
}
public static bool TryParseBool (string str, out bool result)
{
result = false;
if (str == null) return false;
str = str.Trim ().ToLowerInvariant ();
if (trueValue.Any (s => s.ToLowerInvariant () == str))
{
result = true;
return true;
}
if (falseValue.Any (s => s.ToLowerInvariant () == str))
{
result = false;
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" 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>{8E708D9A-6325-4AA9-B5A5-D1B5ECA8EEF7}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>PrivateInit</RootNamespace>
<AssemblyName>PrivateInit</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<RegisterForComInterop>false</RegisterForComInterop>
</PropertyGroup>
<ItemGroup>
<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.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="InitHelper.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Win32.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle ("初始化配置文件读取")]
[assembly: AssemblyDescription ("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany ("Windows Modern")]
[assembly: AssemblyProduct ("Windows 现代风格实用工具")]
[assembly: AssemblyCopyright ("Copyright © 2026 Windows Modern。版权所有。")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//将 ComVisible 设置为 false 将使此程序集中的类型
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible (true)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("8e708d9a-6325-4aa9-b5a5-d1b5eca8eef7")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

198
PrivateInit/Win32.cs Normal file
View File

@@ -0,0 +1,198 @@
using System;
using System.Linq;
using System.Runtime.InteropServices;
using InitFileHelper;
namespace Win32
{
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class RefString
{
public string Value { get; set; }
public RefString (string value) { Value = value; }
public RefString (ref string value) { Value = value; }
public static RefString operator + (RefString a, RefString b)
{
if (ReferenceEquals (a, null)) return b;
if (ReferenceEquals (b, null)) return a;
return new RefString (a.Value + b.Value);
}
public static RefString operator + (RefString a, string b)
{
if (ReferenceEquals (a, null)) return new RefString (b);
return new RefString (a.Value + b);
}
public static RefString operator + (string a, RefString b)
{
if (ReferenceEquals (b, null)) return new RefString (a);
return new RefString (a + b.Value);
}
public static implicit operator RefString (string v) => new RefString (v);
public static implicit operator string (RefString r) => r?.Value;
public static bool operator == (RefString a, RefString b)
{
if (ReferenceEquals (a, b)) return true;
if (ReferenceEquals (a, null) || ReferenceEquals (b, null)) return false;
return a.Value == b.Value;
}
public static bool operator != (RefString a, RefString b) => !(a == b);
public static bool operator == (RefString a, string b)
{
if (ReferenceEquals (a, null)) return b == null;
return a.Value == b;
}
public static bool operator != (RefString a, string b) => !(a == b);
public override bool Equals (object obj)
{
if (obj is RefString) return this == (RefString)obj;
if (obj is string) return this == (string)obj;
return false;
}
public override int GetHashCode () => Value?.GetHashCode () ?? 0;
public override string ToString () => Value;
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class InitKey
{
private RefString filepath = "";
private RefString section = "";
private RefString key = "";
public string FilePath => filepath.Value;
public string Section => section.Value;
public string Key { get { return key; } set { key.Value = value; } }
public InitKey (RefString _fp, RefString _sect, RefString _key)
{
filepath = _fp;
section = _sect;
key = _key;
}
public string ReadString (string dflt = "") { return IniFile.GetPrivateProfileStringW (filepath, section, key, dflt); }
private T ReadTo<T> (T dflt, Func<string, T> convTo)
{
string str = ReadString (dflt?.ToString () ?? "");
try { return convTo (str); }
catch { return dflt; }
}
public short ReadShort (short dflt = 0) { return ReadTo (dflt, Convert.ToInt16); }
public ushort ReadUShort (ushort dflt = 0) { return ReadTo (dflt, Convert.ToUInt16); }
public int ReadInt (int dflt = 0) { return ReadTo (dflt, Convert.ToInt32); }
public uint ReadUInt (uint dflt = 0) { return ReadTo (dflt, Convert.ToUInt32); }
public long ReadLong (long dflt = 0) { return ReadTo (dflt, Convert.ToInt64); }
public ulong ReadULong (ulong dflt = 0) { return ReadTo (dflt, Convert.ToUInt64); }
public Int16 ReadInt16 (Int16 dflt = 0) { return ReadTo (dflt, Convert.ToInt16); }
public UInt16 ReadUInt16 (UInt16 dflt = 0) { return ReadTo (dflt, Convert.ToUInt16); }
public Int32 ReadInt32 (Int32 dflt = 0) { return ReadTo (dflt, Convert.ToInt32); }
public UInt32 ReadUInt32 (UInt32 dflt = 0) { return ReadTo (dflt, Convert.ToUInt32); }
public Int64 ReadInt64 (Int64 dflt = 0) { return ReadTo (dflt, Convert.ToInt64); }
public UInt64 ReadUInt64 (UInt64 dflt = 0) { return ReadTo (dflt, Convert.ToUInt64); }
public bool ReadBool (bool dflt = false) { return ReadTo (dflt, BoolHelper.ConvertToBool); }
public float ReadFloat (float dflt = 0) { return ReadTo (dflt, Convert.ToSingle); }
public double ReadDouble (double dflt = 0) { return ReadTo (dflt, Convert.ToDouble); }
public decimal ReadDecimal (decimal dflt = 0) { return ReadTo (dflt, Convert.ToDecimal); }
public sbyte ReadInt8 (sbyte dflt = 0) { return ReadTo (dflt, Convert.ToSByte); }
public byte ReadUInt8 (byte dflt = 0) { return ReadTo (dflt, Convert.ToByte); }
public byte ReadByte (byte dflt = 0) { return ReadTo (dflt, Convert.ToByte); }
public sbyte ReadSByte (sbyte dflt = 0) { return ReadTo (dflt, Convert.ToSByte); }
public DateTime ReadDateTime (DateTime dflt = default (DateTime)) { return ReadTo (dflt, Convert.ToDateTime); }
public object Get (object dflt) { return ReadString (dflt?.ToString () ?? ""); }
public object Get () { return ReadString (); }
public bool WriteString (string value) { return IniFile.WritePrivateProfileString (filepath, section, key, value); }
public bool Write (string value) { return WriteString (value); }
private bool WriteTo <T> (T value) { return WriteString (value?.ToString ()); }
public bool Write (byte value) { return WriteTo (value); }
public bool Write (sbyte value) { return WriteTo (value); }
public bool Write (short value) { return WriteTo (value); }
public bool Write (ushort value) { return WriteTo (value); }
public bool Write (int value) { return WriteTo (value); }
public bool Write (uint value) { return WriteTo (value); }
public bool Write (long value) { return WriteTo (value); }
public bool Write (ulong value) { return WriteTo (value); }
public bool Write (bool value) { return WriteTo (value); }
public bool Write (float value) { return WriteTo (value); }
public bool Write (double value) { return WriteTo (value); }
public bool Write (decimal value) { return WriteTo (value); }
public bool Write (DateTime value) { return WriteTo (value); }
public bool Set (object value) { return Write (value?.ToString ()); }
public object Value { get { return Get (); } set { Set (value); } }
public bool KeyExists
{
get
{
string val = IniFile.GetPrivateProfileStringW (filepath, section, key, null);
return val != null;
}
}
public bool ValueExists
{
get
{
if (!KeyExists) return false;
string val = IniFile.GetPrivateProfileStringW (filepath, section, key, "");
return !string.IsNullOrEmpty (val);
}
}
public bool DeleteKey () => IniFile.WritePrivateProfileString (filepath, section, key, null);
public bool Clear () => DeleteKey ();
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class InitSection
{
private RefString filepath = "";
private RefString section = "";
public string FilePath => filepath.Value;
public string Section { get { return section; } set { section.Value = value; } }
public InitSection (RefString _fp, RefString _sect)
{
filepath = _fp;
section = _sect;
}
public InitKey GetKey (string key) => new InitKey (filepath, section, key);
public object Get (string key, object dflt = null) => GetKey (key).Get (dflt);
public object Get (string key) => GetKey (key).Get ();
public bool Set (string key, object value) => GetKey (key).Set (value);
public object this [string key]
{
get { return Get (key); }
set { Set (key, value); }
}
public string [] GetAllKeys ()
{
var keys = new System.Collections.Generic.List<string> ();
IniFile.GetPrivateProfileKeysW (filepath, section, keys);
return keys.ToArray ();
}
public InitKey [] Keys
{
get { return GetAllKeys ().Select (k => new InitKey (filepath, section, k)).ToArray (); }
}
public bool DeleteSection () => IniFile.WritePrivateProfileString (filepath, section, null, null);
public bool Clear () => DeleteSection ();
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class InitConfig
{
private RefString filepath = "";
public string FilePath { get { return filepath.Value; } set { filepath.Value = value; } }
public InitConfig (string _fp = "") { FilePath = _fp; }
public InitSection GetSection (string section) => new InitSection (filepath, section);
public InitKey GetKey (string section, string key) => new InitKey (filepath, section, key);
public object Get (string section, string key, object dflt) => GetKey (section, key).Get (dflt);
public object Get (string section, string key) => GetKey (section, key).Get ();
public bool Set (string section, string key, object value) => GetKey (section, key).Set (value);
public object this [string key] => GetSection (key);
public string [] GetAllSections ()
{
var sections = new System.Collections.Generic.List<string> ();
IniFile.GetPrivateProfileSectionNamesW (filepath, sections);
return sections.ToArray ();
}
public InitSection [] Sections => GetAllSections ().Select (s => new InitSection (filepath, s)).ToArray ();
}
}

View File

@@ -5,12 +5,12 @@ using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle ("Update")]
[assembly: AssemblyTitle ("更新")]
[assembly: AssemblyDescription ("")]
[assembly: AssemblyConfiguration ("")]
[assembly: AssemblyCompany ("")]
[assembly: AssemblyProduct ("Update")]
[assembly: AssemblyCopyright ("Copyright © 2026")]
[assembly: AssemblyCompany ("Windows Modern")]
[assembly: AssemblyProduct ("Windows 现代风格实用工具")]
[assembly: AssemblyCopyright ("Copyright © 2026 Windows Modern。版权所有。")]
[assembly: AssemblyTrademark ("")]
[assembly: AssemblyCulture ("")]

View File

@@ -73,6 +73,12 @@
<ItemGroup>
<Content Include="Project1.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\settings\settings.vcxproj">
<Project>{ad25497f-a15f-4dff-ac7a-b8abf5f411d6}</Project>
<Name>settings</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("WAShell")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WAShell")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//将 ComVisible 设置为 false 将使此程序集中的类型
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible (true)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("4ec16578-efbf-41e6-8d7f-976e3646dd1d")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

83
WAShell/SplashForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,83 @@
namespace WAShell
{
partial class SplashForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose (bool disposing)
{
if (disposing && (components != null))
{
components.Dispose ();
}
base.Dispose (disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent ()
{
this.components = new System.ComponentModel.Container();
this.picbox = new System.Windows.Forms.PictureBox();
this.timer = new System.Windows.Forms.Timer(this.components);
((System.ComponentModel.ISupportInitialize)(this.picbox)).BeginInit();
this.SuspendLayout();
//
// picbox
//
this.picbox.Anchor = System.Windows.Forms.AnchorStyles.None;
this.picbox.BackColor = System.Drawing.Color.Transparent;
this.picbox.Location = new System.Drawing.Point(6, 47);
this.picbox.Name = "picbox";
this.picbox.Size = new System.Drawing.Size(620, 300);
this.picbox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.picbox.TabIndex = 0;
this.picbox.TabStop = false;
//
// timer
//
this.timer.Tick += new System.EventHandler(this.timer_Tick);
//
// SplashForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.Window;
this.ClientSize = new System.Drawing.Size(632, 425);
this.Controls.Add(this.picbox);
this.DoubleBuffered = true;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "SplashForm";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Splash Screen";
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.SplashForm_FormClosed);
this.Load += new System.EventHandler(this.SplashForm_Load);
this.Shown += new System.EventHandler(this.SplashForm_Shown);
this.Resize += new System.EventHandler(this.SplashForm_Resize);
((System.ComponentModel.ISupportInitialize)(this.picbox)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.PictureBox picbox;
private System.Windows.Forms.Timer timer;
}
}

229
WAShell/SplashForm.cs Normal file
View File

@@ -0,0 +1,229 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using DataUtils;
namespace WAShell
{
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public partial class SplashForm: Form
{
public enum FadeType
{
Gradually,
Immediately
};
private Image splashImage = null;
private Color background = Color.Transparent;
private FadeType fadeMode = FadeType.Gradually;
double opastep = 0.05;
private Control _host = null;
public Control Host
{
get { return _host; }
set
{
if (ReferenceEquals (_host, value)) return;
DetachHostEvents (_host);
_host = value;
AttachHostEvents (_host);
if (this.Visible)
{
ResizeSplashScreen ();
}
}
}
private void AttachHostEvents (Control host)
{
if (host == null) return;
host.Resize += Host_Changed;
host.LocationChanged += Host_Changed;
}
private void DetachHostEvents (Control host)
{
if (host == null) return;
host.Resize -= Host_Changed;
host.LocationChanged -= Host_Changed;
}
private void Host_Changed (object sender, EventArgs e)
{
if (!this.IsHandleCreated) return;
ResizeSplashScreen ();
}
public SplashForm ()
{
InitializeComponent ();
Init ();
}
private void Init ()
{
this.AllowTransparency = true;
picbox.Size = new Size (
(int)(620 * UITheme.DPIDouble),
(int)(300 * UITheme.DPIDouble)
);
try { picbox.Image = splashImage; } catch (Exception) { }
try { this.BackColor = background; } catch (Exception) { }
}
public Image SplashImage
{
get { return splashImage; }
set
{
splashImage = value;
if (picbox != null && picbox.IsHandleCreated)
{
splashImage = picbox.Image;
}
}
}
public Color SplashBackgroundColor
{
get { try { return background = this.BackColor; } catch (Exception) { return background; } }
set
{
background = value;
try { this.BackColor = background; }
catch (Exception) { background = this.BackColor; }
}
}
private void SplashForm_Load (object sender, EventArgs e)
{
ResizeSplashScreen ();
}
private void ResizeSplashScreen ()
{
Control owner = this.Owner;
if (owner == null) owner = this.Parent;
if (owner == null) return;
owner.Update ();
var pt = owner.PointToScreen (owner.ClientRectangle.Location);
Location = pt;
Size = owner.ClientSize;
ResizeSplashImage ();
}
private void ResizeSplashImage ()
{
if (picbox != null && picbox.IsHandleCreated)
{
var sz = this.ClientSize;
picbox.Location = new Point (
(int)((sz.Width - picbox.Width) * 0.5),
(int)((sz.Height - picbox.Height) * 0.5)
);
}
}
private void SplashForm_Resize (object sender, EventArgs e)
{
ResizeSplashImage ();
}
private bool fadeAwayArmed = false; // 用于 FadeAway 的“第一次 / 第二次”
private bool fading = false; // 防止重复启动 Timer
protected virtual void OnFormFade ()
{
switch (fadeMode)
{
case FadeType.Gradually:
if (this.Opacity > 0)
{
this.Opacity -= opastep;
if (this.Opacity < 0) this.Opacity = 0;
}
else
{
timer.Stop ();
this.Visible = false;
fading = false;
}
break;
case FadeType.Immediately:
if (fadeAwayArmed)
{
this.Opacity = 0;
timer.Stop ();
this.Visible = false;
fading = false;
}
else
{
fadeAwayArmed = true;
}
break;
}
}
private void timer_Tick (object sender, EventArgs e)
{
OnFormFade ();
}
public void OwnerWnd_Resize (object sender, EventArgs e)
{
if (this != null && this.IsHandleCreated && this.picbox != null && this.picbox.IsHandleCreated)
{
ResizeSplashScreen ();
}
}
// 渐变消失
public void FadeOut ()
{
if (fading) return;
fadeMode = FadeType.Gradually;
fadeAwayArmed = false;
fading = true;
this.Opacity = Math.Min (this.Opacity, 1.0);
timer.Interval = 15;
timer.Start ();
}
// 立即消失
public void FadeAway ()
{
if (fading) return;
fadeMode = FadeType.Immediately;
fadeAwayArmed = false;
fading = true;
timer.Interval = 15;
timer.Start ();
}
public void ResetSplash ()
{
this.Opacity = 1.0;
this.Visible = false;
this.Enabled = true;
fadeMode = FadeType.Gradually;
fadeAwayArmed = false;
fading = false;
if (timer != null) timer.Stop ();
if (picbox != null)
{
picbox.Image = splashImage;
picbox.BackColor = background;
}
ResizeSplashScreen ();
}
private void SplashForm_FormClosed (object sender, FormClosedEventArgs e)
{
try
{
DetachHostEvents (_host);
_host = null;
base.OnFormClosed (e);
}
catch (Exception) { }
}
private void SplashForm_Shown (object sender, EventArgs e)
{
base.OnShown (e);
this.Opacity = 1.0;
this.Visible = true;
this.Enabled = true;
ResizeSplashScreen ();
}
}
}

123
WAShell/SplashForm.resx Normal file
View File

@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="timer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

92
WAShell/WAShell.csproj Normal file
View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" 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>{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>WAShell</RootNamespace>
<AssemblyName>WAShell</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>2</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SplashForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="SplashForm.Designer.cs">
<DependentUpon>SplashForm.cs</DependentUpon>
</Compile>
<Compile Include="WebAppForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="WebAppForm.Designer.cs">
<DependentUpon>WebAppForm.cs</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AppxPackage\AppxPackage.csproj">
<Project>{bd681a4f-eb60-4bb8-90b5-65968fc7da59}</Project>
<Name>AppxPackage</Name>
</ProjectReference>
<ProjectReference Include="..\Bridge\Bridge.csproj">
<Project>{3c2f5446-33f0-41d5-813a-64a94aa474af}</Project>
<Name>Bridge</Name>
</ProjectReference>
<ProjectReference Include="..\DataUtils\DataUtils.csproj">
<Project>{ffd3fd52-37a8-4f43-883c-de8d996cb0e0}</Project>
<Name>DataUtils</Name>
</ProjectReference>
<ProjectReference Include="..\PrivateInit\PrivateInit.csproj">
<Project>{8e708d9a-6325-4aa9-b5a5-d1b5eca8eef7}</Project>
<Name>PrivateInit</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="SplashForm.resx">
<DependentUpon>SplashForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="WebAppForm.resx">
<DependentUpon>WebAppForm.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

60
WAShell/WebAppForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,60 @@
namespace WAShell
{
partial class WebAppForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose (bool disposing)
{
if (disposing && (components != null))
{
components.Dispose ();
}
base.Dispose (disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent ()
{
this.webui = new System.Windows.Forms.WebBrowser();
this.SuspendLayout();
//
// webui
//
this.webui.Dock = System.Windows.Forms.DockStyle.Fill;
this.webui.Location = new System.Drawing.Point(0, 0);
this.webui.MinimumSize = new System.Drawing.Size(20, 20);
this.webui.Name = "webui";
this.webui.Size = new System.Drawing.Size(661, 416);
this.webui.TabIndex = 0;
//
// WebAppForm
//
this.AllowDrop = true;
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(661, 416);
this.Controls.Add(this.webui);
this.Name = "WebAppForm";
this.Text = "Main Web App Form";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.WebBrowser webui;
}
}

67
WAShell/WebAppForm.cs Normal file
View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using DataUtils;
namespace WAShell
{
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public partial class WebAppForm: Form, IScriptBridge, IWebBrowserPageScale
{
SplashForm splash;
ITaskbarList3 taskbar = null;
public WebAppForm ()
{
InitializeComponent ();
}
public int PageScale
{
get
{
var web2 = WebBrowserHelper.GetWebBrowser2 (webui);
if (web2 == null) return 0;
object inArg = null;
object outArg = null;
try
{
web2.ExecWB (
OLECMDID.OLECMDID_OPTICAL_ZOOM,
OLECMDEXECOPT.OLECMDEXECOPT_DODEFAULT,
ref inArg,
ref outArg
);
if (outArg is int) return (int)outArg;
}
catch { }
return 0;
}
set
{
var web2 = WebBrowserHelper.GetWebBrowser2 (webui);
if (web2 == null) return;
object inArg = value;
object outArg = null;
try
{
web2.ExecWB (
OLECMDID.OLECMDID_OPTICAL_ZOOM,
OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER,
ref inArg,
ref outArg
);
}
catch { }
}
}
public object CallEvent (string funcName, object e)
{
return null;
}
}
}

120
WAShell/WebAppForm.resx Normal file
View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -56,11 +56,11 @@ System::Drawing::Color GetDwmThemeColor ()
}
else return System::Drawing::Color::FromArgb (0, 120, 215); // 如果获取失败,返回默认颜色
}
String ^ColorToHtml (System::Drawing::Color color)
System::String ^ColorToHtml (System::Drawing::Color color)
{
return String::Format ("#{0:X2}{1:X2}{2:X2}", color.R, color.G, color.B);
return System::String::Format ("#{0:X2}{1:X2}{2:X2}", color.R, color.G, color.B);
}
System::Drawing::Color StringToColor (String ^colorStr)
System::Drawing::Color StringToColor (System::String ^colorStr)
{
using Color = System::Drawing::Color;
using Regex = System::Text::RegularExpressions::Regex;
@@ -68,7 +68,7 @@ System::Drawing::Color StringToColor (String ^colorStr)
{
return (value < min) ? min : (value > max) ? max : value;
};
String ^normalized = colorStr->Trim ()->ToLower ();
System::String ^normalized = colorStr->Trim ()->ToLower ();
if (normalized == "transparent") return Color::Transparent;
if (Color::FromName (normalized).IsKnownColor)
{
@@ -76,17 +76,17 @@ System::Drawing::Color StringToColor (String ^colorStr)
}
if (normalized->StartsWith ("#"))
{
String^ hex = normalized->Substring (1);
System::String^ hex = normalized->Substring (1);
if (hex->Length == 3 || hex->Length == 4)
{
hex = String::Concat (
hex = System::String::Concat (
hex [0].ToString () + hex [0],
hex [1].ToString () + hex [1],
hex [2].ToString () + hex [2],
(hex->Length == 4) ? (hex [3].ToString () + hex [3]) : ""
);
}
uint32_t argb = Convert::ToUInt32 (hex, 16);
uint32_t argb = System::Convert::ToUInt32 (hex, 16);
switch (hex->Length)
{
case 6: return Color::FromArgb (
@@ -101,19 +101,19 @@ System::Drawing::Color StringToColor (String ^colorStr)
(argb >> 8) & 0xFF,
argb & 0xFF
);
default: throw gcnew ArgumentException ("Invalid hex color format");
default: throw gcnew System::ArgumentException ("Invalid hex color format");
}
}
System::Text::RegularExpressions::Match ^match = Regex::Match (normalized,
"^(rgba?)\\s*\\(\\s*(\\d+%?)\\s*,\\s*(\\d+%?)\\s*,\\s*(\\d+%?)\\s*,?\\s*([\\d.]+%?)?\\s*\\)$");
if (match->Success)
{
auto GetComponent = [&] (String^ val) -> int
auto GetComponent = [&] (System::String^ val) -> int
{
if (val->EndsWith ("%"))
{
float percent = float::Parse (val->TrimEnd ('%')) / 100.0f;
return Clamp ((int)Math::Round (percent * 255), 0, 255);
return Clamp ((int)System::Math::Round (percent * 255), 0, 255);
}
return Clamp (int::Parse (val), 0, 255);
};
@@ -122,16 +122,16 @@ System::Drawing::Color StringToColor (String ^colorStr)
int b = GetComponent (match->Groups [4]->Value);
if (match->Groups [1]->Value == "rgba")
{
String^ alphaVal = match->Groups [5]->Value;
System::String^ alphaVal = match->Groups [5]->Value;
int a = 255;
if (alphaVal->EndsWith ("%"))
{
float percent = float::Parse (alphaVal->TrimEnd ('%')) / 100.0f;
a = Clamp ((int)Math::Round (percent * 255), 0, 255);
a = Clamp ((int)System::Math::Round (percent * 255), 0, 255);
}
else if (!String::IsNullOrEmpty (alphaVal))
else if (!System::String::IsNullOrEmpty (alphaVal))
{
a = Clamp ((int)Math::Round (float::Parse (alphaVal) * 255), 0, 255);
a = Clamp ((int)System::Math::Round (float::Parse (alphaVal) * 255), 0, 255);
}
return Color::FromArgb (a, r, g, b);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -683,7 +683,7 @@
<SCDesk>0</SCDesk>
<SCQLaunch>0</SCQLaunch>
<SCStartPinOption>0</SCStartPinOption>
<SCCust>1</SCCust>
<SCCust>0</SCCust>
<CustSCPath>%StartProgramsFolderCommon%\\%AppShortcutFolderName%</CustSCPath>
<SCDesc>Update</SCDesc>
<SCComment/>
@@ -1099,6 +1099,79 @@
<CRC>0</CRC>
<StoreOnly>0</StoreOnly>
</FileData>
<FileData>
<FldRef>0</FldRef>
<FullName>E:\Profiles\Bruce\Documents\Visual Studio 2015\Projects\AppInstallerReset\Release\Update.exe</FullName>
<FileName>Update.exe</FileName>
<Source>E:\Profiles\Bruce\Documents\Visual Studio 2015\Projects\AppInstallerReset\Release</Source>
<Ext>exe</Ext>
<RTSource>档案</RTSource>
<Desc/>
<Recurse>1</Recurse>
<MatchMode>0</MatchMode>
<Dest>%AppFolder%</Dest>
<Overwrite>1</Overwrite>
<Backup>0</Backup>
<Protect>0</Protect>
<InstallOrder>1000</InstallOrder>
<SCStartRoot>0</SCStartRoot>
<SCStartProgs>0</SCStartProgs>
<SCAppFld>1</SCAppFld>
<SCStartup>0</SCStartup>
<SCDesk>0</SCDesk>
<SCQLaunch>0</SCQLaunch>
<SCStartPinOption>0</SCStartPinOption>
<SCCust>0</SCCust>
<CustSCPath/>
<SCDesc>Update</SCDesc>
<SCComment/>
<SCArgs/>
<SCWork/>
<UseExtIco>0</UseExtIco>
<IcoFN/>
<IcoIdx>0</IcoIdx>
<IcoShowMd>0</IcoShowMd>
<IcoHK>0</IcoHK>
<RegTTF>0</RegTTF>
<TTFName/>
<RegOCX>0</RegOCX>
<RegTLB>0</RegTLB>
<SupInUse>0</SupInUse>
<Compress>1</Compress>
<UseOrigAttr>1</UseOrigAttr>
<Attr>0</Attr>
<NoCRC>0</NoCRC>
<NoRemove>0</NoRemove>
<Shared>0</Shared>
<OSCond>
<OS>32768</OS>
<OS>65535</OS>
<OS>65535</OS>
<OS>65535</OS>
<OS>65535</OS>
<OS>65535</OS>
<OS>65535</OS>
<OS>65535</OS>
<OS>65535</OS>
<OS>65535</OS>
<OS>65535</OS>
<OS>65535</OS>
<OS>65535</OS>
<OS>65535</OS>
<OS>65535</OS>
<OS>65535</OS>
</OSCond>
<RTCond/>
<BuildConfigs>
<Cfg>All</Cfg>
</BuildConfigs>
<Package>None</Package>
<Packages/>
<Notes/>
<CompSize>0</CompSize>
<CRC>0</CRC>
<StoreOnly>0</StoreOnly>
</FileData>
</ArchiveFiles>
<ExternalFiles/>
<BeforeInstallingScreens>

View File

@@ -1,5 +1,5 @@
#pragma once
#using "./PriFileFormat.dll"
// #using "./PriFileFormat.dll"
using namespace PriFileFormat;
#include <comip.h>
#include <atlbase.h>

View File

@@ -186,6 +186,11 @@
<ItemGroup>
<ResourceCompile Include="priformatcli.rc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PriFileFormat\PriFile.csproj">
<Project>{ef4012d4-ef08-499c-b803-177739350b2d}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<VisualElements DisplayName="Update" BackgroundColor="#F1F7C0" ShowNameOnSquare150x150Logo="on" ForegroundText="light" Square150x150Logo="Update.Assets\150x150Logo.png" Square70x70Logo="Update.Assets\70x70Logo.png" />
<?xml version="1.0" encoding="utf-8"?>
<Application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" GeneratedByTileIconifier="true">
<VisualElements ShowNameOnSquare150x150Logo="on" Square150x150Logo="VisualElements\MediumIconUpdate.png" Square70x70Logo="VisualElements\SmallIconUpdate.png" ForegroundText="light" BackgroundColor="#ffc107" TileIconifierColorSelection="Custom" TileIconifierCreatedWithUpgrade="false" />
</Application>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@@ -0,0 +1,9 @@
<?xml version="1.0"?>
<ShortcutItemImage xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<OriginalBytes>iVBORw0KGgoAAAANSUhEUgAAANIAAADSCAYAAAA/mZ5CAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAuISURBVHhe7d0L0KxzHcBxMSnFcUlmonKpyBlHJNTEoSldDaaaKZcZpSmOYdyKGoNjNFFEOCdJRUlyGdQoSiEjJcalznRDYqKGcolE49L3v89v37Pn3cu7u8+zu8+zz/cz85vdff7//+/5v2d/v2O9Z/fZlSRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJkpR5/vnn57/wwgsrx0NJg0pNRCyjkZLFxMtiSKo2inkT4jwK/Jo4NBKzmqjVYo6vE9OkaqF430CcH8XcdHEMF6pHE7VKDbV+LJHKjYJ9IwX7vax22zF2dkwtRJ9NNIO5n+dmk1gulUsU9EVZuc7ppFiWy6BN1Ip1p6T1kUqaLIpxAXFJ1GffWHNUpBhKagJiqCZqRY4lxNaRVhovanArCvCyrByHw/qDIt1AWFdIE7Ui39eIN8cppNGi5rah4H6QlV9+5FoUqfvC/MKbqIm8zxFncXerOJ1ULApsW+LKrOSKRd5Pxml6Yt7ImqgV53iWWEq8KU4t5UMxvZW4KmpsZDjHfnHKjhgfSxO14nz/I9L/Qy2IbUiDoXjeTvw0amosON++cfoVcHzsTdSKcz9DnEFsEVuSeqNYFhI/jxoaO869T2ylgccTbaJW7OO/xOlpT7E9qR21kt6fNnEU6kfTflLBEqVoolbs6SniNGLzxh+cNBvFcWHUy0Sxj0OIO+JhKbG/J4lTic3ij09ajsKY/R65cbqV8+8Y+9iY+HYcLy32+ASR3imxaeMPUGqiPs7LymQ8KMLbiQO4+6LYwgyOv474bjazvNjj48TJxOtj61KjgL8RNTIynOO3xIHcXSVO2xXzNiW6viG2RB5jn1/k1jfHKkNBnJ3VRrHIu4w4mLurxqn6xrrNiX7fIDsx7PERbk7iduPYuuqMQlialUZ+5PoDcSixWqQfGjm2IC6N1KXFHv9FfIHYMLauuqIITo+6GArr/0wcwd3VI2VhyLslcXl2pvJijw8T6fNQr42tq44oglOzkugfa+4mPkPMizQjwzm2Jgp7Q+2osMeHiBOIV8fWVTc8+V+KeuiJefdy81li7Vg6Npz7LcRI3mBbJPb4D+J4YoPYuuqEJ/7EqIU2jN1PHM3ddWP6xLCP7YmRv+E2L/b4IDfpmhKviq2rLnjST8jKIMPjB4hjiPViSmmwp7cRP4mtltn1sWXVCU984715FOk5ROn/NmWrO7DPn6U9lw37ujG2qbrhyX8FcRN1UKl/eGTPOxHXZSU8eezl5tia6ooiuIH4N3E+Uan3mrHfdxC/iHqeCM5/S2xHdUYhzPzNzv30a90LiUp9Xoetv4s935j9FOPDOX8dW1DdUQxtL5E49ghxLrFlTKsE9vseIr1UHTnO88s4rdS5kZoYS++G/jJRqctcsd/3EzfHj1E4ct8Qp5IyFMWc/9POnP8QXyG2i2WVwH53Zfu3Zj9FMdKfV6SXlkuFETUyJ+Y+TZxJVOoyV+x3d+K2+DGGRo6RfiOHKozi6LuRmliTrht3FlG1l3wfJO6MH2MgrLs60kjtKJCBG6kV69PnnbaJdJXAnj9M9H1RFub+KJZKneVtpKaKNtRHiN9nP0FnjP8wpkvdFdVITRVtqL2IP2U/wXIcuzymSL0V3UhNFW2ofYi7Y/+XxmFpbqNqpKaKNtTHiTPZ9855I1Jq2o26kZqq0lDsM10z/cfZrvMhz2mRVtNuXI3UVNaGYl/bEV/PdplPWX9GjdC4G6mpLMXGPtKHBr+V7SofG6jGJtVITZMqPs67I1HI5ZRtIE28kZrGVYycY2fOdUHjpDnZQJpRlkZqGlVxkjN9Zun7jZPkZAOpTdkaqamoYiVP+oxSIVdztYHUVVkbqWnY4mXdB4hCrt5qA2lOZW+kplTMxJyf2GVO+negQq7Wms7JjQ2kuVEslWikhL2mi9m/L7behrHtY2ouNpAGVqVGStjvubH1Nozl+jIzG0hDq2Ajdf2oN2ND/T+RDaTcpqmRGE5Xjk3X4D6ueb/T49ZgzK+5VH7T1EjSxNhIUgFsJKkA09RIjKVr76UviH5pHJLGY8oa6ZKYk75J79NE7i+MlvqSCrNRoRWR9htbb8PYRTGtgcfpy5OPJtaIKdJopMKMuquEtN/YehvGGv9Fmo3j6UsBjuXumjFVKtY0NRLDF2ezOouG8t+NVLxpaiTGVnhp14qx9KXOlfpmQlXIlDVS20s7jj1K7BlTpNGYskaa/cuG64gNYlganSlrpJn/InF/CTerxJA0WtPUSAxfzPhz3H4qDknjMU2NxFj63tud4qE0PlPWSL6TQZMxTY2UB3m3JtLF888gbiCeINJbjX5DXEqkr/zcny2sGkuk5SiOWjcS+dKXjf0q0s+JucuII4h1IkVPLFkcdzXNKIhaNhJ5FhKXRdqBsfY+bro2CWMrM+erxKNxSNOMJ7p2jUSOEyJdbuRaEmlncHhNjjcuxMKtjVQHqTDTE14Vab+x9aGw/rRI1ctjzLuHuJm4k3gqjnfEePqH4HUj/wbEldmIjVQbPNG1aSTWfjPSrIDj9xEXEPvxsNEQszG2GbGI6PjlzRy/lphP3BiHGnhsI9UBT3QtGol13ZroiJjSF+bPI9JnnJ6JFDM4tizuzuCYjVQHPNFT30is2S2Wz+DYXcTGMWVgrH03cW+k64o5NlId8ETXoZFmv9x6KIZyIdVG5Lopy9oZ4zZSHfBEF/KNDePCfgdqJOYfGUtbFfZt4+TfO3J2ZCPVBE90P7/FKo1BGonpqzD/7mxlhsdHxXBu5Dos0nbFHBupDniu98ie8moYpJGYu3ssa+Bx+jaLl8dwLuQ5MdL2xDwbqQ54rtfiyb4re9rLj70O0kjnxLIGHp8SQ7mQ5zuRck7MtZHqgif7nfG8lx577auRmJd+Tf1wLGvg8bYxPBTWr0aa67Ns/WGNjVQnPOfp275L/xu8tMfYck9M3Xl2xNBQWJ9+Q3cMcRRxOHEwsT/xCWJfYm8ivQH2Q8TuxK7Eewk/H1VHPPGpOG6jcEqJvfX90k6aOAr2QOLOqN/SsJFUSRTuQcTvoo4nzkZSpVHAhxAd37A5TjaSpgKFfBjxx6jrsbORNFUo6PS1KWP/9ycbSVOJwj6SuCfqfOT6baQ0b4jYLZYPhfWvnJUvxZYxLM2Ngvkc8deo95FJxRmn7Cmm94WcjxMLY+nQyHFKpGzg8bUxJA2G4kkfers/aqlw5C60kcj3F2JBLMuFPH+LtA083j+GpOFQRMcSD0RNFYachTUSuW4hXhNLciHPnpG2gccPcbNWDEv5UEyLKaq/N6qrAOQqpJHIczU3q8f0XMi1IXF7ljnD46UxLBWHwjqeSH9L50KOohqpkO9MIs8aaU+RtoHH6SPoG8UUqXgUWWqof2YlN7hUtJGqp5jeE7kWxfShkCJ9BOWKLNsKPhZTpNGKhno0Cq9vRTZSSC89+7r8cCvW7cG6FV7OJRw7N6ZI40PhpYZ6POpwTswdupFY23a5rITj6YpCB8fSnpi3gOj48XyO38GNL+k0ORRhaqgns5LsjjlDNRLrHiTmc7frN58z/gBxBZHetbELsRdxKHEycQ2xwgcFWzF2FbFenF6aLIoxNVTXSwQzNnAjseZpbnaIoXSO47KRYpDvnEgtlQvFmRqq09VMh2mktrf+pGNEx5d6/WJ9+i2kX9ui8qNYU0M9m5XuUI3U9Tdo5FqfWEoM9Gt55j9FpJd7Q1+pVZoIijY1VNJ3IzH38HjYE1NXZ+4BKXda1w3jqYHOIraIpVI1Uc9rxt2eKPaXxN2BkP/FxNqzg3zzuF05pkmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSJEmSNForrfR/3s15gMpdcisAAAAASUVORK5CYII=</OriginalBytes>
<OriginalPath>C:\Program Files (x86)\Desktop App Installer\Update.Assets\150x150Logo.scale-140.png</OriginalPath>
<Height>100</Height>
<Width>100</Width>
<X>0</X>
<Y>0</Y>
</ShortcutItemImage>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -0,0 +1,9 @@
<?xml version="1.0"?>
<ShortcutItemImage xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<OriginalBytes>iVBORw0KGgoAAAANSUhEUgAAAGIAAABiCAYAAACrpQYOAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAaaSURBVHhe7ZxbqBVlFMcNrZDKQgkUKkiLQKIXIY0eurxIFPYQJ0oSVOiYmt2sJC3yQR8KwgjMougKFSVYUBFdOA9ShHhJOWQXs9Qio6KS7pdz+q3Z/z2cac+ePbP3zOTMXj/4MzPft761Zq11PHOcmb3HOY7jOI7jOI7jOI7jOI7jOI7jOI7jpGNkZOQcNIQu15DTDRRwEVqjw0yMjo5OZ+0HbAPYfxldoGknDdRtkKIdapQwKOISTaUC+9PRNi2PwPij6FyZOnFQoOXosGr2XwZklgh2U/HxbmNJPMz/g+5n9wwtcwyKcgv6vlGmRBKbgY8paEi2HcH2MLqX3aly0Z9QhNvRkUZZUhPbDPxMQm/KJhOsO4TuRqfKXX9Awneh31SHbog0A18T0Wua6xp8HECr0RS5rickeA/6S3n3StAMthPwuaUxlA/4249WsXtKcOJ1gqQGgixzhGLNR5t1mDv43ofuQJOURj0gt1yaQWG+ZrOW7WS2C9l+EUwUBP4/RrehE5RK9SGvrptBIb5D69BpchfC2GJ0UKaFgP+9yP7Cm6iw1YacsjbjR5K/D50pF23B5nr0ldYVAv6H0Qp2j1PY6kISHZtBsr+gB9DZWpYa1ixB9iusMPC/By1nd4LCVhMSiG0Gyf2BHkIzZdo1+FiKvpHrQsD/LnQDu8cobPXg5MNmkIzxMDpP07mBT7t98q1CFQL+d6AV6CyFrRbkMMDJv8F2loYKgzg3oTS3U7oC31coVDUhgWdRaXdFiWV//fyg+uUC/i6V++pCEluVzBZ0iYYLh1j2/4Os97tawMccuaw2JPKecgrg+B10taYLh1h2A/Jnhc8E63K/pv1vkEzsgxzYzpxdaE+SaaEQZxX6VbE7gm01L8ztIKGdyi0W5j9jsxaV8uyAeHaH+PcgeBuYnybz+kBSe5RfIth9iUp7dkCcNehPhR/LyTKpFyT7oRJMBfb27MB+aifLRaEQx27h/63wx2q4fpDkJ0oyE6yzZwd3slvKTyixNhDLfkXa3V97zGrb9egJ9DraiZq3VlI9Zz+q4OTtGtA1rP8UrWT3RLnMFfwOou0WqxOcx3NotpZWC078gPLoCfx8hHK7VY3LLA14CV2kpdWEBHK9dY2/nm5Vsy5LAzajuVpabUikkDuk+N2NlrE7XqESwS5LA15FV2ppPSChwm7EGfi3i2jbNwYxydKAt9hU70KcBpL7qZFmsRDnfYUMsTFNJ4LdVjRfy+oJCXZ1n6cbFDJEw23h3LahRTKvNySaeDshTxQyhKGLkySz/oBGNP/XWjgK6cShGpWCQobwQ2B3XEu5u3vUoxqVgkKG0AR7X8pUn3eWukU1KgWFDLEmaMouzM2X2PrrzfAmqkMpKGTI2EYYHNtj2+ma7i8aJSgHhQxpNoLtEVTt95N6xQpRFgoZYo1Adm9qhob6F9WoFBQyhAZsRPV507sXVKNSUMjM0Kzz0a1oAZqNSnk6WCqqUSkoZCown0XB7SPBsbfpbY5N7BuKzK3UbnVopFUOCtkRFTkV2K7TsgCON6D9OqwOyqcUFDIRzF5sWDegqPbJ003sNp9Xb0KRT7FyvNHWsn1cx96IJBSyLRTwSZlaMQ+ieZpqgbnr0G6ZG2EDGfdGJKGQsTC9sGEVsF3DiVBw+4z3C1oTUslGcNK7dP6Fo5AtcA72zQWfmw3bYQ2nAvv1gfMxMFbJRqzW+ReOQrbAOSySiZH6USjrHtSaCFVtxEw0rBwKRSFbIP4rMul4HWmC6VONFa1UshGGNYPzT/UAvxcULgKxZzCV6ancWPs44bOaL5k1IYnUb1R0g8I4aaFmhTRE7p2sULtcGyK3TrdQw1waIncRGLbf68H/mhPU8WGRrnOBPfs3a7iekGRPDZGbCAxbI2KhoPZi2fEyTQRza0KANUXD9YZEF5Nv5oZoeQSGYxtBjKdlkgrsgz/B2b6tof6BpBeQe+qGaFkEhuMasVbTqeA8HtM6a8Q1Gu4/LHlq0LEhMo/AcLt/EY+gxDc6mJ+G6dhfSTdqqr+hEFdRj7YNkVkEhiONwEf43U/s2zeZLUORhnA8h2m7KIcPjdgf0rTThKLMQy2f39Z0BIbDRrDGbm3bY9G4O6r2FdemvRoKYewZuXPioECXofBLeTUcgeGgEdgt01AAx/ZtM/tsLgH71zeoJU4nKOiF6HkdRmB8DlqqwwgUeTxzc5E9u7ZPsTZlH1q8VmaO4ziO4ziO4ziO4ziO4ziO4ziO49SEceP+Bdbzgt+r46efAAAAAElFTkSuQmCC</OriginalBytes>
<OriginalPath>C:\Program Files (x86)\Desktop App Installer\Update.Assets\70x70Logo.scale-140.png</OriginalPath>
<Height>50</Height>
<Width>50</Width>
<X>0</X>
<Y>0</Y>
</ShortcutItemImage>