mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-16 05:39:07 +10:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2cdc310598 | ||
|
|
fe19eaf169 | ||
|
|
d85fbb8de8 | ||
|
|
d91948eaff | ||
|
|
0c87a2cdcd | ||
|
|
5a404a55e3 | ||
|
|
503ece1c64 | ||
|
|
75cb72964d |
@@ -60,6 +60,17 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bridge", "Bridge\Bridge.csp
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WAShell", "WAShell\WAShell.csproj", "{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Manager", "Manager\Manager.csproj", "{DC074727-72E4-43C5-BAAF-E0D548104797}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{3AE2A022-ED83-41F1-948A-12A7593CBD00} = {3AE2A022-ED83-41F1-948A-12A7593CBD00}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IEHelper", "IEHelper\IEHelper.vcxproj", "{E4CA78A9-9408-4F5F-ADD6-730FD501FF8E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernNotice", "ModernNotice\ModernNotice.csproj", "{C5587B6E-19C4-4484-AA97-5C20FBB07E43}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launch", "Launch\Launch.csproj", "{F0288B24-7B84-42A5-9A92-2E16A012E4DE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -250,6 +261,52 @@ Global
|
||||
{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
|
||||
{DC074727-72E4-43C5-BAAF-E0D548104797}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DC074727-72E4-43C5-BAAF-E0D548104797}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DC074727-72E4-43C5-BAAF-E0D548104797}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{DC074727-72E4-43C5-BAAF-E0D548104797}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{DC074727-72E4-43C5-BAAF-E0D548104797}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{DC074727-72E4-43C5-BAAF-E0D548104797}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{DC074727-72E4-43C5-BAAF-E0D548104797}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DC074727-72E4-43C5-BAAF-E0D548104797}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DC074727-72E4-43C5-BAAF-E0D548104797}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{DC074727-72E4-43C5-BAAF-E0D548104797}.Release|x64.Build.0 = Release|Any CPU
|
||||
{DC074727-72E4-43C5-BAAF-E0D548104797}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{DC074727-72E4-43C5-BAAF-E0D548104797}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E4CA78A9-9408-4F5F-ADD6-730FD501FF8E}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{E4CA78A9-9408-4F5F-ADD6-730FD501FF8E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E4CA78A9-9408-4F5F-ADD6-730FD501FF8E}.Debug|x64.Build.0 = Debug|x64
|
||||
{E4CA78A9-9408-4F5F-ADD6-730FD501FF8E}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{E4CA78A9-9408-4F5F-ADD6-730FD501FF8E}.Debug|x86.Build.0 = Debug|Win32
|
||||
{E4CA78A9-9408-4F5F-ADD6-730FD501FF8E}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{E4CA78A9-9408-4F5F-ADD6-730FD501FF8E}.Release|x64.ActiveCfg = Release|x64
|
||||
{E4CA78A9-9408-4F5F-ADD6-730FD501FF8E}.Release|x64.Build.0 = Release|x64
|
||||
{E4CA78A9-9408-4F5F-ADD6-730FD501FF8E}.Release|x86.ActiveCfg = Release|Win32
|
||||
{E4CA78A9-9408-4F5F-ADD6-730FD501FF8E}.Release|x86.Build.0 = Release|Win32
|
||||
{C5587B6E-19C4-4484-AA97-5C20FBB07E43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C5587B6E-19C4-4484-AA97-5C20FBB07E43}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C5587B6E-19C4-4484-AA97-5C20FBB07E43}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C5587B6E-19C4-4484-AA97-5C20FBB07E43}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C5587B6E-19C4-4484-AA97-5C20FBB07E43}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C5587B6E-19C4-4484-AA97-5C20FBB07E43}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C5587B6E-19C4-4484-AA97-5C20FBB07E43}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C5587B6E-19C4-4484-AA97-5C20FBB07E43}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C5587B6E-19C4-4484-AA97-5C20FBB07E43}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C5587B6E-19C4-4484-AA97-5C20FBB07E43}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C5587B6E-19C4-4484-AA97-5C20FBB07E43}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C5587B6E-19C4-4484-AA97-5C20FBB07E43}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -48,6 +48,10 @@
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</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.Xml.Linq" />
|
||||
@@ -57,12 +61,25 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="DataInterface.cs" />
|
||||
<Compile Include="ManifestReader.cs" />
|
||||
<Compile Include="PackageManager.cs" />
|
||||
<Compile Include="PackageReader.cs" />
|
||||
<Compile Include="PkgMgrNative.cs" />
|
||||
<Compile Include="PkgReadNative.cs" />
|
||||
<Compile Include="PriFileNative.cs" />
|
||||
<Compile Include="PriReader.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DataUtils\DataUtils.csproj">
|
||||
<Project>{ffd3fd52-37a8-4f43-883c-de8d996cb0e0}</Project>
|
||||
<Name>DataUtils</Name>
|
||||
</ProjectReference>
|
||||
</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.
|
||||
|
||||
261
AppxPackage/DataInterface.cs
Normal file
261
AppxPackage/DataInterface.cs
Normal file
@@ -0,0 +1,261 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
|
||||
namespace AppxPackage
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class Ref<T>
|
||||
{
|
||||
private T _value;
|
||||
public Ref ()
|
||||
{
|
||||
_value = default (T);
|
||||
}
|
||||
public Ref (T value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// 模拟 & 引用访问
|
||||
/// </summary>
|
||||
public T Value
|
||||
{
|
||||
get { return _value; }
|
||||
set { _value = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 直接赋值(像 *ref = value)
|
||||
/// </summary>
|
||||
public void Set (T value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// 取值(像 value = *ref)
|
||||
/// </summary>
|
||||
public T Get ()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
public override string ToString ()
|
||||
{
|
||||
return _value == null ? string.Empty : _value.ToString ();
|
||||
}
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return _value == null ? 0 : _value.GetHashCode ();
|
||||
}
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
if (ReferenceEquals (this, obj)) return true;
|
||||
if (obj is Ref<T>) return Equals (_value, ((Ref<T>)obj)._value);
|
||||
return Equals (_value, obj);
|
||||
}
|
||||
public static implicit operator T (Ref<T> r)
|
||||
{
|
||||
return r == null ? default (T) : r._value;
|
||||
}
|
||||
public static implicit operator Ref<T>(T value)
|
||||
{
|
||||
return new Ref<T> (value);
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace AppxPackage.Info
|
||||
{
|
||||
public enum Architecture
|
||||
{
|
||||
x86 = 0,
|
||||
ARM = 5,
|
||||
x64 = 9,
|
||||
Neutral = 11,
|
||||
ARM64 = 12,
|
||||
Unknown = ushort.MaxValue
|
||||
};
|
||||
public enum PackageType
|
||||
{
|
||||
Unknown = 0,
|
||||
Appx = 1,
|
||||
Bundle = 2
|
||||
};
|
||||
public enum PackageRole
|
||||
{
|
||||
Unknown = 0,
|
||||
Application = 1,
|
||||
Framework = 2,
|
||||
Resource = 3
|
||||
};
|
||||
public interface IIdentity
|
||||
{
|
||||
string Name { get; }
|
||||
string Publisher { get; }
|
||||
string FamilyName { get; }
|
||||
string FullName { get; }
|
||||
string ResourceId { get; }
|
||||
DataUtils.Version Version { get; }
|
||||
List<Architecture> ProcessArchitecture { get; }
|
||||
}
|
||||
public interface IProperties
|
||||
{
|
||||
string DisplayName { get; }
|
||||
string Description { get; }
|
||||
string Publisher { get; }
|
||||
string Logo { get; }
|
||||
string LogoBase64 { get; }
|
||||
bool Framework { get; }
|
||||
bool ResourcePackage { get; }
|
||||
}
|
||||
public interface ICapabilities
|
||||
{
|
||||
List<string> Capabilities { get; }
|
||||
List<string> DeviceCapabilities { get; }
|
||||
}
|
||||
public class DependencyInfo
|
||||
{
|
||||
public string Name { get; private set; } = "";
|
||||
public string Publisher { get; private set; } = "";
|
||||
public DataUtils.Version Version { get; private set; } = new DataUtils.Version ();
|
||||
public DependencyInfo (string name, string publisher, DataUtils.Version ver)
|
||||
{
|
||||
Name = name;
|
||||
Publisher = publisher;
|
||||
Version = ver;
|
||||
}
|
||||
public DependencyInfo (string name, DataUtils.Version ver): this (name, "", ver) { }
|
||||
public DependencyInfo () { }
|
||||
}
|
||||
public enum DXFeatureLevel
|
||||
{
|
||||
Unspecified = 0,
|
||||
Level9 = 0x1,
|
||||
Level10 = 0x2,
|
||||
Level11 = 0x4,
|
||||
Level12 = 0x8
|
||||
}
|
||||
public interface IResources
|
||||
{
|
||||
List <string> Languages { get; }
|
||||
List <int> Languages_LCID { get; }
|
||||
List <int> Scales { get; }
|
||||
List <DXFeatureLevel> DXFeatures { get; }
|
||||
}
|
||||
public interface IPrerequisites
|
||||
{
|
||||
DataUtils.Version OSMinVersion { get; }
|
||||
DataUtils.Version OSMaxVersionTested { get; }
|
||||
string OSMinVersionDescription { get; }
|
||||
string OSMaxVersionDescription { get; }
|
||||
}
|
||||
[Serializable]
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
public struct HRESULT: IEquatable<HRESULT>
|
||||
{
|
||||
private readonly int _value;
|
||||
public HRESULT (int value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
public int Value
|
||||
{
|
||||
get { return _value; }
|
||||
}
|
||||
public bool Succeeded
|
||||
{
|
||||
get { return _value >= 0; }
|
||||
}
|
||||
public bool Failed
|
||||
{
|
||||
get { return _value < 0; }
|
||||
}
|
||||
public void ThrowIfFailed ()
|
||||
{
|
||||
if (Failed)
|
||||
Marshal.ThrowExceptionForHR (_value);
|
||||
}
|
||||
public Exception GetException ()
|
||||
{
|
||||
return Failed ? Marshal.GetExceptionForHR (_value) : null;
|
||||
}
|
||||
public override string ToString ()
|
||||
{
|
||||
return string.Format ("HRESULT 0x{0:X8}", _value);
|
||||
}
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
if (obj is HRESULT) return Equals ((HRESULT)obj);
|
||||
return false;
|
||||
}
|
||||
public bool Equals (HRESULT other)
|
||||
{
|
||||
return _value == other._value;
|
||||
}
|
||||
public static implicit operator int (HRESULT hr)
|
||||
{
|
||||
return hr._value;
|
||||
}
|
||||
public static implicit operator HRESULT (int value)
|
||||
{
|
||||
return new HRESULT (value);
|
||||
}
|
||||
public static bool operator == (HRESULT a, HRESULT b)
|
||||
{
|
||||
return a._value == b._value;
|
||||
}
|
||||
public static bool operator != (HRESULT a, HRESULT b)
|
||||
{
|
||||
return a._value != b._value;
|
||||
}
|
||||
public static bool operator >= (HRESULT a, int value)
|
||||
{
|
||||
return a._value >= value;
|
||||
}
|
||||
public static bool operator <= (HRESULT a, int value)
|
||||
{
|
||||
return a._value <= value;
|
||||
}
|
||||
public static bool operator > (HRESULT a, int value)
|
||||
{
|
||||
return a._value > value;
|
||||
}
|
||||
public static bool operator < (HRESULT a, int value)
|
||||
{
|
||||
return a._value < value;
|
||||
}
|
||||
}
|
||||
public static class JSHelper
|
||||
{
|
||||
public static void CallJS (object jsFunc, params object [] args)
|
||||
{
|
||||
if (jsFunc == null) return;
|
||||
|
||||
try
|
||||
{
|
||||
// 这里固定第一个参数为 thisArg(比如 1)
|
||||
object [] realArgs = new object [args.Length + 1];
|
||||
realArgs [0] = jsFunc; // thisArg
|
||||
Array.Copy (args, 0, realArgs, 1, args.Length);
|
||||
|
||||
jsFunc.GetType ().InvokeMember (
|
||||
"call",
|
||||
BindingFlags.InvokeMethod,
|
||||
null,
|
||||
jsFunc,
|
||||
realArgs
|
||||
);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore errors in callback invocation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
996
AppxPackage/ManifestReader.cs
Normal file
996
AppxPackage/ManifestReader.cs
Normal file
@@ -0,0 +1,996 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using AppxPackage.Info;
|
||||
using NativeWrappers;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
//using PriFormat;
|
||||
namespace AppxPackage
|
||||
{
|
||||
public static class DataUrlHelper
|
||||
{
|
||||
[DllImport ("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
|
||||
private static extern int FindMimeFromData (
|
||||
IntPtr pBC,
|
||||
string pwzUrl,
|
||||
byte [] pBuffer,
|
||||
int cbSize,
|
||||
string pwzMimeProposed,
|
||||
int dwMimeFlags,
|
||||
out IntPtr ppwzMimeOut,
|
||||
int dwReserved);
|
||||
private const int FMFD_RETURNUPDATEDIMGMIMES = 0x00000001;
|
||||
private const int FMFD_IGNOREMIMETEXTPLAIN = 0x00000010;
|
||||
private const int FMFD_URLASFILENAME = 0x00000020;
|
||||
private static string GetMimeTypeFromStream (Stream stream)
|
||||
{
|
||||
if (stream == null) return string.Empty;
|
||||
long originalPos = 0;
|
||||
try
|
||||
{
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
originalPos = stream.Position;
|
||||
stream.Seek (0, SeekOrigin.Begin);
|
||||
}
|
||||
byte [] buffer = new byte [256];
|
||||
int bytesRead = stream.Read (buffer, 0, buffer.Length);
|
||||
if (stream.CanSeek) stream.Seek (originalPos, SeekOrigin.Begin);
|
||||
if (bytesRead == 0) return string.Empty;
|
||||
IntPtr mimePtr;
|
||||
int hr = FindMimeFromData (
|
||||
IntPtr.Zero,
|
||||
null,
|
||||
buffer,
|
||||
bytesRead,
|
||||
null,
|
||||
FMFD_RETURNUPDATEDIMGMIMES | FMFD_IGNOREMIMETEXTPLAIN | FMFD_URLASFILENAME,
|
||||
out mimePtr,
|
||||
0);
|
||||
string mime = string.Empty;
|
||||
if (hr == 0 && mimePtr != IntPtr.Zero)
|
||||
{
|
||||
mime = Marshal.PtrToStringUni (mimePtr);
|
||||
Marshal.FreeCoTaskMem (mimePtr);
|
||||
}
|
||||
if (string.IsNullOrEmpty (mime))
|
||||
{
|
||||
// fallback by magic bytes
|
||||
if (bytesRead >= 8 && buffer [0] == 0x89 && buffer [1] == 0x50 && buffer [2] == 0x4E && buffer [3] == 0x47 &&
|
||||
buffer [4] == 0x0D && buffer [5] == 0x0A && buffer [6] == 0x1A && buffer [7] == 0x0A)
|
||||
mime = "image/png";
|
||||
else if (bytesRead >= 3 && buffer [0] == 0xFF && buffer [1] == 0xD8)
|
||||
mime = "image/jpeg";
|
||||
else if (bytesRead >= 6 && Encoding.ASCII.GetString (buffer, 0, 6) == "GIF89a")
|
||||
mime = "image/gif";
|
||||
else if (bytesRead >= 2 && buffer [0] == 'B' && buffer [1] == 'M')
|
||||
mime = "image/bmp";
|
||||
else if (bytesRead >= 12 && Encoding.ASCII.GetString (buffer, 0, 4) == "RIFF" &&
|
||||
Encoding.ASCII.GetString (buffer, 8, 4) == "WEBP")
|
||||
mime = "image/webp";
|
||||
else if (bytesRead >= 4 && buffer [0] == 0x00 && buffer [1] == 0x00 && buffer [2] == 0x01 && buffer [3] == 0x00)
|
||||
mime = "image/x-icon";
|
||||
else
|
||||
mime = "application/octet-stream";
|
||||
}
|
||||
return mime;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
public static string FileToDataUrl (string filePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty (filePath)) return string.Empty;
|
||||
try
|
||||
{
|
||||
using (FileStream fs = new FileStream (filePath, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
if (fs.Length == 0) return string.Empty;
|
||||
string mime = GetMimeTypeFromStream (fs);
|
||||
if (string.IsNullOrEmpty (mime)) return string.Empty;
|
||||
byte [] bytes = new byte [fs.Length];
|
||||
fs.Seek (0, SeekOrigin.Begin);
|
||||
int read = fs.Read (bytes, 0, bytes.Length);
|
||||
if (read != bytes.Length) return string.Empty;
|
||||
string base64 = Convert.ToBase64String (bytes);
|
||||
return $"data:{mime};base64,{base64}";
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class BaseInfoSectWithPRISingle: BaseInfoSection
|
||||
{
|
||||
protected Ref<ManifestReader> m_reader = new Ref<ManifestReader> (null);
|
||||
protected Ref<PriReader> m_pri = new Ref<PriReader> (null);
|
||||
protected Ref<bool> m_usePri = new Ref<bool> (false);
|
||||
protected Ref<bool> m_enablePri = new Ref<bool> (false);
|
||||
public BaseInfoSectWithPRISingle (ref IntPtr hReader, ManifestReader reader, ref PriReader pri, ref bool usePri, ref bool enablePri) : base (ref hReader)
|
||||
{
|
||||
m_reader.Set (reader);
|
||||
m_pri.Set (pri);
|
||||
m_usePri.Set (usePri);
|
||||
m_enablePri.Set (enablePri);
|
||||
}
|
||||
public new void Dispose ()
|
||||
{
|
||||
try { m_reader.Set (null); } catch (Exception) { }
|
||||
try { m_pri.Set (null); } catch (Exception) { }
|
||||
m_usePri = null;
|
||||
m_enablePri = null;
|
||||
m_hReader = null;
|
||||
}
|
||||
~BaseInfoSectWithPRISingle () { Dispose (); }
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class MRIdentity: BaseInfoSection, Info.IIdentity
|
||||
{
|
||||
public MRIdentity (ref IntPtr hReader) : base (ref hReader) { }
|
||||
protected string StringValue (uint name)
|
||||
{
|
||||
var ptr = PackageReadHelper.GetManifestIdentityStringValue (m_hReader, name);
|
||||
return PackageReadHelper.GetStringAndFreeFromPkgRead (ptr) ?? "";
|
||||
}
|
||||
public string FamilyName { get { return StringValue (2); } }
|
||||
public string FullName { get { return StringValue (3); } }
|
||||
public string Name { get { return StringValue (0); } }
|
||||
public List<Architecture> ProcessArchitecture
|
||||
{
|
||||
get
|
||||
{
|
||||
var list = new List<Architecture> ();
|
||||
uint uarch = 0;
|
||||
PackageReadHelper.GetManifestIdentityArchitecture (m_hReader, out uarch);
|
||||
var t = PackageReadHelper.GetManifestType (m_hReader);
|
||||
switch (t)
|
||||
{
|
||||
case 1:
|
||||
switch (uarch)
|
||||
{
|
||||
case 0x1: list.Add (Architecture.x86); break;
|
||||
case 0x2: list.Add (Architecture.x64); break;
|
||||
case 0x4: list.Add (Architecture.ARM); break;
|
||||
case 0x8: list.Add (Architecture.ARM64); break;
|
||||
case 0xE: list.Add (Architecture.Neutral); break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if ((uarch & 0x1) != 0) list.Add (Architecture.x86);
|
||||
if ((uarch & 0x2) != 0) list.Add (Architecture.x64);
|
||||
if ((uarch & 0x4) != 0) list.Add (Architecture.ARM);
|
||||
if ((uarch & 0x8) != 0) list.Add (Architecture.ARM64);
|
||||
break;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
public string Publisher { get { return StringValue (1); } }
|
||||
public string ResourceId { get { return StringValue (4); } }
|
||||
public DataUtils.Version Version
|
||||
{
|
||||
get
|
||||
{
|
||||
PackageReadHelper.VERSION ver = new PackageReadHelper.VERSION ();
|
||||
PackageReadHelper.GetManifestIdentityVersion (m_hReader, out ver);
|
||||
return new DataUtils.Version (ver.major, ver.minor, ver.build, ver.revision);
|
||||
}
|
||||
}
|
||||
public override object BuildJSON ()
|
||||
{
|
||||
return new
|
||||
{
|
||||
name = Name,
|
||||
package_full_name = FullName,
|
||||
package_family_name = FamilyName,
|
||||
publisher = Publisher,
|
||||
resource_id = ResourceId,
|
||||
architecture = ProcessArchitecture.Select (e => (int)e).ToList (),
|
||||
version = Version.BuildJSON ()
|
||||
};
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class MRProperties: BaseInfoSectWithPRISingle, Info.IProperties
|
||||
{
|
||||
public MRProperties (ref IntPtr hReader, ManifestReader reader, ref PriReader priBundle, ref bool usePri, ref bool enablePri) : base (ref hReader, reader, ref priBundle, ref usePri, ref enablePri) { }
|
||||
protected string StringValue (string attr)
|
||||
{
|
||||
var ptr = PackageReadHelper.GetManifestPropertiesStringValue (m_hReader, attr);
|
||||
return PackageReadHelper.GetStringAndFreeFromPkgRead (ptr) ?? "";
|
||||
}
|
||||
protected bool BoolValue (string attr, bool defaultValue = false)
|
||||
{
|
||||
int ret = 0;
|
||||
HRESULT hr = PackageReadHelper.GetManifestPropertiesBoolValue (m_hReader, attr, out ret);
|
||||
if (hr.Succeeded) return ret != 0;
|
||||
else return defaultValue;
|
||||
}
|
||||
protected string StringResValue (string attr)
|
||||
{
|
||||
var res = StringValue (attr);
|
||||
try
|
||||
{
|
||||
if (m_usePri && m_enablePri)
|
||||
{
|
||||
if (PriFileHelper.IsMsResourcePrefix (res))
|
||||
return m_pri.Value.String (res) ?? res;
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
return res;
|
||||
}
|
||||
protected string PathResValue (string attr)
|
||||
{
|
||||
var res = StringValue (attr);
|
||||
try
|
||||
{
|
||||
if (m_usePri && m_enablePri)
|
||||
{
|
||||
var resvalue = m_pri.Value.String (res);
|
||||
if (!string.IsNullOrEmpty (resvalue)) return resvalue;
|
||||
else return res;
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
return res;
|
||||
}
|
||||
public string Description { get { return StringResValue ("Description"); } }
|
||||
public string DisplayName { get { return StringResValue ("DisplayName"); } }
|
||||
public bool Framework { get { return BoolValue ("Framework"); } }
|
||||
public string Logo { get { return PathResValue ("Logo"); } }
|
||||
public string LogoBase64
|
||||
{
|
||||
get
|
||||
{
|
||||
var root = m_reader.Value.FileRoot;
|
||||
var logopath = Path.Combine (root, Logo);
|
||||
var ret = DataUrlHelper.FileToDataUrl (logopath);
|
||||
if (!string.IsNullOrWhiteSpace (ret)) return ret;
|
||||
logopath = Path.Combine (root, StringValue ("Logo"));
|
||||
ret = DataUrlHelper.FileToDataUrl (logopath);
|
||||
if (!string.IsNullOrWhiteSpace (ret)) return ret;
|
||||
return String.Empty;
|
||||
}
|
||||
}
|
||||
public string Publisher { get { return StringResValue ("PublisherDisplayName"); } }
|
||||
public bool ResourcePackage { get { return BoolValue ("ResourcePackage"); } }
|
||||
public override object BuildJSON ()
|
||||
{
|
||||
return new
|
||||
{
|
||||
display_name = DisplayName,
|
||||
description = Description,
|
||||
publisher_display_name = Publisher,
|
||||
Framework = Framework,
|
||||
resource_package = ResourcePackage,
|
||||
logo = Logo,
|
||||
logo_base64 = LogoBase64
|
||||
};
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class MRApplication: Dictionary<string, string>
|
||||
{
|
||||
protected Ref<IntPtr> m_hReader = IntPtr.Zero;
|
||||
protected Ref<PriReader> m_pri = null;
|
||||
protected Ref<bool> m_usePri = false;
|
||||
protected Ref<bool> m_enablePri = false;
|
||||
protected string m_root = String.Empty;
|
||||
public MRApplication (ref IntPtr hReader, ref PriReader priBundle, ref bool usePri, ref bool enablePri, string rootDir) : base (StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
m_hReader = hReader;
|
||||
m_pri = priBundle;
|
||||
m_usePri = usePri;
|
||||
m_enablePri = enablePri;
|
||||
m_root = rootDir;
|
||||
}
|
||||
public MRApplication (ref Ref<IntPtr> m_hReader, ref Ref<PriReader> m_priBundle, ref Ref<bool> m_usePri, ref Ref<bool> m_enablePri, string rootDir)
|
||||
{
|
||||
this.m_hReader = m_hReader;
|
||||
this.m_pri = m_priBundle;
|
||||
this.m_usePri = m_usePri;
|
||||
this.m_enablePri = m_enablePri;
|
||||
this.m_root = rootDir;
|
||||
}
|
||||
public string UserModelID { get { return this ["AppUserModelID"]; } }
|
||||
protected bool EnablePri ()
|
||||
{
|
||||
if (m_pri == null || m_pri.Value == null) return false;
|
||||
if (!m_usePri.Value) return false;
|
||||
return m_enablePri.Value;
|
||||
}
|
||||
protected string StringResValue (string attr)
|
||||
{
|
||||
try
|
||||
{
|
||||
var res = this [attr];
|
||||
try
|
||||
{
|
||||
if (m_usePri && m_enablePri)
|
||||
{
|
||||
if (PriFileHelper.IsMsResourcePrefix (res))
|
||||
return m_pri.Value.String (res) ?? res;
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
return res;
|
||||
}
|
||||
catch (Exception) { return String.Empty; }
|
||||
}
|
||||
protected string PriGetRes (string resName)
|
||||
{
|
||||
if (string.IsNullOrEmpty (resName)) return string.Empty;
|
||||
if (m_pri == null || m_pri.Value == null) return string.Empty;
|
||||
return m_pri.Value.Resource (resName);
|
||||
}
|
||||
protected bool IsFilePathKey (string key)
|
||||
{
|
||||
foreach (var i in ConstData.FilePathItems)
|
||||
if ((i?.Trim ()?.ToLower () ?? "") == (key?.Trim ()?.ToLower () ?? ""))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
public new string this [string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
string value;
|
||||
if (!TryGetValue (key, out value))
|
||||
{
|
||||
value = string.Empty;
|
||||
base [key] = value;
|
||||
}
|
||||
if (!EnablePri ()) return value;
|
||||
if (PriFileHelper.IsMsResourcePrefix (value))
|
||||
{
|
||||
string pri = PriGetRes (value);
|
||||
return string.IsNullOrEmpty (pri) ? value : pri;
|
||||
}
|
||||
if (IsFilePathKey (key) && !string.IsNullOrEmpty (value))
|
||||
{
|
||||
string pri = PriGetRes (value);
|
||||
return string.IsNullOrEmpty (pri) ? value : pri;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
public string At (string key)
|
||||
{
|
||||
string value;
|
||||
if (!TryGetValue (key, out value)) throw new KeyNotFoundException ($"PRBaseApplication.At: key \"{key}\" not found");
|
||||
if (!EnablePri ()) return value;
|
||||
if (PriFileHelper.IsMsResourcePrefix (value))
|
||||
{
|
||||
string pri = PriGetRes (value);
|
||||
if (!string.IsNullOrEmpty (pri))
|
||||
return pri;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public string NewAt (string key, bool toPriString)
|
||||
{
|
||||
string value;
|
||||
if (!TryGetValue (key, out value))
|
||||
{
|
||||
value = string.Empty;
|
||||
base [key] = value;
|
||||
}
|
||||
if (!EnablePri () && toPriString) return value;
|
||||
if (PriFileHelper.IsMsResourcePrefix (value))
|
||||
{
|
||||
string pri = PriGetRes (value);
|
||||
return string.IsNullOrEmpty (pri) ? value : pri;
|
||||
}
|
||||
if (IsFilePathKey (key) && !string.IsNullOrEmpty (value))
|
||||
{
|
||||
string pri = PriGetRes (value);
|
||||
return string.IsNullOrEmpty (pri) ? value : pri;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public string NewAtBase64 (string key)
|
||||
{
|
||||
string value = NewAt (key, true);
|
||||
if (!IsFilePathKey (key) || string.IsNullOrEmpty (value)) return "";
|
||||
switch (PackageReadHelper.GetPackageType (m_hReader))
|
||||
{
|
||||
case 1: // PKGTYPE_APPX
|
||||
{
|
||||
var root = m_root;
|
||||
var logopath = Path.Combine (root, NewAt (key, true));
|
||||
var ret = DataUrlHelper.FileToDataUrl (logopath);
|
||||
if (!string.IsNullOrWhiteSpace (ret)) return ret;
|
||||
logopath = Path.Combine (root, NewAt (key, false));
|
||||
ret = DataUrlHelper.FileToDataUrl (logopath);
|
||||
if (!string.IsNullOrWhiteSpace (ret)) return ret;
|
||||
return String.Empty;
|
||||
} break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
public static bool operator == (MRApplication a, MRApplication b)
|
||||
{
|
||||
if (ReferenceEquals (a, b)) return true;
|
||||
if ((object)a == null || (object)b == null) return false;
|
||||
return string.Equals (a.UserModelID, b.UserModelID, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
public static bool operator != (MRApplication a, MRApplication b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
var other = obj as MRApplication;
|
||||
if (other == null) return false;
|
||||
return this == other;
|
||||
}
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return (UserModelID ?? "").ToLowerInvariant ().GetHashCode ();
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class MRApplications: BaseInfoSectWithPRISingle, IEnumerable<MRApplication>
|
||||
{
|
||||
private IntPtr _hList = IntPtr.Zero;
|
||||
private List<MRApplication> _apps;
|
||||
public MRApplications (
|
||||
ref IntPtr hReader,
|
||||
ManifestReader reader,
|
||||
ref PriReader priBundle,
|
||||
ref bool usePri,
|
||||
ref bool enablePri)
|
||||
: base (ref hReader, reader, ref priBundle, ref usePri, ref enablePri)
|
||||
{
|
||||
if (IsValid)
|
||||
{
|
||||
_hList = PackageReadHelper.GetManifestApplications (m_hReader.Value);
|
||||
}
|
||||
}
|
||||
#region Dispose
|
||||
public new void Dispose ()
|
||||
{
|
||||
if (_hList != IntPtr.Zero)
|
||||
{
|
||||
PackageReadHelper.DestroyManifestApplications (_hList);
|
||||
_hList = IntPtr.Zero;
|
||||
}
|
||||
base.Dispose ();
|
||||
}
|
||||
~MRApplications ()
|
||||
{
|
||||
Dispose ();
|
||||
}
|
||||
#endregion
|
||||
#region 属性:Applications
|
||||
public List<MRApplication> Applications
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_apps == null)
|
||||
_apps = ReadApplications ();
|
||||
return _apps;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region 索引器
|
||||
public MRApplication this [int index]
|
||||
{
|
||||
get { return Applications [index]; }
|
||||
}
|
||||
public MRApplication this [string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var app in Applications)
|
||||
{
|
||||
if (string.Equals (app.UserModelID, key, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return app;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region IEnumerable
|
||||
public IEnumerator<MRApplication> GetEnumerator ()
|
||||
{
|
||||
return Applications.GetEnumerator ();
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator ()
|
||||
{
|
||||
return GetEnumerator ();
|
||||
}
|
||||
#endregion
|
||||
#region 内部解析逻辑(核心等价 C++ get)
|
||||
private List<MRApplication> ReadApplications ()
|
||||
{
|
||||
var list = new List<MRApplication> ();
|
||||
if (_hList == IntPtr.Zero) return list;
|
||||
IntPtr hMapList = PackageReadHelper.ApplicationsToMap (_hList);
|
||||
if (hMapList == IntPtr.Zero) return list;
|
||||
try
|
||||
{
|
||||
uint count = (uint)Marshal.ReadInt32 (hMapList);
|
||||
int baseOffset = Marshal.SizeOf (typeof (uint));
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
IntPtr hKeyValues = Marshal.ReadIntPtr (hMapList, baseOffset + i * IntPtr.Size);
|
||||
if (hKeyValues == IntPtr.Zero) continue;
|
||||
list.Add (ReadSingleApplication (hKeyValues));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
PackageReadHelper.DestroyApplicationsMap (hMapList);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
private MRApplication ReadSingleApplication (IntPtr hKeyValues)
|
||||
{
|
||||
var app = new MRApplication (ref m_hReader, ref m_pri, ref m_usePri, ref m_enablePri, m_reader.Value.FileRoot);
|
||||
int pairCount = Marshal.ReadInt32 (hKeyValues);
|
||||
IntPtr arrayBase = IntPtr.Add (hKeyValues, sizeof (uint));
|
||||
for (int i = 0; i < pairCount; i++)
|
||||
{
|
||||
IntPtr pPairPtr = Marshal.ReadIntPtr (arrayBase, i * IntPtr.Size);
|
||||
if (pPairPtr == IntPtr.Zero) continue;
|
||||
PackageReadHelper.PAIR_PVOID pair =
|
||||
(PackageReadHelper.PAIR_PVOID)Marshal.PtrToStructure (pPairPtr, typeof (PackageReadHelper.PAIR_PVOID));
|
||||
if (pair.lpKey == IntPtr.Zero) continue;
|
||||
string key = Marshal.PtrToStringUni (pair.lpKey);
|
||||
if (string.IsNullOrEmpty (key)) continue;
|
||||
string value = pair.lpValue != IntPtr.Zero
|
||||
? Marshal.PtrToStringUni (pair.lpValue)
|
||||
: string.Empty;
|
||||
app.Add (key, value);
|
||||
}
|
||||
return app;
|
||||
}
|
||||
#endregion
|
||||
public override object BuildJSON ()
|
||||
{
|
||||
using (var apps = this)
|
||||
{
|
||||
return apps.Select (app => {
|
||||
var dict = new Dictionary<string, object> (StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var kv in app)
|
||||
{
|
||||
dict [kv.Key] = kv.Value;
|
||||
if (ConstData.IsFilePathKey (kv.Key))
|
||||
{
|
||||
dict [(kv.Key?.Trim () ?? "") + "_Base64"] = app.NewAtBase64 (kv.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
dict [kv.Key] = app.NewAt (kv.Key, m_usePri.Value && m_enablePri.Value) ?? kv.Value;
|
||||
}
|
||||
}
|
||||
dict ["AppUserModelID"] = app.UserModelID;
|
||||
return dict;
|
||||
}).ToList ();
|
||||
}
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class MRCapabilities: BaseInfoSection, ICapabilities
|
||||
{
|
||||
public MRCapabilities (ref IntPtr hReader) : base (ref hReader) { }
|
||||
public List<string> Capabilities
|
||||
{
|
||||
get
|
||||
{
|
||||
var ret = new List<string> ();
|
||||
if (!IsValid) return ret;
|
||||
IntPtr hList = PackageReadHelper.GetManifestCapabilitiesList (m_hReader.Value);
|
||||
if (hList == IntPtr.Zero) return ret;
|
||||
try
|
||||
{
|
||||
uint count = (uint)Marshal.ReadInt32 (hList);
|
||||
int baseOffset = Marshal.SizeOf (typeof (uint)); // dwSize 后
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
IntPtr pStr = Marshal.ReadIntPtr (hList, baseOffset + i * IntPtr.Size);
|
||||
if (pStr == IntPtr.Zero) continue;
|
||||
string s = Marshal.PtrToStringUni (pStr);
|
||||
if (!string.IsNullOrEmpty (s)) ret.Add (s);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
PackageReadHelper.DestroyWStringList (hList);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
public List<string> DeviceCapabilities
|
||||
{
|
||||
get
|
||||
{
|
||||
var ret = new List<string> ();
|
||||
if (!IsValid) return ret;
|
||||
IntPtr hList = PackageReadHelper.GetManifestDeviceCapabilitiesList (m_hReader.Value);
|
||||
if (hList == IntPtr.Zero) return ret;
|
||||
try
|
||||
{
|
||||
uint count = (uint)Marshal.ReadInt32 (hList);
|
||||
int baseOffset = Marshal.SizeOf (typeof (uint)); // dwSize 后
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
IntPtr pStr = Marshal.ReadIntPtr (hList, baseOffset + i * IntPtr.Size);
|
||||
if (pStr == IntPtr.Zero) continue;
|
||||
string s = Marshal.PtrToStringUni (pStr);
|
||||
if (!string.IsNullOrEmpty (s)) ret.Add (s);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
PackageReadHelper.DestroyWStringList (hList);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
public List<string> CapabilityDisplayNames
|
||||
{
|
||||
get
|
||||
{
|
||||
var caps = Capabilities;
|
||||
var dev = DeviceCapabilities;
|
||||
var ret = new List<string> ();
|
||||
foreach (var c in caps)
|
||||
{
|
||||
var capname = CacheData.GetPackageCapabilityDisplayName (c);
|
||||
if (String.IsNullOrWhiteSpace (capname)) ret.Add (c);
|
||||
else ret.Add (capname);
|
||||
}
|
||||
foreach (var d in dev)
|
||||
{
|
||||
var dcapname = CacheData.GetPackageCapabilityDisplayName (d);
|
||||
if (!String.IsNullOrWhiteSpace (dcapname)) ret.Add (dcapname);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
public override object BuildJSON ()
|
||||
{
|
||||
return new
|
||||
{
|
||||
capabilities_name = Capabilities,
|
||||
device_capabilities = DeviceCapabilities,
|
||||
scales = CapabilityDisplayNames
|
||||
};
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class MRDependencies: BaseInfoSection, IEnumerable<DependencyInfo>
|
||||
{
|
||||
public MRDependencies (ref IntPtr hReader) : base (ref hReader) { }
|
||||
public List<DependencyInfo> Dependencies
|
||||
{
|
||||
get
|
||||
{
|
||||
var output = new List<DependencyInfo> ();
|
||||
if (!IsValid) return output;
|
||||
IntPtr hList = PackageReadHelper.GetManifestDependencesInfoList (m_hReader);
|
||||
if (hList == IntPtr.Zero) return output;
|
||||
try
|
||||
{
|
||||
var deps = PackageReadHelper.ReadDependencyInfoList (hList);
|
||||
foreach (var dep in deps)
|
||||
{
|
||||
// dep.lpName / dep.lpPublisher 是 IntPtr
|
||||
string name = Marshal.PtrToStringUni (dep.lpName) ?? "";
|
||||
string publisher = Marshal.PtrToStringUni (dep.lpPublisher) ?? "";
|
||||
// VERSION 直接映射为 System.Version
|
||||
var ver = new DataUtils.Version (dep.verMin.major, dep.verMin.minor, dep.verMin.build, dep.verMin.revision);
|
||||
output.Add (new DependencyInfo (name, publisher, ver));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
PackageReadHelper.DestroyDependencesInfoList (hList);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
public DependencyInfo this [int index] => Dependencies [index];
|
||||
public IEnumerator<DependencyInfo> GetEnumerator ()
|
||||
{
|
||||
return Dependencies.GetEnumerator ();
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator ()
|
||||
{
|
||||
return GetEnumerator ();
|
||||
}
|
||||
public override object BuildJSON ()
|
||||
{
|
||||
return this.Select (d => new {
|
||||
name = d.Name,
|
||||
publisher = d.Publisher,
|
||||
vermin = d.Version.BuildJSON ()
|
||||
}).ToList ();
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class MRResources: BaseInfoSection, IResources
|
||||
{
|
||||
public MRResources (ref IntPtr hReader) : base (ref hReader) { }
|
||||
public List<DXFeatureLevel> DXFeatures
|
||||
{
|
||||
get
|
||||
{
|
||||
var ret = new List<DXFeatureLevel> ();
|
||||
try
|
||||
{
|
||||
var dw = PackageReadHelper.GetManifestResourcesDxFeatureLevels (m_hReader);
|
||||
if ((dw & 0x1) != 0) ret.Add (DXFeatureLevel.Level9);
|
||||
if ((dw & 0x2) != 0) ret.Add (DXFeatureLevel.Level10);
|
||||
if ((dw & 0x4) != 0) ret.Add (DXFeatureLevel.Level11);
|
||||
if ((dw & 0x8) != 0) ret.Add (DXFeatureLevel.Level12);
|
||||
}
|
||||
catch (Exception) { }
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
public List<string> Languages
|
||||
{
|
||||
get
|
||||
{
|
||||
var ret = new List<string> ();
|
||||
if (!IsValid) return ret;
|
||||
IntPtr hList = PackageReadHelper.GetManifestResourcesLanguages (m_hReader.Value);
|
||||
if (hList == IntPtr.Zero) return ret;
|
||||
try
|
||||
{
|
||||
ret = PackageReadHelper.ReadWStringList (hList).ToList ();
|
||||
}
|
||||
finally
|
||||
{
|
||||
PackageReadHelper.DestroyWStringList (hList);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
public List<int> Languages_LCID
|
||||
{
|
||||
get
|
||||
{
|
||||
var ret = new List<int> ();
|
||||
if (!IsValid) return ret;
|
||||
IntPtr hList = PackageReadHelper.GetManifestResourcesLanguagesToLcid (m_hReader.Value);
|
||||
if (hList == IntPtr.Zero) return ret;
|
||||
try
|
||||
{
|
||||
ret = PackageReadHelper.ReadLcidList (hList).ToList ();
|
||||
}
|
||||
finally
|
||||
{
|
||||
PackageReadHelper.DestroyResourcesLanguagesLcidList (hList);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
public List<int> Scales
|
||||
{
|
||||
get
|
||||
{
|
||||
var ret = new List<int> ();
|
||||
if (!IsValid) return ret;
|
||||
IntPtr hList = PackageReadHelper.GetManifestResourcesLanguagesToLcid (m_hReader.Value);
|
||||
if (hList == IntPtr.Zero) return ret;
|
||||
try
|
||||
{
|
||||
ret = PackageReadHelper.ReadUInt32List (hList).Select (e => (int)e).ToList ();
|
||||
}
|
||||
finally
|
||||
{
|
||||
PackageReadHelper.DestroyUInt32List (hList);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
public override object BuildJSON ()
|
||||
{
|
||||
return new
|
||||
{
|
||||
dx_feature_levels = DXFeatures.Select (e => (int)e).ToList (),
|
||||
languages = Languages,
|
||||
scales = Scales
|
||||
};
|
||||
}
|
||||
}
|
||||
public class MRPrerequisites: BaseInfoSection, IPrerequisites
|
||||
{
|
||||
public MRPrerequisites (ref IntPtr hReader) : base (ref hReader) { }
|
||||
protected DataUtils.Version GetVersion (string name)
|
||||
{
|
||||
PackageReadHelper.VERSION ver;
|
||||
bool res = PackageReadHelper.GetManifestPrerequisite (m_hReader, name, out ver);
|
||||
if (res) return new DataUtils.Version (ver.major, ver.minor, ver.build, ver.revision);
|
||||
else return new DataUtils.Version ();
|
||||
}
|
||||
protected string GetVersionDescription (string name)
|
||||
{
|
||||
var ptr = PackageReadHelper.GetManifestPrerequistieSystemVersionName (m_hReader, name);
|
||||
return PackageReadHelper.GetStringAndFreeFromPkgRead (ptr) ?? "";
|
||||
}
|
||||
public string OSMaxVersionDescription { get { return GetVersionDescription ("OSMaxVersionTested"); } }
|
||||
public DataUtils.Version OSMaxVersionTested { get { return GetVersion ("OSMaxVersionTested"); } }
|
||||
public DataUtils.Version OSMinVersion { get { return GetVersion ("OSMinVersion"); } }
|
||||
public string OSMinVersionDescription { get { return GetVersionDescription ("OSMinVersion"); } }
|
||||
public override object BuildJSON ()
|
||||
{
|
||||
return new
|
||||
{
|
||||
os_min_version = OSMinVersion.BuildJSON (),
|
||||
os_min_version_description = OSMinVersionDescription,
|
||||
os_max_version_tested = OSMaxVersionTested.BuildJSON (),
|
||||
os_max_version_tested_description = OSMaxVersionDescription
|
||||
};
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class ManifestReader: IDisposable
|
||||
{
|
||||
private IntPtr m_hReader = PackageReadHelper.CreateManifestReader ();
|
||||
private string m_filePath = string.Empty;
|
||||
private bool m_usePRI = false;
|
||||
private bool m_enablePRI = false;
|
||||
private PriReader m_pri = null;
|
||||
public PriReader PriFile => m_pri;
|
||||
public IntPtr Instance => m_hReader;
|
||||
public string FileRoot{ get { return Path.GetDirectoryName (m_filePath); } }
|
||||
private void InitPri ()
|
||||
{
|
||||
m_pri?.Dispose ();
|
||||
if (!m_usePRI) return;
|
||||
#region Get PRI IStream
|
||||
switch (Type)
|
||||
{
|
||||
case PackageType.Appx:
|
||||
{
|
||||
var pripath = Path.Combine (FileRoot, "resources.pri");
|
||||
m_pri = new PriReader (pripath);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endregion
|
||||
return;
|
||||
}
|
||||
public PackageType Type
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = PackageReadHelper.GetManifestType (m_hReader);
|
||||
switch (value)
|
||||
{
|
||||
case 0: return PackageType.Unknown;
|
||||
case 1: return PackageType.Appx;
|
||||
case 2: return PackageType.Bundle;
|
||||
}
|
||||
return PackageType.Unknown;
|
||||
}
|
||||
}
|
||||
public PackageRole Role
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = PackageReadHelper.GetManifestRole (m_hReader);
|
||||
switch (value)
|
||||
{
|
||||
case 0: return PackageRole.Unknown;
|
||||
case 1: return PackageRole.Application;
|
||||
case 2: return PackageRole.Framework;
|
||||
case 3: return PackageRole.Resource;
|
||||
}
|
||||
return PackageRole.Unknown;
|
||||
}
|
||||
}
|
||||
public bool IsApplicationManifest { get { return Role == PackageRole.Application; } }
|
||||
public bool IsValid { get { return m_hReader != IntPtr.Zero && Type != PackageType.Unknown; } }
|
||||
/// <summary>使用 PRI,启用后会预先处理 PRI 文件。</summary>
|
||||
public bool UsePri { get { return m_usePRI; } set { m_usePRI = value; InitPri (); } }
|
||||
/// <summary>允许 PRI,启用后会返回读取的 PRI 文件结果,需保证 UsePri 开启。</summary>
|
||||
public bool EnablePri { get { return m_enablePRI; } set { m_enablePRI = value; } }
|
||||
public MRIdentity Identity { get { return new MRIdentity (ref m_hReader); } }
|
||||
public MRProperties Properties { get { return new MRProperties (ref m_hReader, this, ref m_pri, ref m_usePRI, ref m_enablePRI); } }
|
||||
public MRPrerequisites Prerequisites { get { return new MRPrerequisites (ref m_hReader); } }
|
||||
public MRResources Resources { get { return new MRResources (ref m_hReader); } }
|
||||
public MRApplications Applications { get { return new MRApplications (ref m_hReader, this, ref m_pri, ref m_usePRI, ref m_enablePRI); } }
|
||||
public MRCapabilities Capabilities { get { return new MRCapabilities (ref m_hReader); } }
|
||||
public MRDependencies Dependencies { get { return new MRDependencies (ref m_hReader); } }
|
||||
public void Dispose ()
|
||||
{
|
||||
var lastvalue = m_usePRI;
|
||||
m_usePRI = false;
|
||||
InitPri ();
|
||||
m_usePRI = lastvalue;
|
||||
if (m_hReader != IntPtr.Zero)
|
||||
{
|
||||
PackageReadHelper.DestroyManifestReader (m_hReader);
|
||||
m_hReader = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
~ManifestReader () { Dispose (); }
|
||||
public string FilePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_filePath;
|
||||
}
|
||||
set
|
||||
{
|
||||
PackageReadHelper.LoadManifestFromFile (m_hReader, m_filePath = value);
|
||||
}
|
||||
}
|
||||
public ManifestReader (string filePath) { FilePath = filePath; }
|
||||
public ManifestReader () { }
|
||||
public string JSONText { get { return BuildJsonText (); } }
|
||||
public string BuildJsonText ()
|
||||
{
|
||||
var obj = BuildJsonObject ();
|
||||
return Newtonsoft.Json.JsonConvert.SerializeObject (
|
||||
obj,
|
||||
Newtonsoft.Json.Formatting.Indented
|
||||
);
|
||||
}
|
||||
public void BuildJsonTextAsync (object callback)
|
||||
{
|
||||
if (callback == null) return;
|
||||
Thread thread = new Thread (() => {
|
||||
string json = string.Empty;
|
||||
try
|
||||
{
|
||||
json = BuildJsonText ();
|
||||
}
|
||||
catch
|
||||
{
|
||||
json = string.Empty;
|
||||
}
|
||||
JSHelper.CallJS (callback, json);
|
||||
});
|
||||
thread.SetApartmentState (ApartmentState.MTA);
|
||||
thread.IsBackground = true;
|
||||
thread.Start ();
|
||||
}
|
||||
private object BuildJsonObject ()
|
||||
{
|
||||
return new
|
||||
{
|
||||
valid = IsValid,
|
||||
filepath = FilePath,
|
||||
type = (int)Type,
|
||||
role = (int)Role,
|
||||
identity = Identity.BuildJSON (),
|
||||
properties = Properties.BuildJSON (),
|
||||
prerequisites = Prerequisites.BuildJSON (),
|
||||
resources = Resources.BuildJSON (),
|
||||
capabilities = Capabilities.BuildJSON (),
|
||||
dependencies = Dependencies.BuildJSON (),
|
||||
applications = Applications.BuildJSON ()
|
||||
};
|
||||
}
|
||||
public static bool AddApplicationItem (string itemName) => PackageReadHelper.AddPackageApplicationItemGetName (itemName);
|
||||
public static bool RemoveApplicationItem (string itemName) => PackageReadHelper.RemovePackageApplicationItemGetName (itemName);
|
||||
}
|
||||
}
|
||||
619
AppxPackage/PackageManager.cs
Normal file
619
AppxPackage/PackageManager.cs
Normal file
@@ -0,0 +1,619 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AppxPackage.Info;
|
||||
using NativeWrappers;
|
||||
using System.Runtime.InteropServices;
|
||||
using DataUtils;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
|
||||
namespace AppxPackage
|
||||
{
|
||||
public enum DeploymentOptions
|
||||
{
|
||||
None = 0,
|
||||
ForceAppShutdown = 0x00000001,
|
||||
DevelopmentMode = 0x00000002,
|
||||
InstallAllResources = 0x00000020
|
||||
};
|
||||
public enum PackageStatus
|
||||
{
|
||||
Normal = 0,
|
||||
LicenseInvalid = 1,
|
||||
Modified = 2,
|
||||
Tampered = 3
|
||||
};
|
||||
public static class ImageUriToBase64
|
||||
{
|
||||
public static string ConvertToDataUri (string uriString)
|
||||
{
|
||||
if (string.IsNullOrEmpty (uriString)) throw new ArgumentNullException ("uriString");
|
||||
Uri uri = new Uri (uriString, UriKind.Absolute);
|
||||
byte [] data;
|
||||
string mime;
|
||||
if (uri.IsFile)
|
||||
{
|
||||
string path = uri.LocalPath;
|
||||
data = File.ReadAllBytes (path);
|
||||
mime = GetMimeFromExtension (Path.GetExtension (path));
|
||||
}
|
||||
else
|
||||
{
|
||||
using (WebClient wc = new WebClient ())
|
||||
{
|
||||
data = wc.DownloadData (uri);
|
||||
mime = GetMimeFromExtension (Path.GetExtension (uri.AbsolutePath));
|
||||
}
|
||||
}
|
||||
string base64 = Convert.ToBase64String (data);
|
||||
return "data:" + mime + ";base64," + base64;
|
||||
}
|
||||
private static string GetMimeFromExtension (string ext)
|
||||
{
|
||||
if (string.IsNullOrEmpty (ext)) return "application/octet-stream";
|
||||
switch (ext.ToLowerInvariant ())
|
||||
{
|
||||
case ".png": return "image/png";
|
||||
case ".jpg":
|
||||
case ".jpeg": return "image/jpeg";
|
||||
case ".gif": return "image/gif";
|
||||
case ".bmp": return "image/bmp";
|
||||
case ".webp": return "image/webp";
|
||||
case ".svg": return "image/svg+xml";
|
||||
default: return "application/octet-stream";
|
||||
}
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class PMIdentity: IIdentity
|
||||
{
|
||||
private string name = "";
|
||||
private string publisher = "";
|
||||
private DataUtils.Version version = new DataUtils.Version ();
|
||||
private IEnumerable<Architecture> archs;
|
||||
private string familyName = "";
|
||||
private string fullName = "";
|
||||
private string resourceId = "";
|
||||
private string publisherId = "";
|
||||
public PMIdentity (string _name, string _publisher, DataUtils.Version _ver, IEnumerable<Architecture> _archs, string _family, string _full, string _resid, string _publisherId)
|
||||
{
|
||||
name = _name;
|
||||
publisher = _publisher;
|
||||
version = _ver;
|
||||
archs = _archs ?? new List<Architecture> ();
|
||||
familyName = _family;
|
||||
fullName = _full;
|
||||
resourceId = _resid;
|
||||
publisherId = _publisherId;
|
||||
}
|
||||
public PMIdentity (PackageManageHelper.FIND_PACKAGE_ID pkgId) :
|
||||
this (
|
||||
Marshal.PtrToStringUni (pkgId.lpName),
|
||||
Marshal.PtrToStringUni (pkgId.lpPublisher),
|
||||
new DataUtils.Version (pkgId.qwVersion),
|
||||
new Architecture [] { (Architecture)pkgId.wProcessArchitecture },
|
||||
Marshal.PtrToStringUni (pkgId.lpFamilyName),
|
||||
Marshal.PtrToStringUni (pkgId.lpFullName),
|
||||
Marshal.PtrToStringUni (pkgId.lpResourceId),
|
||||
Marshal.PtrToStringUni (pkgId.lpPublisherId)
|
||||
)
|
||||
{ }
|
||||
public string FamilyName => familyName;
|
||||
public string FullName => fullName;
|
||||
public string Name => name;
|
||||
public List<Architecture> ProcessArchitecture => archs.ToList ();
|
||||
public string Publisher => publisher;
|
||||
public string PublisherId => publisherId;
|
||||
public string ResourceId => resourceId;
|
||||
public DataUtils.Version Version => version;
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class PMProperties: IProperties
|
||||
{
|
||||
private string desc = "";
|
||||
private string displayName = "";
|
||||
private bool framework = false;
|
||||
private string logo = "";
|
||||
private string publisher = "";
|
||||
private bool isres = false;
|
||||
public PMProperties (string _name, string _pub, string _desc, string _logo, bool _fw, bool _res)
|
||||
{
|
||||
desc = _desc;
|
||||
displayName = _name;
|
||||
framework = _fw;
|
||||
logo = _logo;
|
||||
publisher = _pub;
|
||||
isres = _res;
|
||||
}
|
||||
public PMProperties (PackageManageHelper.FIND_PACKAGE_PROPERTIES prop) :
|
||||
this (
|
||||
Marshal.PtrToStringUni (prop.lpDisplayName),
|
||||
Marshal.PtrToStringUni (prop.lpPublisher),
|
||||
Marshal.PtrToStringUni (prop.lpDescription),
|
||||
Marshal.PtrToStringUni (prop.lpLogoUri),
|
||||
prop.bIsFramework,
|
||||
prop.bIsResourcePackage
|
||||
)
|
||||
{ }
|
||||
public string Description => desc;
|
||||
public string DisplayName => displayName;
|
||||
public bool Framework => framework;
|
||||
public string Logo => logo;
|
||||
public string LogoBase64
|
||||
{
|
||||
get
|
||||
{
|
||||
try { return ImageUriToBase64.ConvertToDataUri (Logo); }
|
||||
catch (Exception) { }
|
||||
return "";
|
||||
}
|
||||
}
|
||||
public string Publisher => publisher;
|
||||
public bool ResourcePackage => isres;
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class PMPackageInfo
|
||||
{
|
||||
public PMIdentity Identity { get; private set; }
|
||||
public PMProperties Properties { get; private set; }
|
||||
public bool IsBundle { get; private set; }
|
||||
public bool DevelopmentMode { get; private set; }
|
||||
public string InstallLocation { get; private set; }
|
||||
public List<string> Users { get; private set; }
|
||||
public List<string> SIDs { get; private set; }
|
||||
public PMPackageInfo (PackageManageHelper.FIND_PACKAGE_INFO info)
|
||||
{
|
||||
Identity = new PMIdentity (info.piIdentity);
|
||||
Properties = new PMProperties (info.piProperties);
|
||||
IsBundle = info.piProperties.bIsBundle;
|
||||
DevelopmentMode = info.piProperties.bIsDevelopmentMode;
|
||||
InstallLocation = Marshal.PtrToStringUni (info.lpInstallLocation);
|
||||
Users = (Marshal.PtrToStringUni (info.lpUsers) ?? "").Split (';').ToList ();
|
||||
SIDs = (Marshal.PtrToStringUni (info.lpSIDs) ?? "").Split (';').ToList ();
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public static class PackageManager
|
||||
{
|
||||
private static DataUtils._I_HResult FromNative (int hr,IntPtr pErrorCode,IntPtr pDetailMsg)
|
||||
{
|
||||
string errCode = null;
|
||||
string detail = null;
|
||||
try
|
||||
{
|
||||
if (pErrorCode != IntPtr.Zero) errCode = Marshal.PtrToStringUni (pErrorCode);
|
||||
if (pDetailMsg != IntPtr.Zero) detail = Marshal.PtrToStringUni (pDetailMsg);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pErrorCode != IntPtr.Zero) PackageManageHelper.PackageManagerFreeString (pErrorCode);
|
||||
if (pDetailMsg != IntPtr.Zero) PackageManageHelper.PackageManagerFreeString (pDetailMsg);
|
||||
}
|
||||
return new DataUtils._I_HResult (hr, errCode, detail);
|
||||
}
|
||||
public delegate void PackageProgressCallback (uint progress);
|
||||
internal sealed class ProgressCallbackHolder
|
||||
{
|
||||
private readonly PackageProgressCallback _callback;
|
||||
public ProgressCallbackHolder (PackageProgressCallback cb)
|
||||
{
|
||||
_callback = cb;
|
||||
Native = new PackageManageHelper.PKGMRR_PROGRESSCALLBACK (OnNative);
|
||||
}
|
||||
public PackageManageHelper.PKGMRR_PROGRESSCALLBACK Native { get; private set; }
|
||||
private void OnNative (uint progress, IntPtr custom)
|
||||
{
|
||||
if (_callback != null)
|
||||
_callback (progress);
|
||||
}
|
||||
}
|
||||
internal sealed class ResultCallbackHolder
|
||||
{
|
||||
public readonly List<PMPackageInfo> RetList = new List<PMPackageInfo> ();
|
||||
public PackageManageHelper.PKGMGR_FINDENUMCALLBACK Callback;
|
||||
public ResultCallbackHolder ()
|
||||
{
|
||||
Callback = OnResult;
|
||||
}
|
||||
private void OnResult (
|
||||
IntPtr nativeInfo,
|
||||
IntPtr pCustom)
|
||||
{
|
||||
RetList.Add (new PMPackageInfo (PackageManageHelper.PtrToFindPackageInfo (nativeInfo)));
|
||||
}
|
||||
}
|
||||
public static DataUtils._I_HResult AddPackage (Uri fileUri, IEnumerable<Uri> depUris, DeploymentOptions options, PackageProgressCallback progress = null)
|
||||
{
|
||||
if (fileUri == null) throw new ArgumentNullException ("Required File URI");
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
var depList = depUris == null ? new List<string> () : depUris.Select (u => u.AbsoluteUri).ToList ();
|
||||
ProgressCallbackHolder holder = null;
|
||||
try
|
||||
{
|
||||
depArray = NativeUtil.AllocStringArray (depList);
|
||||
PackageManageHelper.PKGMRR_PROGRESSCALLBACK nativeCb = null;
|
||||
if (progress != null)
|
||||
{
|
||||
holder = new ProgressCallbackHolder (progress);
|
||||
nativeCb = holder.Native;
|
||||
}
|
||||
int hr = PackageManageHelper.AddAppxPackageFromURI (fileUri.AbsoluteUri, depArray, (uint)options, nativeCb, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return FromNative (hr, pErrCode, pDetail);
|
||||
}
|
||||
finally
|
||||
{
|
||||
NativeUtil.FreeStringArray (depArray, depList.Count);
|
||||
GC.KeepAlive (holder);
|
||||
}
|
||||
}
|
||||
public static DataUtils._I_HResult AddPackage (string filePath, IEnumerable<string> depUris, DeploymentOptions options, PackageProgressCallback progress = null)
|
||||
{
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
var depList = depUris == null ? new List<string> () : depUris.ToList ();
|
||||
ProgressCallbackHolder holder = null;
|
||||
try
|
||||
{
|
||||
depArray = NativeUtil.AllocStringArray (depList);
|
||||
PackageManageHelper.PKGMRR_PROGRESSCALLBACK nativeCb = null;
|
||||
if (progress != null)
|
||||
{
|
||||
holder = new ProgressCallbackHolder (progress);
|
||||
nativeCb = holder.Native;
|
||||
}
|
||||
int hr = PackageManageHelper.AddAppxPackageFromPath (filePath, depArray, (uint)options, nativeCb, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return FromNative (hr, pErrCode, pDetail);
|
||||
}
|
||||
finally
|
||||
{
|
||||
NativeUtil.FreeStringArray (depArray, depList.Count);
|
||||
GC.KeepAlive (holder);
|
||||
}
|
||||
}
|
||||
public static Tuple <DataUtils._I_HResult, List <PMPackageInfo>> GetPackages ()
|
||||
{
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
ResultCallbackHolder callback = null;
|
||||
try
|
||||
{
|
||||
callback = new ResultCallbackHolder ();
|
||||
int hr = PackageManageHelper.GetAppxPackages (callback.Callback, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return Tuple.Create (FromNative (hr, pErrCode, pDetail), callback.RetList);
|
||||
}
|
||||
finally
|
||||
{
|
||||
GC.KeepAlive (callback);
|
||||
}
|
||||
}
|
||||
public static DataUtils._I_HResult RemovePackage (string packageFullName, PackageProgressCallback progress = null)
|
||||
{
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
ProgressCallbackHolder holder = null;
|
||||
try
|
||||
{
|
||||
PackageManageHelper.PKGMRR_PROGRESSCALLBACK nativeCb = null;
|
||||
if (progress != null)
|
||||
{
|
||||
holder = new ProgressCallbackHolder (progress);
|
||||
nativeCb = holder.Native;
|
||||
}
|
||||
int hr = PackageManageHelper.RemoveAppxPackage (packageFullName, nativeCb, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return FromNative (hr, pErrCode, pDetail);
|
||||
}
|
||||
finally
|
||||
{
|
||||
GC.KeepAlive (holder);
|
||||
}
|
||||
}
|
||||
public static DataUtils._I_HResult ClearupPackage (string packageName, string userSID, PackageProgressCallback progress = null)
|
||||
{
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
ProgressCallbackHolder holder = null;
|
||||
try
|
||||
{
|
||||
PackageManageHelper.PKGMRR_PROGRESSCALLBACK nativeCb = null;
|
||||
if (progress != null)
|
||||
{
|
||||
holder = new ProgressCallbackHolder (progress);
|
||||
nativeCb = holder.Native;
|
||||
}
|
||||
int hr = PackageManageHelper.CleanupAppxPackage (packageName, userSID, nativeCb, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return FromNative (hr, pErrCode, pDetail);
|
||||
}
|
||||
finally
|
||||
{
|
||||
GC.KeepAlive (holder);
|
||||
}
|
||||
}
|
||||
public static DataUtils._I_HResult RegisterPackage (Uri manifestUri, IEnumerable<Uri> depUris, DeploymentOptions options, PackageProgressCallback progress = null)
|
||||
{
|
||||
if (manifestUri == null) throw new ArgumentNullException ("Required File URI");
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
var depList = depUris == null ? new List<string> () : depUris.Select (u => u.AbsoluteUri).ToList ();
|
||||
ProgressCallbackHolder holder = null;
|
||||
try
|
||||
{
|
||||
depArray = NativeUtil.AllocStringArray (depList);
|
||||
PackageManageHelper.PKGMRR_PROGRESSCALLBACK nativeCb = null;
|
||||
if (progress != null)
|
||||
{
|
||||
holder = new ProgressCallbackHolder (progress);
|
||||
nativeCb = holder.Native;
|
||||
}
|
||||
int hr = PackageManageHelper.RegisterAppxPackageByUri (manifestUri.AbsoluteUri, depArray, (uint)options, nativeCb, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return FromNative (hr, pErrCode, pDetail);
|
||||
}
|
||||
finally
|
||||
{
|
||||
NativeUtil.FreeStringArray (depArray, depList.Count);
|
||||
GC.KeepAlive (holder);
|
||||
}
|
||||
}
|
||||
public static DataUtils._I_HResult RegisterPackage (string manifestPath, IEnumerable<string> depUris, DeploymentOptions options, PackageProgressCallback progress = null)
|
||||
{
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
var depList = depUris == null ? new List<string> () : depUris.ToList ();
|
||||
ProgressCallbackHolder holder = null;
|
||||
try
|
||||
{
|
||||
depArray = NativeUtil.AllocStringArray (depList);
|
||||
PackageManageHelper.PKGMRR_PROGRESSCALLBACK nativeCb = null;
|
||||
if (progress != null)
|
||||
{
|
||||
holder = new ProgressCallbackHolder (progress);
|
||||
nativeCb = holder.Native;
|
||||
}
|
||||
int hr = PackageManageHelper.RegisterAppxPackageByUri (manifestPath, depArray, (uint)options, nativeCb, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return FromNative (hr, pErrCode, pDetail);
|
||||
}
|
||||
finally
|
||||
{
|
||||
NativeUtil.FreeStringArray (depArray, depList.Count);
|
||||
GC.KeepAlive (holder);
|
||||
}
|
||||
}
|
||||
public static DataUtils._I_HResult RegisterPackageByFullName (string pkgFullName, IEnumerable<string> depFullNames, DeploymentOptions options, PackageProgressCallback progress = null)
|
||||
{
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
var depList = depFullNames == null ? new List<string> () : depFullNames.ToList ();
|
||||
ProgressCallbackHolder holder = null;
|
||||
try
|
||||
{
|
||||
depArray = NativeUtil.AllocStringArray (depList);
|
||||
PackageManageHelper.PKGMRR_PROGRESSCALLBACK nativeCb = null;
|
||||
if (progress != null)
|
||||
{
|
||||
holder = new ProgressCallbackHolder (progress);
|
||||
nativeCb = holder.Native;
|
||||
}
|
||||
int hr = PackageManageHelper.RegisterAppxPackageByFullName (pkgFullName, depArray, (uint)options, nativeCb, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return FromNative (hr, pErrCode, pDetail);
|
||||
}
|
||||
finally
|
||||
{
|
||||
NativeUtil.FreeStringArray (depArray, depList.Count);
|
||||
GC.KeepAlive (holder);
|
||||
}
|
||||
}
|
||||
public static DataUtils._I_HResult SetPackageStatus (string packageFullName, PackageStatus status)
|
||||
{
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
int hr = PackageManageHelper.SetAppxPackageStatus (packageFullName, (uint)status, out pErrCode, out pDetail);
|
||||
return FromNative (hr, pErrCode, pDetail);
|
||||
}
|
||||
finally { }
|
||||
}
|
||||
public static DataUtils._I_HResult StagePackage (Uri fileUri, IEnumerable<Uri> depUris, DeploymentOptions options, PackageProgressCallback progress = null)
|
||||
{
|
||||
if (fileUri == null) throw new ArgumentNullException ("Required File URI");
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
var depList = depUris == null ? new List<string> () : depUris.Select (u => u.AbsoluteUri).ToList ();
|
||||
ProgressCallbackHolder holder = null;
|
||||
try
|
||||
{
|
||||
depArray = NativeUtil.AllocStringArray (depList);
|
||||
PackageManageHelper.PKGMRR_PROGRESSCALLBACK nativeCb = null;
|
||||
if (progress != null)
|
||||
{
|
||||
holder = new ProgressCallbackHolder (progress);
|
||||
nativeCb = holder.Native;
|
||||
}
|
||||
int hr = PackageManageHelper.StageAppxPackageFromURI (fileUri.AbsoluteUri, depArray, (uint)options, nativeCb, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return FromNative (hr, pErrCode, pDetail);
|
||||
}
|
||||
finally
|
||||
{
|
||||
NativeUtil.FreeStringArray (depArray, depList.Count);
|
||||
GC.KeepAlive (holder);
|
||||
}
|
||||
}
|
||||
public static DataUtils._I_HResult StagePackage (string filePath, IEnumerable<string> depUris, DeploymentOptions options, PackageProgressCallback progress = null)
|
||||
{
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
var depList = depUris == null ? new List<string> () : depUris.ToList ();
|
||||
ProgressCallbackHolder holder = null;
|
||||
try
|
||||
{
|
||||
depArray = NativeUtil.AllocStringArray (depList);
|
||||
PackageManageHelper.PKGMRR_PROGRESSCALLBACK nativeCb = null;
|
||||
if (progress != null)
|
||||
{
|
||||
holder = new ProgressCallbackHolder (progress);
|
||||
nativeCb = holder.Native;
|
||||
}
|
||||
int hr = PackageManageHelper.StageAppxPackageFromPath (filePath, depArray, (uint)options, nativeCb, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return FromNative (hr, pErrCode, pDetail);
|
||||
}
|
||||
finally
|
||||
{
|
||||
NativeUtil.FreeStringArray (depArray, depList.Count);
|
||||
GC.KeepAlive (holder);
|
||||
}
|
||||
}
|
||||
public static DataUtils._I_HResult StageUserData (string packageFullName, PackageProgressCallback progress = null)
|
||||
{
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
ProgressCallbackHolder holder = null;
|
||||
try
|
||||
{
|
||||
PackageManageHelper.PKGMRR_PROGRESSCALLBACK nativeCb = null;
|
||||
if (progress != null)
|
||||
{
|
||||
holder = new ProgressCallbackHolder (progress);
|
||||
nativeCb = holder.Native;
|
||||
}
|
||||
int hr = PackageManageHelper.StageAppxUserData (packageFullName, nativeCb, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return FromNative (hr, pErrCode, pDetail);
|
||||
}
|
||||
finally
|
||||
{
|
||||
GC.KeepAlive (holder);
|
||||
}
|
||||
}
|
||||
public static DataUtils._I_HResult UpdatePackage (Uri fileUri, IEnumerable<Uri> depUris, DeploymentOptions options, PackageProgressCallback progress = null)
|
||||
{
|
||||
if (fileUri == null) throw new ArgumentNullException ("Required File URI");
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
var depList = depUris == null ? new List<string> () : depUris.Select (u => u.AbsoluteUri).ToList ();
|
||||
ProgressCallbackHolder holder = null;
|
||||
try
|
||||
{
|
||||
depArray = NativeUtil.AllocStringArray (depList);
|
||||
PackageManageHelper.PKGMRR_PROGRESSCALLBACK nativeCb = null;
|
||||
if (progress != null)
|
||||
{
|
||||
holder = new ProgressCallbackHolder (progress);
|
||||
nativeCb = holder.Native;
|
||||
}
|
||||
int hr = PackageManageHelper.UpdateAppxPackageFromURI (fileUri.AbsoluteUri, depArray, (uint)options, nativeCb, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return FromNative (hr, pErrCode, pDetail);
|
||||
}
|
||||
finally
|
||||
{
|
||||
NativeUtil.FreeStringArray (depArray, depList.Count);
|
||||
GC.KeepAlive (holder);
|
||||
}
|
||||
}
|
||||
public static DataUtils._I_HResult UpdatePackage (string filePath, IEnumerable<string> depUris, DeploymentOptions options, PackageProgressCallback progress = null)
|
||||
{
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
var depList = depUris == null ? new List<string> () : depUris.ToList ();
|
||||
ProgressCallbackHolder holder = null;
|
||||
try
|
||||
{
|
||||
depArray = NativeUtil.AllocStringArray (depList);
|
||||
PackageManageHelper.PKGMRR_PROGRESSCALLBACK nativeCb = null;
|
||||
if (progress != null)
|
||||
{
|
||||
holder = new ProgressCallbackHolder (progress);
|
||||
nativeCb = holder.Native;
|
||||
}
|
||||
int hr = PackageManageHelper.UpdateAppxPackageFromPath (filePath, depArray, (uint)options, nativeCb, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return FromNative (hr, pErrCode, pDetail);
|
||||
}
|
||||
finally
|
||||
{
|
||||
NativeUtil.FreeStringArray (depArray, depList.Count);
|
||||
GC.KeepAlive (holder);
|
||||
}
|
||||
}
|
||||
public static Tuple<DataUtils._I_HResult, List<PMPackageInfo>> FindPackage (string packageName, string packagePublisher)
|
||||
{
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
ResultCallbackHolder callback = null;
|
||||
try
|
||||
{
|
||||
callback = new ResultCallbackHolder ();
|
||||
int hr = PackageManageHelper.FindAppxPackagesByIdentity (packageName, packagePublisher, callback.Callback, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return Tuple.Create (FromNative (hr, pErrCode, pDetail), callback.RetList);
|
||||
}
|
||||
finally
|
||||
{
|
||||
GC.KeepAlive (callback);
|
||||
}
|
||||
}
|
||||
public static Tuple<DataUtils._I_HResult, List<PMPackageInfo>> FindPackage (string packageFamilyName)
|
||||
{
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
ResultCallbackHolder callback = null;
|
||||
try
|
||||
{
|
||||
callback = new ResultCallbackHolder ();
|
||||
int hr = PackageManageHelper.FindAppxPackagesByFamilyName (packageFamilyName, callback.Callback, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return Tuple.Create (FromNative (hr, pErrCode, pDetail), callback.RetList);
|
||||
}
|
||||
finally
|
||||
{
|
||||
GC.KeepAlive (callback);
|
||||
}
|
||||
}
|
||||
public static Tuple<DataUtils._I_HResult, List<PMPackageInfo>> FindPackageByFullName (string packageFullName)
|
||||
{
|
||||
IntPtr depArray = IntPtr.Zero;
|
||||
IntPtr pErrCode = IntPtr.Zero;
|
||||
IntPtr pDetail = IntPtr.Zero;
|
||||
ResultCallbackHolder callback = null;
|
||||
try
|
||||
{
|
||||
callback = new ResultCallbackHolder ();
|
||||
int hr = PackageManageHelper.FindAppxPackage (packageFullName, callback.Callback, IntPtr.Zero, out pErrCode, out pDetail);
|
||||
return Tuple.Create (FromNative (hr, pErrCode, pDetail), callback.RetList);
|
||||
}
|
||||
finally
|
||||
{
|
||||
GC.KeepAlive (callback);
|
||||
}
|
||||
}
|
||||
public static DataUtils._I_HResult ActiveApp (string appUserId)
|
||||
{
|
||||
uint processId;
|
||||
var hr = PackageManageHelper.ActivateAppxApplication (appUserId, out processId);
|
||||
return new DataUtils._I_HResult (hr);
|
||||
}
|
||||
public static DataUtils._I_HResult ActiveApp (string appUserId, string cmdargs)
|
||||
{
|
||||
uint processId;
|
||||
var hr = PackageManageHelper.ActivateAppxApplicationWithArgs (appUserId, cmdargs, out processId);
|
||||
return new DataUtils._I_HResult (hr);
|
||||
}
|
||||
}
|
||||
}
|
||||
1192
AppxPackage/PackageReader.cs
Normal file
1192
AppxPackage/PackageReader.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,8 @@ namespace NativeWrappers
|
||||
using HRESULT = System.Int32;
|
||||
using BOOL = System.Int32;
|
||||
using UINT64 = System.UInt64;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public static class PackageManageHelper
|
||||
{
|
||||
@@ -141,6 +143,8 @@ namespace NativeWrappers
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
|
||||
public static extern void PackageManagerFreeString (IntPtr lpString);
|
||||
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode, ExactSpelling = true)]
|
||||
public static extern HRESULT ActivateAppxApplicationWithArgs ([MarshalAs (UnmanagedType.LPWStr)] string lpAppUserId, [MarshalAs (UnmanagedType.LPWStr)] string lpArguments, out DWORD pdwProcessId);
|
||||
|
||||
// ========== 托管辅助 ==========
|
||||
public static string PtrToStringAndFree (IntPtr nativePtr)
|
||||
@@ -186,4 +190,41 @@ namespace NativeWrappers
|
||||
return result;
|
||||
}
|
||||
}
|
||||
internal static class NativeUtil
|
||||
{
|
||||
public static string ToAbsoluteUriString (Uri uri)
|
||||
{
|
||||
if (uri == null) return null;
|
||||
return uri.AbsoluteUri;
|
||||
}
|
||||
|
||||
public static IntPtr AllocStringArray (IEnumerable<string> values)
|
||||
{
|
||||
if (values == null) return IntPtr.Zero;
|
||||
|
||||
var list = values.Where (s => !string.IsNullOrEmpty (s)).ToList ();
|
||||
if (list.Count == 0) return IntPtr.Zero;
|
||||
|
||||
IntPtr mem = Marshal.AllocHGlobal (IntPtr.Size * list.Count);
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
IntPtr pStr = Marshal.StringToHGlobalUni (list [i]);
|
||||
Marshal.WriteIntPtr (mem, i * IntPtr.Size, pStr);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
public static void FreeStringArray (IntPtr array, int count)
|
||||
{
|
||||
if (array == IntPtr.Zero) return;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
IntPtr p = Marshal.ReadIntPtr (array, i * IntPtr.Size);
|
||||
if (p != IntPtr.Zero)
|
||||
Marshal.FreeHGlobal (p);
|
||||
}
|
||||
Marshal.FreeHGlobal (array);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,7 +210,8 @@ namespace NativeWrappers
|
||||
string s = Marshal.PtrToStringUni (nativePtr);
|
||||
try
|
||||
{
|
||||
crt_free (nativePtr);
|
||||
PackageReaderFreeString (nativePtr);
|
||||
nativePtr = IntPtr.Zero;
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -218,6 +219,12 @@ namespace NativeWrappers
|
||||
}
|
||||
return s;
|
||||
}
|
||||
public static string GetStringFromPkgRead (IntPtr nativePtr)
|
||||
{
|
||||
if (nativePtr == IntPtr.Zero) return null;
|
||||
string s = Marshal.PtrToStringUni (nativePtr);
|
||||
return s;
|
||||
}
|
||||
|
||||
public static string PtrToStringNoFree (IntPtr nativePtr)
|
||||
{
|
||||
@@ -297,5 +304,105 @@ namespace NativeWrappers
|
||||
{
|
||||
}
|
||||
}
|
||||
// ================= Manifest Reader =================
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr CreateManifestReader ();
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs (UnmanagedType.Bool)]
|
||||
public static extern bool LoadManifestFromFile (
|
||||
IntPtr hReader,
|
||||
string lpFilePath
|
||||
);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
|
||||
public static extern void DestroyManifestReader (IntPtr hReader);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv)]
|
||||
public static extern ushort GetManifestType (IntPtr hReader);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv)]
|
||||
[return: MarshalAs (UnmanagedType.Bool)]
|
||||
public static extern bool IsManifestValid (IntPtr hReader);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv)]
|
||||
public static extern ushort GetManifestRole (IntPtr hReader);
|
||||
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr GetManifestIdentityStringValue (
|
||||
IntPtr hReader,
|
||||
uint dwName
|
||||
);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv)]
|
||||
[return: MarshalAs (UnmanagedType.Bool)]
|
||||
public static extern bool GetManifestIdentityVersion (
|
||||
IntPtr hReader,
|
||||
out VERSION pVersion
|
||||
);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv)]
|
||||
[return: MarshalAs (UnmanagedType.Bool)]
|
||||
public static extern bool GetManifestIdentityArchitecture (
|
||||
IntPtr hReader,
|
||||
out DWORD pdwArchi
|
||||
);
|
||||
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr GetManifestPropertiesStringValue (
|
||||
IntPtr hReader,
|
||||
string lpName
|
||||
);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
|
||||
public static extern HRESULT GetManifestPropertiesBoolValue (
|
||||
IntPtr hReader,
|
||||
string lpName,
|
||||
out BOOL pRet
|
||||
);
|
||||
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs (UnmanagedType.Bool)]
|
||||
public static extern bool AddManifestApplicationItemGetName (string lpName);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs (UnmanagedType.Bool)]
|
||||
public static extern bool RemoveManifestApplicationItemGetName (string lpName);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv)]
|
||||
public static extern IntPtr GetManifestApplications (IntPtr hReader);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv)]
|
||||
public static extern void DestroyManifestApplications (IntPtr hEnumerator);
|
||||
[DllImport (DllName, CallingConvention = CallConv)]
|
||||
public static extern IntPtr GetManifestResourcesLanguages (IntPtr hReader);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv)]
|
||||
public static extern IntPtr GetManifestResourcesLanguagesToLcid (IntPtr hReader);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv)]
|
||||
public static extern IntPtr GetManifestResourcesScales (IntPtr hReader);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv)]
|
||||
public static extern DWORD GetManifestResourcesDxFeatureLevels (IntPtr hReader);
|
||||
[DllImport (DllName, CallingConvention = CallConv)]
|
||||
public static extern IntPtr GetManifestDependencesInfoList (IntPtr hReader);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv)]
|
||||
public static extern IntPtr GetManifestCapabilitiesList (IntPtr hReader);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv)]
|
||||
public static extern IntPtr GetManifestDeviceCapabilitiesList (IntPtr hReader);
|
||||
|
||||
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs (UnmanagedType.Bool)]
|
||||
public static extern bool GetManifestPrerequisite (
|
||||
IntPtr hReader,
|
||||
string lpName,
|
||||
out VERSION pVerRet
|
||||
);
|
||||
[DllImport (DllName, CallingConvention = CallConv)]
|
||||
public static extern void PackageReaderFreeString (IntPtr p);
|
||||
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr GetManifestPrerequistieSystemVersionName (IntPtr hReader, string lpName);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -32,10 +32,10 @@ namespace AppxPackage
|
||||
public static extern string PriFileGetLastError ();
|
||||
|
||||
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void FindPriStringResource (PCSPRIFILE pFilePri, ref LPCWSTRLIST hUriList);
|
||||
public static extern void FindPriStringResource (PCSPRIFILE pFilePri, IntPtr hUriList);
|
||||
|
||||
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void FindPriPathResource (PCSPRIFILE pFilePri, ref LPCWSTRLIST hPathList);
|
||||
public static extern void FindPriPathResource (PCSPRIFILE pFilePri, IntPtr hPathList);
|
||||
|
||||
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void ClearPriCacheData ();
|
||||
@@ -44,7 +44,7 @@ namespace AppxPackage
|
||||
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);
|
||||
public static extern void FindPriResource (PCSPRIFILE pFilePri, IntPtr hUriList);
|
||||
|
||||
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
[return: MarshalAs (UnmanagedType.Bool)]
|
||||
@@ -57,21 +57,151 @@ namespace AppxPackage
|
||||
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
[return: MarshalAs (UnmanagedType.Bool)]
|
||||
public static extern bool IsMsResourceUri ([MarshalAs (UnmanagedType.LPWStr)] string pResUri);
|
||||
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void PriFormatFreeString (IntPtr ptr);
|
||||
public static string PtrToString (IntPtr ptr)
|
||||
{
|
||||
if (ptr == IntPtr.Zero) return null;
|
||||
string s = Marshal.PtrToStringUni (ptr);
|
||||
Marshal.FreeHGlobal (ptr); // 如果 DLL 返回的内存要求 free
|
||||
PriFormatFreeString (ptr); // 如果 DLL 返回的内存要求 free
|
||||
return s;
|
||||
}
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
internal struct DWORDWSTRPAIR
|
||||
{
|
||||
public uint dwKey;
|
||||
public IntPtr lpValue; // LPWSTR
|
||||
}
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
internal struct DWSPAIRLIST
|
||||
{
|
||||
public uint dwLength;
|
||||
public DWORDWSTRPAIR lpArray; // 第一个元素(柔性数组起点)
|
||||
}
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
internal struct WSDSPAIR
|
||||
{
|
||||
public IntPtr lpKey; // LPWSTR
|
||||
public IntPtr lpValue; // HDWSPAIRLIST
|
||||
}
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
internal struct WSDSPAIRLIST
|
||||
{
|
||||
public uint dwLength;
|
||||
public WSDSPAIR lpArray; // 第一个元素
|
||||
}
|
||||
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr GetPriResourceAllValueList (PCSPRIFILE pFilePri, [MarshalAs (UnmanagedType.LPWStr)] string resName);
|
||||
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void DestroyPriResourceAllValueList (IntPtr list);
|
||||
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr GetPriResourcesAllValuesList (PCSPRIFILE pFilePri, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string [] lpResNames, uint dwCount);
|
||||
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void DestroyResourcesAllValuesList (IntPtr list);
|
||||
public static Dictionary<uint, string> ParseDWSPAIRLIST (IntPtr ptr)
|
||||
{
|
||||
if (ptr == IntPtr.Zero)
|
||||
return null;
|
||||
|
||||
var result = new Dictionary<uint, string> ();
|
||||
|
||||
// 读取数量
|
||||
uint count = (uint)Marshal.ReadInt32 (ptr);
|
||||
|
||||
// 跳过 dwLength
|
||||
IntPtr pFirst = IntPtr.Add (ptr, sizeof (uint));
|
||||
|
||||
int elementSize = Marshal.SizeOf (typeof (DWORDWSTRPAIR));
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
IntPtr pItem = IntPtr.Add (pFirst, i * elementSize);
|
||||
|
||||
object boxed =
|
||||
Marshal.PtrToStructure (pItem, typeof (DWORDWSTRPAIR));
|
||||
|
||||
DWORDWSTRPAIR item = (DWORDWSTRPAIR)boxed;
|
||||
|
||||
string value = null;
|
||||
|
||||
if (item.lpValue != IntPtr.Zero)
|
||||
value = Marshal.PtrToStringUni (item.lpValue);
|
||||
|
||||
result [item.dwKey] = value;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
public static Dictionary<string, Dictionary<uint, string>> ParseWSDSPAIRLIST (IntPtr ptr)
|
||||
{
|
||||
if (ptr == IntPtr.Zero)
|
||||
return null;
|
||||
|
||||
var result =
|
||||
new Dictionary<string, Dictionary<uint, string>> ();
|
||||
|
||||
uint count = (uint)Marshal.ReadInt32 (ptr);
|
||||
|
||||
IntPtr pFirst = IntPtr.Add (ptr, sizeof (uint));
|
||||
|
||||
int elementSize = Marshal.SizeOf (typeof (WSDSPAIR));
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
IntPtr pItem = IntPtr.Add (pFirst, i * elementSize);
|
||||
|
||||
object boxed =
|
||||
Marshal.PtrToStructure (pItem, typeof (WSDSPAIR));
|
||||
|
||||
WSDSPAIR item = (WSDSPAIR)boxed;
|
||||
|
||||
string key = null;
|
||||
|
||||
if (item.lpKey != IntPtr.Zero)
|
||||
key = Marshal.PtrToStringUni (item.lpKey);
|
||||
|
||||
Dictionary<uint, string> valueDict =
|
||||
ParseDWSPAIRLIST (item.lpValue);
|
||||
|
||||
result [key] = valueDict;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
public struct LPCWSTRLIST
|
||||
public static class LpcwstrListHelper
|
||||
{
|
||||
public uint dwLength; // DWORD
|
||||
[MarshalAs (UnmanagedType.ByValArray, SizeConst = 1)]
|
||||
public IntPtr [] aswArray; // LPCWSTR*,数组
|
||||
}
|
||||
public static IntPtr Create (IEnumerable<string> strings)
|
||||
{
|
||||
if (strings == null) return IntPtr.Zero;
|
||||
var list = new List<string> (strings);
|
||||
int count = list.Count;
|
||||
int size = sizeof (uint) + IntPtr.Size * count;
|
||||
IntPtr pMem = Marshal.AllocHGlobal (size);
|
||||
Marshal.WriteInt32 (pMem, count);
|
||||
IntPtr pArray = pMem + sizeof (uint);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
IntPtr pStr = Marshal.StringToHGlobalUni (list [i]);
|
||||
Marshal.WriteIntPtr (pArray, i * IntPtr.Size, pStr);
|
||||
}
|
||||
return pMem;
|
||||
}
|
||||
public static void Destroy (IntPtr pList)
|
||||
{
|
||||
if (pList == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
int count = Marshal.ReadInt32 (pList);
|
||||
IntPtr pArray = pList + sizeof (uint);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
IntPtr pStr = Marshal.ReadIntPtr (pArray, i * IntPtr.Size);
|
||||
if (pStr != IntPtr.Zero)
|
||||
Marshal.FreeHGlobal (pStr);
|
||||
}
|
||||
Marshal.FreeHGlobal (pList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,391 @@
|
||||
using System;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AppxPackage
|
||||
{
|
||||
class PriReader
|
||||
public struct PriResourceKey
|
||||
{
|
||||
public enum PriResourceType: byte
|
||||
{
|
||||
Scale = 0,
|
||||
TargetSize = 1,
|
||||
String = 2
|
||||
}
|
||||
public enum PriContrast: byte
|
||||
{
|
||||
None = 0,
|
||||
White = 1,
|
||||
Black = 2,
|
||||
High = 3,
|
||||
Low = 4
|
||||
}
|
||||
public readonly PriResourceType Type;
|
||||
public readonly PriContrast Contrast;
|
||||
public readonly ushort Value;
|
||||
public uint Raw { get; }
|
||||
public PriResourceKey (uint raw)
|
||||
{
|
||||
Raw = raw;
|
||||
Type = (PriResourceType)((raw >> 28) & 0xF);
|
||||
Contrast = (PriContrast)((raw >> 24) & 0xF);
|
||||
Value = (ushort)(raw & 0xFFFF);
|
||||
}
|
||||
public bool IsScale => Type == PriResourceType.Scale;
|
||||
public bool IsTargetSize => Type == PriResourceType.TargetSize;
|
||||
public bool IsString => Type == PriResourceType.String;
|
||||
public override string ToString ()
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case PriResourceType.Scale:
|
||||
return $"Scale={Value}, Contrast={Contrast}";
|
||||
case PriResourceType.TargetSize:
|
||||
return $"TargetSize={Value}, Contrast={Contrast}";
|
||||
case PriResourceType.String:
|
||||
return $"LCID=0x{Value:X4}";
|
||||
default:
|
||||
return $"Unknown(0x{Raw:X8})";
|
||||
}
|
||||
}
|
||||
}
|
||||
public class PriReader: IDisposable
|
||||
{
|
||||
private IntPtr m_hPriFile = IntPtr.Zero;
|
||||
public bool Valid { get { return m_hPriFile != IntPtr.Zero; } }
|
||||
public void Dispose ()
|
||||
{
|
||||
if (Valid)
|
||||
{
|
||||
PriFileHelper.DestroyPriFileInstance (m_hPriFile);
|
||||
m_hPriFile = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
~PriReader () { Dispose (); }
|
||||
public bool Create (IStream isfile)
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose ();
|
||||
if (isfile == null) return false;
|
||||
var pStream = Marshal.GetComInterfaceForObject (isfile, typeof (IStream));
|
||||
m_hPriFile = PriFileHelper.CreatePriFileInstanceFromStream (pStream);
|
||||
}
|
||||
catch (Exception) { m_hPriFile = IntPtr.Zero; }
|
||||
return Valid;
|
||||
}
|
||||
public bool Create (IntPtr pStream)
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose ();
|
||||
if (pStream == IntPtr.Zero) return false;
|
||||
m_hPriFile = PriFileHelper.CreatePriFileInstanceFromStream (pStream);
|
||||
}
|
||||
catch (Exception) { m_hPriFile = IntPtr.Zero; }
|
||||
return Valid;
|
||||
}
|
||||
public bool Create ([MarshalAs (UnmanagedType.LPWStr)] string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose ();
|
||||
if (string.IsNullOrWhiteSpace (filePath)) return false;
|
||||
m_hPriFile = PriFileHelper.CreatePriFileInstanceFromPath (filePath);
|
||||
}
|
||||
catch (Exception) { m_hPriFile = IntPtr.Zero; }
|
||||
return Valid;
|
||||
}
|
||||
public PriReader (IStream isfile) { Create (isfile); }
|
||||
public PriReader (IntPtr pStream) { Create (pStream); }
|
||||
public PriReader ([MarshalAs (UnmanagedType.LPWStr)] string fileName) { Create (fileName); }
|
||||
public PriReader () { }
|
||||
public void AddSearch (IEnumerable<string> arr)
|
||||
{
|
||||
IntPtr buf = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
if (arr == null) return;
|
||||
buf = LpcwstrListHelper.Create (arr);
|
||||
PriFileHelper.FindPriResource (m_hPriFile, buf);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (buf != IntPtr.Zero) LpcwstrListHelper.Destroy (buf);
|
||||
}
|
||||
}
|
||||
public void AddSearch (string uri) { AddSearch (new string [] { uri }); }
|
||||
public string Resource (string resName)
|
||||
{
|
||||
var task = Task.Factory.StartNew (() => {
|
||||
IntPtr ret = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
ret = PriFileHelper.GetPriResource (m_hPriFile, resName);
|
||||
if (ret == IntPtr.Zero) return string.Empty;
|
||||
return PriFileHelper.PtrToString (ret);
|
||||
}
|
||||
finally
|
||||
{
|
||||
//if (ret != IntPtr.Zero) PriFileHelper.FreePriString(ret);
|
||||
}
|
||||
});
|
||||
return task.Result;
|
||||
}
|
||||
public Dictionary<string, string> Resources (IEnumerable<string> resnames)
|
||||
{
|
||||
if (resnames == null) throw new ArgumentNullException (nameof (resnames));
|
||||
var result = new Dictionary<string, string> ();
|
||||
AddSearch (resnames);
|
||||
foreach (var name in resnames) result [name] = Resource (name);
|
||||
return result;
|
||||
}
|
||||
public static string LastError { get { return PriFileHelper.PriFileGetLastError (); } }
|
||||
public string Path (string resName) { return Resource (resName); }
|
||||
public Dictionary<string, string> Paths (IEnumerable<string> resNames) { return Resources (resNames); }
|
||||
public string String (string resName) { return Resource (resName); }
|
||||
public Dictionary<string, string> Strings (IEnumerable<string> resNames) { return Resources (resNames); }
|
||||
public Dictionary<PriResourceKey, string> ResourceAllValues (string resName)
|
||||
{
|
||||
var task = Task.Factory.StartNew (() => {
|
||||
IntPtr ptr = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
ptr = PriFileHelper.GetPriResourceAllValueList (
|
||||
m_hPriFile, resName);
|
||||
|
||||
if (ptr == IntPtr.Zero)
|
||||
return new Dictionary<PriResourceKey, string> ();
|
||||
|
||||
var raw =
|
||||
PriFileHelper.ParseDWSPAIRLIST (ptr);
|
||||
|
||||
var result =
|
||||
new Dictionary<PriResourceKey, string> ();
|
||||
|
||||
foreach (var kv in raw)
|
||||
{
|
||||
var key = new PriResourceKey (kv.Key);
|
||||
result [key] = kv.Value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ptr != IntPtr.Zero) PriFileHelper.DestroyPriResourceAllValueList (ptr);
|
||||
}
|
||||
});
|
||||
return task.Result;
|
||||
}
|
||||
public Dictionary<string, Dictionary<PriResourceKey, string>> ResourcesAllValues (IEnumerable<string> resNames)
|
||||
{
|
||||
var task = Task.Factory.StartNew (() => {
|
||||
IntPtr ptr = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
var list = resNames?.ToList ();
|
||||
|
||||
if (list == null || list.Count == 0)
|
||||
return new Dictionary<string,
|
||||
Dictionary<PriResourceKey, string>> ();
|
||||
|
||||
ptr = PriFileHelper.GetPriResourcesAllValuesList (
|
||||
m_hPriFile,
|
||||
list.ToArray (),
|
||||
(uint)list.Count);
|
||||
|
||||
if (ptr == IntPtr.Zero)
|
||||
return new Dictionary<string,
|
||||
Dictionary<PriResourceKey, string>> ();
|
||||
|
||||
var raw =
|
||||
PriFileHelper.ParseWSDSPAIRLIST (ptr);
|
||||
|
||||
var result =
|
||||
new Dictionary<string,
|
||||
Dictionary<PriResourceKey, string>> ();
|
||||
|
||||
foreach (var outer in raw)
|
||||
{
|
||||
var innerDict =
|
||||
new Dictionary<PriResourceKey, string> ();
|
||||
|
||||
foreach (var inner in outer.Value)
|
||||
{
|
||||
var key =
|
||||
new PriResourceKey (inner.Key);
|
||||
|
||||
innerDict [key] = inner.Value;
|
||||
}
|
||||
|
||||
result [outer.Key] = innerDict;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ptr != IntPtr.Zero)
|
||||
PriFileHelper.DestroyResourcesAllValuesList (ptr);
|
||||
}
|
||||
});
|
||||
|
||||
return task.Result;
|
||||
}
|
||||
}
|
||||
public class PriReaderBundle: IDisposable
|
||||
{
|
||||
private class PriInst
|
||||
{
|
||||
public byte Type; // 0b01 lang, 0b10 scale, 0b11 both
|
||||
public PriReader Reader;
|
||||
public PriInst (byte type, IStream stream)
|
||||
{
|
||||
Type = (byte)(type & 0x03);
|
||||
Reader = new PriReader (stream);
|
||||
}
|
||||
public PriInst (byte type, IntPtr stream)
|
||||
{
|
||||
Type = (byte)(type & 0x03);
|
||||
Reader = new PriReader (stream);
|
||||
}
|
||||
public bool IsValid
|
||||
{
|
||||
get { return (Type & 0x03) != 0; }
|
||||
}
|
||||
}
|
||||
private readonly List<PriInst> _priFiles = new List<PriInst> (3);
|
||||
private readonly Dictionary<byte, PriInst> _mapPri = new Dictionary<byte, PriInst> ();
|
||||
// type: 1 language, 2 scale, 3 both
|
||||
public bool Set (byte type, IStream priStream)
|
||||
{
|
||||
byte realType = (byte)(type & 0x03);
|
||||
if (realType == 0) return false;
|
||||
PriInst inst;
|
||||
if (_mapPri.TryGetValue (realType, out inst))
|
||||
{
|
||||
inst.Reader.Dispose ();
|
||||
if (priStream != null) inst.Reader.Create (priStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (priStream == null) return false;
|
||||
inst = new PriInst (realType, priStream);
|
||||
_priFiles.Add (inst);
|
||||
_mapPri [realType] = inst;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public bool Set (byte type, IntPtr priStream)
|
||||
{
|
||||
byte realType = (byte)(type & 0x03);
|
||||
if (realType == 0) return false;
|
||||
PriInst inst;
|
||||
if (_mapPri.TryGetValue (realType, out inst))
|
||||
{
|
||||
inst.Reader.Dispose ();
|
||||
if (priStream != IntPtr.Zero) inst.Reader.Create (priStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (priStream == IntPtr.Zero) return false;
|
||||
inst = new PriInst (realType, priStream);
|
||||
_priFiles.Add (inst);
|
||||
_mapPri [realType] = inst;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private PriReader Get (byte type, bool mustReturn)
|
||||
{
|
||||
type = (byte)(type & 0x03);
|
||||
PriInst inst;
|
||||
if (_mapPri.TryGetValue (type, out inst)) return inst.Reader;
|
||||
if (type != 0x03 && _mapPri.TryGetValue (0x03, out inst)) return inst.Reader;
|
||||
if (_priFiles.Count > 0 && mustReturn) return _priFiles [0].Reader;
|
||||
return null;
|
||||
}
|
||||
private static bool IsMsResourcePrefix (string s)
|
||||
{
|
||||
return PriFileHelper.IsMsResourcePrefix (s);
|
||||
}
|
||||
public void AddSearch (IEnumerable<string> arr)
|
||||
{
|
||||
if (arr == null) return;
|
||||
List<string> strRes = new List<string> ();
|
||||
List<string> pathRes = new List<string> ();
|
||||
foreach (string it in arr)
|
||||
{
|
||||
if (IsMsResourcePrefix (it)) strRes.Add (it);
|
||||
else pathRes.Add (it);
|
||||
}
|
||||
PriReader langPri = Get (1, true);
|
||||
PriReader scalePri = Get (2, true);
|
||||
if (langPri != null && strRes.Count > 0) langPri.AddSearch (strRes);
|
||||
if (scalePri != null && pathRes.Count > 0) scalePri.AddSearch (pathRes);
|
||||
}
|
||||
public void AddSearch (string resName)
|
||||
{
|
||||
if (IsMsResourcePrefix (resName))
|
||||
{
|
||||
PriReader langPri = Get (1, true);
|
||||
if (langPri != null) langPri.AddSearch (resName);
|
||||
}
|
||||
else
|
||||
{
|
||||
PriReader scalePri = Get (2, true);
|
||||
if (scalePri != null) scalePri.AddSearch (resName);
|
||||
}
|
||||
}
|
||||
public string Resource (string resName)
|
||||
{
|
||||
if (IsMsResourcePrefix (resName))
|
||||
{
|
||||
PriReader langPri = Get (1, true);
|
||||
return langPri != null ? langPri.Resource (resName) : string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
PriReader scalePri = Get (2, true);
|
||||
return scalePri != null ? scalePri.Resource (resName) : string.Empty;
|
||||
}
|
||||
}
|
||||
public Dictionary<string, string> Resources (IEnumerable<string> resNames)
|
||||
{
|
||||
if (resNames == null) throw new ArgumentNullException ("resNames");
|
||||
Dictionary<string, string> result = new Dictionary<string, string> ();
|
||||
AddSearch (resNames);
|
||||
foreach (string name in resNames) result [name] = Resource (name);
|
||||
return result;
|
||||
}
|
||||
public string Path (string resName)
|
||||
{
|
||||
return Resource (resName);
|
||||
}
|
||||
public Dictionary<string, string> Paths (IEnumerable<string> resNames)
|
||||
{
|
||||
return Resources (resNames);
|
||||
}
|
||||
public string String (string resName)
|
||||
{
|
||||
return Resource (resName);
|
||||
}
|
||||
public Dictionary<string, string> Strings (IEnumerable<string> resNames)
|
||||
{
|
||||
return Resources (resNames);
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
foreach (PriInst it in _priFiles) it.Reader.Dispose ();
|
||||
_mapPri.Clear ();
|
||||
_priFiles.Clear ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
4
AppxPackage/packages.config
Normal file
4
AppxPackage/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="13.0.4" targetFramework="net40" />
|
||||
</packages>
|
||||
@@ -60,6 +60,10 @@
|
||||
<Project>{ffd3fd52-37a8-4f43-883c-de8d996cb0e0}</Project>
|
||||
<Name>DataUtils</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ModernNotice\ModernNotice.csproj">
|
||||
<Project>{c5587b6e-19c4-4484-aa97-5c20fbb07e43}</Project>
|
||||
<Name>ModernNotice</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\PrivateInit\PrivateInit.csproj">
|
||||
<Project>{8e708d9a-6325-4aa9-b5a5-d1b5eca8eef7}</Project>
|
||||
<Name>PrivateInit</Name>
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
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;
|
||||
using AppxPackage;
|
||||
using ModernNotice;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Bridge
|
||||
{
|
||||
@@ -73,9 +74,9 @@ namespace Bridge
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class _I_InitConfig
|
||||
{
|
||||
InitConfig Create (string filepath) => new InitConfig (filepath);
|
||||
InitConfig GetConfig () => InitFileStore.Config;
|
||||
InitConfig Current => InitFileStore.Config;
|
||||
public InitConfig Create (string filepath) => new InitConfig (filepath);
|
||||
public InitConfig GetConfig () => InitFileStore.Config;
|
||||
public InitConfig Current => InitFileStore.Config;
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
@@ -147,6 +148,732 @@ namespace Bridge
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class _I_PackageManager
|
||||
{
|
||||
public enum JsAsyncResultKind
|
||||
{
|
||||
Success,
|
||||
Failed,
|
||||
None // 什么都不回调(极少数情况)
|
||||
}
|
||||
public sealed class JsAsyncResult
|
||||
{
|
||||
public JsAsyncResultKind Kind { get; private set; }
|
||||
public object Value { get; private set; }
|
||||
private JsAsyncResult (JsAsyncResultKind kind, object value)
|
||||
{
|
||||
Kind = kind;
|
||||
Value = value;
|
||||
}
|
||||
public static JsAsyncResult Success (object value = null)
|
||||
{
|
||||
return new JsAsyncResult (JsAsyncResultKind.Success, value);
|
||||
}
|
||||
public static JsAsyncResult Failed (object value = null)
|
||||
{
|
||||
return new JsAsyncResult (JsAsyncResultKind.Failed, value);
|
||||
}
|
||||
public static JsAsyncResult None ()
|
||||
{
|
||||
return new JsAsyncResult (JsAsyncResultKind.None, null);
|
||||
}
|
||||
}
|
||||
internal static class JsAsyncRunner
|
||||
{
|
||||
private static readonly int MaxConcurrency =
|
||||
Math.Min (8, Environment.ProcessorCount * 2);
|
||||
|
||||
private static readonly SemaphoreSlim _semaphore =
|
||||
new SemaphoreSlim (MaxConcurrency);
|
||||
|
||||
private static CancellationTokenSource _cts =
|
||||
new CancellationTokenSource ();
|
||||
|
||||
public static Task Run (
|
||||
Func<CancellationToken, Action<object>, JsAsyncResult> work,
|
||||
object jsSuccess,
|
||||
object jsFailed,
|
||||
object jsProgress)
|
||||
{
|
||||
var success = jsSuccess;
|
||||
var failed = jsFailed;
|
||||
var progress = jsProgress;
|
||||
var token = _cts.Token;
|
||||
|
||||
return Task.Factory.StartNew (() =>
|
||||
{
|
||||
bool entered = false;
|
||||
|
||||
try
|
||||
{
|
||||
_semaphore.Wait (token);
|
||||
entered = true;
|
||||
|
||||
token.ThrowIfCancellationRequested ();
|
||||
|
||||
Action<object> reportProgress = p =>
|
||||
{
|
||||
if (!token.IsCancellationRequested && progress != null)
|
||||
CallJS (progress, p);
|
||||
};
|
||||
|
||||
var result = work (token, reportProgress);
|
||||
|
||||
if (token.IsCancellationRequested || result == null)
|
||||
return;
|
||||
|
||||
switch (result.Kind)
|
||||
{
|
||||
case JsAsyncResultKind.Success:
|
||||
CallJS (success, result.Value);
|
||||
break;
|
||||
|
||||
case JsAsyncResultKind.Failed:
|
||||
CallJS (failed, result.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 只对“已进入执行态”的任务回调取消
|
||||
if (!entered)
|
||||
return;
|
||||
|
||||
var cancelObj = new
|
||||
{
|
||||
status = false,
|
||||
canceled = true,
|
||||
message = "Operation canceled",
|
||||
jsontext = ""
|
||||
};
|
||||
|
||||
CallJS (failed,
|
||||
Newtonsoft.Json.JsonConvert.SerializeObject (cancelObj));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errObj = new
|
||||
{
|
||||
status = false,
|
||||
message = ex.Message,
|
||||
jsontext = ""
|
||||
};
|
||||
|
||||
CallJS (failed,
|
||||
Newtonsoft.Json.JsonConvert.SerializeObject (errObj));
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (entered)
|
||||
_semaphore.Release ();
|
||||
}
|
||||
},
|
||||
token,
|
||||
TaskCreationOptions.LongRunning,
|
||||
TaskScheduler.Default);
|
||||
}
|
||||
|
||||
private static void CallJS (object jsFunc, params object [] args)
|
||||
{
|
||||
if (jsFunc == null) return;
|
||||
try
|
||||
{
|
||||
object [] invokeArgs = new object [(args?.Length ?? 0) + 1];
|
||||
invokeArgs [0] = 1;
|
||||
if (args != null)
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
invokeArgs [i + 1] = args [i];
|
||||
|
||||
jsFunc.GetType ().InvokeMember (
|
||||
"call",
|
||||
BindingFlags.InvokeMethod,
|
||||
null,
|
||||
jsFunc,
|
||||
invokeArgs);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
// 兼容旧版:只有 reportProgress 的写法
|
||||
public static Task Run (
|
||||
Func<Action<object>, JsAsyncResult> work,
|
||||
object jsSuccess,
|
||||
object jsFailed,
|
||||
object jsProgress)
|
||||
{
|
||||
return Run (
|
||||
(token, report) => {
|
||||
token.ThrowIfCancellationRequested ();
|
||||
return work (report);
|
||||
},
|
||||
jsSuccess,
|
||||
jsFailed,
|
||||
jsProgress
|
||||
);
|
||||
}
|
||||
|
||||
public static void CancelAll ()
|
||||
{
|
||||
var old = _cts;
|
||||
_cts = new CancellationTokenSource ();
|
||||
old.Cancel ();
|
||||
old.Dispose ();
|
||||
}
|
||||
}
|
||||
private string BuildJsonText (object obj)
|
||||
{
|
||||
return Newtonsoft.Json.JsonConvert.SerializeObject (
|
||||
obj,
|
||||
Newtonsoft.Json.Formatting.Indented
|
||||
);
|
||||
}
|
||||
public void AddPackage (string path, int options, object success, object failed, object progress)
|
||||
{
|
||||
JsAsyncRunner.Run (
|
||||
report => {
|
||||
var hr = PackageManager.AddPackage (
|
||||
path,
|
||||
null,
|
||||
(DeploymentOptions)options,
|
||||
e => report (e)
|
||||
);
|
||||
if (hr == null) return JsAsyncResult.Failed ("Unknown error");
|
||||
return hr.Succeeded ? JsAsyncResult.Success (hr) : JsAsyncResult.Failed (hr);
|
||||
},
|
||||
success,
|
||||
failed,
|
||||
progress
|
||||
);
|
||||
}
|
||||
public void GetPackages (object success, object failed)
|
||||
{
|
||||
JsAsyncRunner.Run (
|
||||
report => {
|
||||
var res = PackageManager.GetPackages ();
|
||||
var hr = res.Item1;
|
||||
var jsstr = "";
|
||||
{
|
||||
var ret = new
|
||||
{
|
||||
result = res.Item1,
|
||||
list = res.Item2
|
||||
};
|
||||
jsstr = BuildJsonText (ret);
|
||||
}
|
||||
if (hr == null) return JsAsyncResult.Failed (jsstr);
|
||||
return hr.Succeeded ? JsAsyncResult.Success (jsstr) : JsAsyncResult.Failed (jsstr);
|
||||
},
|
||||
success,
|
||||
failed,
|
||||
null
|
||||
);
|
||||
}
|
||||
public void RemovePackage (string packageFullName, object success, object failed, object progress)
|
||||
{
|
||||
JsAsyncRunner.Run (
|
||||
report => {
|
||||
var hr = PackageManager.RemovePackage (
|
||||
packageFullName,
|
||||
e => report (e)
|
||||
);
|
||||
if (hr == null) return JsAsyncResult.Failed ("Unknown error");
|
||||
return hr.Succeeded ? JsAsyncResult.Success (hr) : JsAsyncResult.Failed (hr);
|
||||
},
|
||||
success,
|
||||
failed,
|
||||
progress
|
||||
);
|
||||
}
|
||||
public void ClearupPackage (string packageName, string userSID, object success, object failed, object progress)
|
||||
{
|
||||
JsAsyncRunner.Run (
|
||||
report => {
|
||||
var hr = PackageManager.ClearupPackage (
|
||||
packageName,
|
||||
userSID,
|
||||
e => report (e)
|
||||
);
|
||||
if (hr == null) return JsAsyncResult.Failed ("Unknown error");
|
||||
return hr.Succeeded ? JsAsyncResult.Success (hr) : JsAsyncResult.Failed (hr);
|
||||
},
|
||||
success,
|
||||
failed,
|
||||
progress
|
||||
);
|
||||
}
|
||||
public void RegisterPackage (string path, int options, object success, object failed, object progress)
|
||||
{
|
||||
JsAsyncRunner.Run (
|
||||
report => {
|
||||
var hr = PackageManager.RegisterPackage (
|
||||
path,
|
||||
null,
|
||||
(DeploymentOptions)options,
|
||||
e => report (e)
|
||||
);
|
||||
if (hr == null) return JsAsyncResult.Failed ("Unknown error");
|
||||
return hr.Succeeded ? JsAsyncResult.Success (hr) : JsAsyncResult.Failed (hr);
|
||||
},
|
||||
success,
|
||||
failed,
|
||||
progress
|
||||
);
|
||||
}
|
||||
public void RegisterPackageByFullName (string packageFullName, int options, object success, object failed, object progress)
|
||||
{
|
||||
JsAsyncRunner.Run (
|
||||
report => {
|
||||
var hr = PackageManager.RegisterPackageByFullName (
|
||||
packageFullName,
|
||||
null,
|
||||
(DeploymentOptions)options,
|
||||
e => report (e)
|
||||
);
|
||||
if (hr == null) return JsAsyncResult.Failed ("Unknown error");
|
||||
return hr.Succeeded ? JsAsyncResult.Success (hr) : JsAsyncResult.Failed (hr);
|
||||
},
|
||||
success,
|
||||
failed,
|
||||
progress
|
||||
);
|
||||
}
|
||||
public _I_HResult SetPackageStatus (string packageFullName, int status)
|
||||
{
|
||||
return PackageManager.SetPackageStatus (packageFullName, (PackageStatus)status);
|
||||
}
|
||||
public void StagePackage (string path, int options, object success, object failed, object progress)
|
||||
{
|
||||
JsAsyncRunner.Run (
|
||||
report => {
|
||||
var hr = PackageManager.StagePackage (
|
||||
path,
|
||||
null,
|
||||
(DeploymentOptions)options,
|
||||
e => report (e)
|
||||
);
|
||||
if (hr == null) return JsAsyncResult.Failed ("Unknown error");
|
||||
return hr.Succeeded ? JsAsyncResult.Success (hr) : JsAsyncResult.Failed (hr);
|
||||
},
|
||||
success,
|
||||
failed,
|
||||
progress
|
||||
);
|
||||
}
|
||||
public void StageUserData (string packageFullName, object success, object failed, object progress)
|
||||
{
|
||||
JsAsyncRunner.Run (
|
||||
report => {
|
||||
var hr = PackageManager.StageUserData (
|
||||
packageFullName,
|
||||
e => report (e)
|
||||
);
|
||||
if (hr == null) return JsAsyncResult.Failed ("Unknown error");
|
||||
return hr.Succeeded ? JsAsyncResult.Success (hr) : JsAsyncResult.Failed (hr);
|
||||
},
|
||||
success,
|
||||
failed,
|
||||
progress
|
||||
);
|
||||
}
|
||||
public void UpdatePackage (string path, int options, object success, object failed, object progress)
|
||||
{
|
||||
JsAsyncRunner.Run (
|
||||
report => {
|
||||
var hr = PackageManager.UpdatePackage (
|
||||
path,
|
||||
null,
|
||||
(DeploymentOptions)options,
|
||||
e => report (e)
|
||||
);
|
||||
if (hr == null) return JsAsyncResult.Failed ("Unknown error");
|
||||
return hr.Succeeded ? JsAsyncResult.Success (hr) : JsAsyncResult.Failed (hr);
|
||||
},
|
||||
success,
|
||||
failed,
|
||||
progress
|
||||
);
|
||||
}
|
||||
public void FindPackageByIdentity (string packageName, string packagePublisher, object success, object failed)
|
||||
{
|
||||
JsAsyncRunner.Run (
|
||||
report => {
|
||||
var res = PackageManager.FindPackage (packageName, packagePublisher);
|
||||
var hr = res.Item1;
|
||||
var jsstr = "";
|
||||
{
|
||||
var ret = new
|
||||
{
|
||||
result = res.Item1,
|
||||
list = res.Item2
|
||||
};
|
||||
jsstr = BuildJsonText (ret);
|
||||
}
|
||||
if (hr == null) return JsAsyncResult.Failed (jsstr);
|
||||
return hr.Succeeded ? JsAsyncResult.Success (jsstr) : JsAsyncResult.Failed (jsstr);
|
||||
},
|
||||
success,
|
||||
failed,
|
||||
null
|
||||
);
|
||||
}
|
||||
public void FindPackageByFamilyName (string packageFamilyName, object success, object failed)
|
||||
{
|
||||
JsAsyncRunner.Run (
|
||||
report => {
|
||||
var res = PackageManager.FindPackage (packageFamilyName);
|
||||
var hr = res.Item1;
|
||||
var jsstr = "";
|
||||
{
|
||||
var ret = new
|
||||
{
|
||||
result = res.Item1,
|
||||
list = res.Item2
|
||||
};
|
||||
jsstr = BuildJsonText (ret);
|
||||
}
|
||||
if (hr == null) return JsAsyncResult.Failed (jsstr);
|
||||
return hr.Succeeded ? JsAsyncResult.Success (jsstr) : JsAsyncResult.Failed (jsstr);
|
||||
},
|
||||
success,
|
||||
failed,
|
||||
null
|
||||
);
|
||||
}
|
||||
public void FindPackageByFullName (string packageFullName, object success, object failed)
|
||||
{
|
||||
JsAsyncRunner.Run (
|
||||
report => {
|
||||
var res = PackageManager.FindPackageByFullName (packageFullName);
|
||||
var hr = res.Item1;
|
||||
var jsstr = "";
|
||||
{
|
||||
var ret = new
|
||||
{
|
||||
result = res.Item1,
|
||||
list = res.Item2
|
||||
};
|
||||
jsstr = BuildJsonText (ret);
|
||||
}
|
||||
if (hr == null) return JsAsyncResult.Failed (jsstr);
|
||||
return hr.Succeeded ? JsAsyncResult.Success (jsstr) : JsAsyncResult.Failed (jsstr);
|
||||
},
|
||||
success,
|
||||
failed,
|
||||
null
|
||||
);
|
||||
}
|
||||
public _I_HResult ActiveApp (string appUserId, string args) { return PackageManager.ActiveApp (appUserId, args); }
|
||||
public _I_HResult ActiveAppByIdentity (string idName, string appId, string args) { return ActiveApp ($"{idName?.Trim ()}!{appId?.Trim ()}", args); }
|
||||
public void CancelAll () { JsAsyncRunner.CancelAll (); }
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class _I_PackageReader
|
||||
{
|
||||
private static readonly int MaxConcurrency = Math.Min (8, Environment.ProcessorCount * 2);
|
||||
private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim (MaxConcurrency);
|
||||
private static CancellationTokenSource _cts = new CancellationTokenSource ();
|
||||
private static void CallJS (object jsFunc, params object [] args)
|
||||
{
|
||||
if (jsFunc == null) return;
|
||||
try
|
||||
{
|
||||
// 这里固定第一个参数为 thisArg(比如 1)
|
||||
object [] realArgs = new object [args.Length + 1];
|
||||
realArgs [0] = jsFunc; // thisArg
|
||||
Array.Copy (args, 0, realArgs, 1, args.Length);
|
||||
|
||||
jsFunc.GetType ().InvokeMember (
|
||||
"call",
|
||||
BindingFlags.InvokeMethod,
|
||||
null,
|
||||
jsFunc,
|
||||
realArgs
|
||||
);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore errors in callback invocation
|
||||
}
|
||||
}
|
||||
private static Task RunAsync (Action<CancellationToken> work, object successCallback, object failedCallback)
|
||||
{
|
||||
var token = _cts.Token;
|
||||
return Task.Factory.StartNew (() => {
|
||||
_semaphore.Wait (token);
|
||||
try
|
||||
{
|
||||
token.ThrowIfCancellationRequested ();
|
||||
work (token);
|
||||
}
|
||||
catch (OperationCanceledException oce)
|
||||
{
|
||||
var errObj = new
|
||||
{
|
||||
status = false,
|
||||
message = "Task is canceled. Message: " + oce.Message,
|
||||
jsontext = ""
|
||||
};
|
||||
string errJson = Newtonsoft.Json.JsonConvert.SerializeObject (errObj);
|
||||
if (failedCallback != null) CallJS (failedCallback, errJson);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errObj = new
|
||||
{
|
||||
status = false,
|
||||
message = ex.Message,
|
||||
jsontext = ""
|
||||
};
|
||||
string errJson = Newtonsoft.Json.JsonConvert.SerializeObject (errObj);
|
||||
if (failedCallback != null) CallJS (failedCallback, errJson);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_semaphore.Release ();
|
||||
}
|
||||
},
|
||||
token,
|
||||
TaskCreationOptions.LongRunning,
|
||||
TaskScheduler.Default);
|
||||
}
|
||||
public AppxPackage.PackageReader Package (string packagePath) { return new AppxPackage.PackageReader (packagePath); }
|
||||
public AppxPackage.ManifestReader Manifest (string manifestPath) { return new AppxPackage.ManifestReader (manifestPath); }
|
||||
public AppxPackage.ManifestReader FromInstallLocation (string installLocation) { return Manifest (Path.Combine (installLocation, "AppxManifest.xml")); }
|
||||
public Task ReadFromPackageAsync (string packagePath, bool enablePri, object successCallback, object failedCallback)
|
||||
{
|
||||
return RunAsync (token => {
|
||||
string cacheKey = BuildCacheKey (packagePath, enablePri, ReadKind.Package);
|
||||
if (TryHitCache (cacheKey, successCallback)) return;
|
||||
using (var reader = Package (packagePath))
|
||||
{
|
||||
if (enablePri)
|
||||
{
|
||||
reader.EnablePri = true;
|
||||
reader.UsePri = true;
|
||||
}
|
||||
token.ThrowIfCancellationRequested ();
|
||||
if (!reader.IsValid)
|
||||
{
|
||||
var failObj = new
|
||||
{
|
||||
status = false,
|
||||
message = "Reader invalid",
|
||||
jsontext = ""
|
||||
};
|
||||
string failJson = Newtonsoft.Json.JsonConvert.SerializeObject (failObj);
|
||||
if (failedCallback != null) CallJS (failedCallback, failJson);
|
||||
return;
|
||||
}
|
||||
var obj = new
|
||||
{
|
||||
status = true,
|
||||
message = "ok",
|
||||
jsontext = reader.BuildJsonText ()
|
||||
};
|
||||
string json = Newtonsoft.Json.JsonConvert.SerializeObject (obj);
|
||||
if (!token.IsCancellationRequested && successCallback != null) CallJS (successCallback, json);
|
||||
SaveCache (cacheKey, json);
|
||||
}
|
||||
}, successCallback, failedCallback);
|
||||
}
|
||||
public Task ReadFromManifestAsync (string manifestPath, bool enablePri, object successCallback, object failedCallback)
|
||||
{
|
||||
return RunAsync (token => {
|
||||
string cacheKey = BuildCacheKey (manifestPath, enablePri, ReadKind.Manifest);
|
||||
if (TryHitCache (cacheKey, successCallback)) return;
|
||||
using (var reader = Manifest (manifestPath))
|
||||
{
|
||||
if (enablePri)
|
||||
{
|
||||
reader.EnablePri = true;
|
||||
reader.UsePri = true;
|
||||
}
|
||||
token.ThrowIfCancellationRequested ();
|
||||
if (!reader.IsValid)
|
||||
{
|
||||
var failObj = new
|
||||
{
|
||||
status = false,
|
||||
message = "Reader invalid",
|
||||
jsontext = ""
|
||||
};
|
||||
string failJson = Newtonsoft.Json.JsonConvert.SerializeObject (failObj);
|
||||
if (failedCallback != null) CallJS (failedCallback, failJson);
|
||||
return;
|
||||
}
|
||||
var obj = new
|
||||
{
|
||||
status = true,
|
||||
message = "ok",
|
||||
jsontext = reader.BuildJsonText ()
|
||||
};
|
||||
string json = Newtonsoft.Json.JsonConvert.SerializeObject (obj);
|
||||
if (!token.IsCancellationRequested && successCallback != null) CallJS (successCallback, json);
|
||||
SaveCache (cacheKey, json);
|
||||
}
|
||||
}, successCallback, failedCallback);
|
||||
}
|
||||
public Task ReadFromInstallLocationAsync (string installLocation, bool enablePri, object successCallback, object failedCallback)
|
||||
{
|
||||
return RunAsync (token => {
|
||||
var manifestpath = Path.Combine (installLocation, "AppxManifest.xml");
|
||||
string cacheKey = BuildCacheKey (manifestpath, enablePri, ReadKind.Manifest);
|
||||
if (TryHitCache (cacheKey, successCallback)) return;
|
||||
using (var reader = FromInstallLocation (installLocation))
|
||||
{
|
||||
if (enablePri)
|
||||
{
|
||||
reader.EnablePri = true;
|
||||
reader.UsePri = true;
|
||||
}
|
||||
token.ThrowIfCancellationRequested ();
|
||||
if (!reader.IsValid)
|
||||
{
|
||||
var failObj = new
|
||||
{
|
||||
status = false,
|
||||
message = "Reader invalid",
|
||||
jsontext = ""
|
||||
};
|
||||
string failJson = Newtonsoft.Json.JsonConvert.SerializeObject (failObj);
|
||||
if (failedCallback != null) CallJS (failedCallback, failJson);
|
||||
return;
|
||||
}
|
||||
var obj = new
|
||||
{
|
||||
status = true,
|
||||
message = "ok",
|
||||
jsontext = reader.BuildJsonText ()
|
||||
};
|
||||
string json = Newtonsoft.Json.JsonConvert.SerializeObject (obj);
|
||||
if (!token.IsCancellationRequested && successCallback != null) CallJS (successCallback, json);
|
||||
SaveCache (cacheKey, json);
|
||||
}
|
||||
}, successCallback, failedCallback);
|
||||
}
|
||||
public void CancelAll ()
|
||||
{
|
||||
var old = _cts;
|
||||
_cts = new CancellationTokenSource ();
|
||||
old.Cancel ();
|
||||
old.Dispose ();
|
||||
}
|
||||
public bool AddApplicationItem (string itemName) => PackageReader.AddApplicationItem (itemName);
|
||||
public bool RemoveApplicationItem (string itemName) => PackageReader.RemoveApplicationItem (itemName);
|
||||
// Cache about
|
||||
private const int MaxCacheItems = 64; // 最大缓存数量
|
||||
private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes (30);
|
||||
internal sealed class CacheEntry
|
||||
{
|
||||
public string Json { get; private set; }
|
||||
public DateTime ExpireAt { get; private set; }
|
||||
public DateTime LastAccessUtc { get; private set; }
|
||||
public CacheEntry (string json, DateTime expireAt)
|
||||
{
|
||||
Json = json;
|
||||
ExpireAt = expireAt;
|
||||
LastAccessUtc = DateTime.UtcNow;
|
||||
}
|
||||
public bool IsExpired { get { return DateTime.UtcNow > ExpireAt; } }
|
||||
public void Touch () { LastAccessUtc = DateTime.UtcNow; }
|
||||
}
|
||||
private static readonly ConcurrentDictionary<string, CacheEntry> _cache = new ConcurrentDictionary<string, CacheEntry> ();
|
||||
private static readonly object _cacheCleanupLock = new object ();
|
||||
private static bool TryHitCache (string cacheKey, object successCallback)
|
||||
{
|
||||
CacheEntry entry;
|
||||
if (_cache.TryGetValue (cacheKey, out entry))
|
||||
{
|
||||
if (!entry.IsExpired)
|
||||
{
|
||||
entry.Touch ();
|
||||
if (successCallback != null) CallJS (successCallback, entry.Json);
|
||||
return true;
|
||||
}
|
||||
CacheEntry removed;
|
||||
_cache.TryRemove (cacheKey, out removed);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static void SaveCache (string cacheKey, string json)
|
||||
{
|
||||
var entry = new CacheEntry (
|
||||
json,
|
||||
DateTime.UtcNow.Add (CacheDuration)
|
||||
);
|
||||
_cache [cacheKey] = entry;
|
||||
EnsureCacheSize ();
|
||||
}
|
||||
private static void EnsureCacheSize ()
|
||||
{
|
||||
if (_cache.Count <= MaxCacheItems) return;
|
||||
lock (_cacheCleanupLock)
|
||||
{
|
||||
if (_cache.Count <= MaxCacheItems) return;
|
||||
foreach (var kv in _cache)
|
||||
{
|
||||
if (kv.Value.IsExpired)
|
||||
{
|
||||
CacheEntry removed;
|
||||
_cache.TryRemove (kv.Key, out removed);
|
||||
}
|
||||
}
|
||||
if (_cache.Count <= MaxCacheItems) return;
|
||||
while (_cache.Count > MaxCacheItems)
|
||||
{
|
||||
string oldestKey = null;
|
||||
DateTime oldest = DateTime.MaxValue;
|
||||
foreach (var kv in _cache)
|
||||
{
|
||||
if (kv.Value.LastAccessUtc < oldest)
|
||||
{
|
||||
oldest = kv.Value.LastAccessUtc;
|
||||
oldestKey = kv.Key;
|
||||
}
|
||||
}
|
||||
if (oldestKey == null) break;
|
||||
CacheEntry removed;
|
||||
_cache.TryRemove (oldestKey, out removed);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static string NormalizePath (string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace (path)) return string.Empty;
|
||||
path = path.Trim ();
|
||||
while (path.EndsWith ("\\") || path.EndsWith ("/")) path = path.Substring (0, path.Length - 1);
|
||||
return path.ToLowerInvariant ();
|
||||
}
|
||||
private enum ReadKind { Package, Manifest }
|
||||
private static string BuildCacheKey (string path, bool enablePri, ReadKind kind)
|
||||
{
|
||||
return NormalizePath (path) + "|" + enablePri.ToString () + "|" + kind.ToString ();
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class _I_Package
|
||||
{
|
||||
public _I_PackageReader Reader => new _I_PackageReader ();
|
||||
public _I_PackageManager Manager => new _I_PackageManager ();
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class _I_Notice
|
||||
{
|
||||
public string TemplateXml (string templateName) { return Notice.GetTemplateString (templateName); }
|
||||
public string SimpleTemplateXml (string text, string imgPath = null) { return Notice.GetSimpleTemplateString (text, imgPath); }
|
||||
public string SimpleTemplateXml2 (string title, string text = null, string imgPath = null) { return Notice.GetSimpleTemplateString2 (title, text, imgPath); }
|
||||
public _I_HResult NoticeByXml (string appId, string xmlstr) { return Notice.Create (appId, xmlstr); }
|
||||
public _I_HResult NoticeSimply (string appId, string text, string imgPath = null) { return Notice.Create (appId, text, imgPath); }
|
||||
public _I_HResult NoticeSimply2 (string appId, string title, string text = null, string imgPath = null) { return Notice.Create (appId, title, text, imgPath); }
|
||||
public _I_HResult NoticeSimplyByBase64 (string appId, string text, string imgBase64 = null) { return Notice.CreateWithImgBase64 (appId, text, imgBase64); }
|
||||
public _I_HResult NoticeSimply2ByBase64 (string appId, string title, string text = null, string imgBase64 = null) { return Notice.CreateWithImgBase64 (appId, title, text, imgBase64); }
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class _I_BridgeBase
|
||||
{
|
||||
protected readonly _I_String str = new _I_String ();
|
||||
@@ -163,6 +890,11 @@ namespace Bridge
|
||||
public _I_IEFrame IEFrame => ieframe;
|
||||
public _I_VisualElements VisualElements => new _I_VisualElements ();
|
||||
public StringResXmlDoc StringResources => ResXmlStore.StringRes;
|
||||
public _I_Package Package => new _I_Package ();
|
||||
public _I_Taskbar Taskbar { get; private set; } = null;
|
||||
public _I_System System => system;
|
||||
public _I_Notice Notice => new _I_Notice ();
|
||||
public _I_Process Process => proc;
|
||||
public string CmdArgs
|
||||
{
|
||||
get
|
||||
@@ -172,11 +904,12 @@ namespace Bridge
|
||||
);
|
||||
}
|
||||
}
|
||||
public _I_BridgeBase (Form wnd, IScriptBridge isc, IWebBrowserPageScale iwbps)
|
||||
public _I_BridgeBase (Form wnd, IScriptBridge isc, IWebBrowserPageScale iwbps, ITaskbarProgress itp)
|
||||
{
|
||||
window = new _I_Window (isc);
|
||||
system = new _I_System (wnd);
|
||||
ieframe = new _I_IEFrame (iwbps);
|
||||
Taskbar = new _I_Taskbar (itp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,12 @@
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\IEHelper\IEHelper.vcxproj">
|
||||
<Project>{e4ca78a9-9408-4f5f-add6-730fd501ff8e}</Project>
|
||||
<Name>IEHelper</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.
|
||||
|
||||
@@ -230,6 +230,7 @@ namespace DataUtils
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
public string GetString (string id) => Get (id);
|
||||
|
||||
public string this [string id]
|
||||
{
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace DataUtils
|
||||
{
|
||||
@@ -257,6 +262,28 @@ namespace DataUtils
|
||||
string b = Utilities.NormalizeFullPath (r);
|
||||
return string.Equals (a, b, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
public bool Open (string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty (path)) return false;
|
||||
try
|
||||
{
|
||||
if (File.Exists (path))
|
||||
{
|
||||
Process.Start (path);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Directory.Exists (path))
|
||||
{
|
||||
Process.Start ("explorer.exe", path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Basic entry object
|
||||
[ComVisible (true)]
|
||||
@@ -476,13 +503,183 @@ namespace DataUtils
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class _I_Explorer
|
||||
{
|
||||
[DllImport ("user32.dll")]
|
||||
private static extern IntPtr GetForegroundWindow ();
|
||||
class WindowWrapper: IWin32Window
|
||||
{
|
||||
private IntPtr _hwnd;
|
||||
public WindowWrapper (IntPtr handle) { _hwnd = handle; }
|
||||
public IntPtr Handle { get { return _hwnd; } }
|
||||
}
|
||||
private static IWin32Window GetActiveWindowOwner ()
|
||||
{
|
||||
IntPtr hWnd = GetForegroundWindow ();
|
||||
return hWnd != IntPtr.Zero ? new WindowWrapper (hWnd) : null;
|
||||
}
|
||||
private static void CallJS (object jsFunc, params object [] args)
|
||||
{
|
||||
if (jsFunc == null) return;
|
||||
try
|
||||
{
|
||||
object [] realArgs = new object [args.Length + 1];
|
||||
realArgs [0] = jsFunc; // thisArg
|
||||
Array.Copy (args, 0, realArgs, 1, args.Length);
|
||||
jsFunc.GetType ().InvokeMember (
|
||||
"call",
|
||||
System.Reflection.BindingFlags.InvokeMethod,
|
||||
null,
|
||||
jsFunc,
|
||||
realArgs
|
||||
);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
public void File (string filter, string initDir, object jsCallback)
|
||||
{
|
||||
IWin32Window owner = GetActiveWindowOwner ();
|
||||
Thread t = new Thread (() =>
|
||||
{
|
||||
string result = string.Empty;
|
||||
try
|
||||
{
|
||||
using (OpenFileDialog dlg = new OpenFileDialog ())
|
||||
{
|
||||
dlg.Filter = filter;
|
||||
dlg.InitialDirectory = string.IsNullOrEmpty (initDir)
|
||||
? Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments)
|
||||
: initDir;
|
||||
dlg.Multiselect = false;
|
||||
if (dlg.ShowDialog (owner) == DialogResult.OK)
|
||||
result = dlg.FileName;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
CallJS (jsCallback, result);
|
||||
});
|
||||
t.IsBackground = true;
|
||||
t.SetApartmentState (ApartmentState.STA);
|
||||
t.Start ();
|
||||
}
|
||||
public void Files (string filter, string initDir, object jsCallback)
|
||||
{
|
||||
IWin32Window owner = GetActiveWindowOwner ();
|
||||
Thread t = new Thread (() =>
|
||||
{
|
||||
string result = "[]";
|
||||
try
|
||||
{
|
||||
using (OpenFileDialog dlg = new OpenFileDialog ())
|
||||
{
|
||||
dlg.Filter = filter;
|
||||
dlg.InitialDirectory = string.IsNullOrEmpty (initDir)
|
||||
? Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments)
|
||||
: initDir;
|
||||
dlg.Multiselect = true;
|
||||
if (dlg.ShowDialog (owner) == DialogResult.OK)
|
||||
result = Newtonsoft.Json.JsonConvert.SerializeObject (dlg.FileNames);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
CallJS (jsCallback, result);
|
||||
});
|
||||
t.IsBackground = true;
|
||||
t.SetApartmentState (ApartmentState.STA);
|
||||
t.Start ();
|
||||
}
|
||||
public void Dir (string initDir, object jsCallback)
|
||||
{
|
||||
IWin32Window owner = GetActiveWindowOwner ();
|
||||
Thread t = new Thread (() =>
|
||||
{
|
||||
string result = string.Empty;
|
||||
try
|
||||
{
|
||||
using (FolderBrowserDialog dlg = new FolderBrowserDialog ())
|
||||
{
|
||||
dlg.SelectedPath = string.IsNullOrEmpty (initDir)
|
||||
? Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments)
|
||||
: initDir;
|
||||
if (dlg.ShowDialog (owner) == DialogResult.OK)
|
||||
result = dlg.SelectedPath;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
CallJS (jsCallback, result);
|
||||
});
|
||||
t.IsBackground = true;
|
||||
t.SetApartmentState (ApartmentState.STA);
|
||||
t.Start ();
|
||||
}
|
||||
public void Dirs (string initDir, object jsCallback)
|
||||
{
|
||||
IWin32Window owner = GetActiveWindowOwner ();
|
||||
Thread t = new Thread (() =>
|
||||
{
|
||||
string result = "[]";
|
||||
try
|
||||
{
|
||||
using (var dlg = new OpenFileDialog ())
|
||||
{
|
||||
// trick: 多选文件夹
|
||||
dlg.ValidateNames = false;
|
||||
dlg.CheckFileExists = false;
|
||||
dlg.CheckPathExists = true;
|
||||
dlg.FileName = "SelectFolder";
|
||||
dlg.InitialDirectory = string.IsNullOrEmpty (initDir)
|
||||
? Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments)
|
||||
: initDir;
|
||||
dlg.Multiselect = true;
|
||||
if (dlg.ShowDialog (owner) == DialogResult.OK)
|
||||
{
|
||||
var dirs = dlg.FileNames.Select (f => Path.GetDirectoryName (f)).Distinct ().ToArray ();
|
||||
result = Newtonsoft.Json.JsonConvert.SerializeObject (dirs);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
CallJS (jsCallback, result);
|
||||
});
|
||||
t.IsBackground = true;
|
||||
t.SetApartmentState (ApartmentState.STA);
|
||||
t.Start ();
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class _I_Storage
|
||||
{
|
||||
private static void CallJS (object jsFunc, params object [] args)
|
||||
{
|
||||
if (jsFunc == null) return;
|
||||
try
|
||||
{
|
||||
// 这里固定第一个参数为 thisArg(比如 1)
|
||||
object [] realArgs = new object [args.Length + 1];
|
||||
realArgs [0] = jsFunc; // thisArg
|
||||
Array.Copy (args, 0, realArgs, 1, args.Length);
|
||||
|
||||
jsFunc.GetType ().InvokeMember (
|
||||
"call",
|
||||
BindingFlags.InvokeMethod,
|
||||
null,
|
||||
jsFunc,
|
||||
realArgs
|
||||
);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore errors in callback invocation
|
||||
}
|
||||
}
|
||||
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); }
|
||||
public _I_Explorer Explorer => new _I_Explorer ();
|
||||
}
|
||||
// Small shell helpers that P/Invoke for folder retrieval using CSIDL or Known Folder GUIDs
|
||||
internal static class ShellHelpers
|
||||
|
||||
@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace DataUtils
|
||||
{
|
||||
internal static class VisualElementsStore
|
||||
public static class VisualElementsStore
|
||||
{
|
||||
// Publicly accessible instances for internal use
|
||||
public static readonly VisualElementManifest Vemanifest;
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DataUtils
|
||||
@@ -51,30 +48,69 @@ namespace DataUtils
|
||||
}
|
||||
public sealed class TaskbarProgress: IDisposable
|
||||
{
|
||||
private readonly ITaskbarList3 _taskbar;
|
||||
private readonly IntPtr _hwnd;
|
||||
private ITaskbarList3 _taskbar3;
|
||||
public TaskbarProgress (IntPtr hwnd)
|
||||
{
|
||||
_hwnd = hwnd;
|
||||
_taskbar = (ITaskbarList3)new TaskbarList ();
|
||||
_taskbar.HrInit ();
|
||||
object obj = new TaskbarList ();
|
||||
ITaskbarList baseTaskbar = (ITaskbarList)obj;
|
||||
baseTaskbar.HrInit ();
|
||||
_taskbar3 = obj as ITaskbarList3;
|
||||
}
|
||||
public bool IsSupported
|
||||
{
|
||||
get { return _taskbar3 != null; }
|
||||
}
|
||||
public void SetState (TBPFLAG state)
|
||||
{
|
||||
_taskbar.SetProgressState (_hwnd, state);
|
||||
if (_taskbar3 != null)
|
||||
_taskbar3.SetProgressState (_hwnd, state);
|
||||
}
|
||||
public void SetValue (ulong completed, ulong total)
|
||||
{
|
||||
_taskbar.SetProgressValue (_hwnd, completed, total);
|
||||
if (_taskbar3 != null)
|
||||
_taskbar3.SetProgressValue (_hwnd, completed, total);
|
||||
}
|
||||
public void Clear ()
|
||||
{
|
||||
_taskbar.SetProgressState (_hwnd, TBPFLAG.TBPF_NOPROGRESS);
|
||||
if (_taskbar3 != null)
|
||||
_taskbar3.SetProgressState (_hwnd, TBPFLAG.TBPF_NOPROGRESS);
|
||||
}
|
||||
public void Dispose ()
|
||||
{
|
||||
Clear ();
|
||||
Marshal.ReleaseComObject (_taskbar);
|
||||
if (_taskbar3 != null)
|
||||
{
|
||||
Marshal.ReleaseComObject (_taskbar3);
|
||||
_taskbar3 = null;
|
||||
}
|
||||
}
|
||||
~TaskbarProgress () { Dispose (); }
|
||||
public ITaskbarList3 Instance => _taskbar3;
|
||||
}
|
||||
[ComImport]
|
||||
[Guid ("56FDF342-FD6D-11d0-958A-006097C9A090")]
|
||||
[InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface ITaskbarList
|
||||
{
|
||||
void HrInit ();
|
||||
void AddTab (IntPtr hwnd);
|
||||
void DeleteTab (IntPtr hwnd);
|
||||
void ActivateTab (IntPtr hwnd);
|
||||
void SetActiveAlt (IntPtr hwnd);
|
||||
}
|
||||
public interface ITaskbarProgress
|
||||
{
|
||||
double ProgressValue { set; }
|
||||
TBPFLAG ProgressStatus { set; }
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class _I_Taskbar
|
||||
{
|
||||
private ITaskbarProgress taskbar = null;
|
||||
public double Progress { set { if (taskbar == null) return; taskbar.ProgressValue = value; } }
|
||||
public int Status { set { if (taskbar == null) return; taskbar.ProgressStatus = (TBPFLAG)value; } }
|
||||
public _I_Taskbar (ITaskbarProgress tp) { taskbar = tp; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,17 +186,6 @@ namespace DataUtils
|
||||
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 ("#"))
|
||||
{
|
||||
@@ -321,6 +310,17 @@ namespace DataUtils
|
||||
}
|
||||
}
|
||||
|
||||
// Named color
|
||||
try
|
||||
{
|
||||
Color byName = Color.FromName (s);
|
||||
if (byName.IsKnownColor || byName.IsNamedColor)
|
||||
{
|
||||
return byName;
|
||||
}
|
||||
}
|
||||
catch { /* ignore */ }
|
||||
|
||||
// fallback: try parse as known color again (case-insensitive)
|
||||
try
|
||||
{
|
||||
|
||||
@@ -181,5 +181,9 @@ namespace DataUtils
|
||||
}
|
||||
public static bool NNoEmpty (this string l) => !((l ?? "")?.NEmpty () ?? true);
|
||||
public static string NNormalize (this string l) => (l ?? "")?.Trim ()?.ToLower () ?? "";
|
||||
public interface IJsonBuild
|
||||
{
|
||||
object BuildJSON ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace DataUtils
|
||||
/// bits 48..63 = major, 32..47 = minor, 16..31 = build, 0..15 = revision.
|
||||
/// </summary>
|
||||
[ComVisible (true)]
|
||||
public class Version: IComparable<Version>, IEquatable<Version>
|
||||
public class Version: IComparable<Version>, IEquatable<Version>, Utilities.IJsonBuild
|
||||
{
|
||||
// Backing fields
|
||||
private ushort major;
|
||||
@@ -70,12 +70,13 @@ namespace DataUtils
|
||||
// cast to ulong before shifting
|
||||
return (((ulong)major) << 48) | (((ulong)minor) << 32) | (((ulong)build) << 16) | ((ulong)revision);
|
||||
}
|
||||
public void FromUInt64 (ulong value)
|
||||
public Version FromUInt64 (ulong value)
|
||||
{
|
||||
major = (ushort)((value >> 48) & 0xFFFFUL);
|
||||
minor = (ushort)((value >> 32) & 0xFFFFUL);
|
||||
build = (ushort)((value >> 16) & 0xFFFFUL);
|
||||
revision = (ushort)(value & 0xFFFFUL);
|
||||
return this;
|
||||
}
|
||||
public ulong Data { get { return ToUInt64 (); } set { FromUInt64 (value); } }
|
||||
public override string ToString ()
|
||||
@@ -242,6 +243,16 @@ namespace DataUtils
|
||||
if (v == null) return 0UL;
|
||||
return v.ToUInt64 ();
|
||||
}
|
||||
public object BuildJSON ()
|
||||
{
|
||||
return new
|
||||
{
|
||||
major = Major,
|
||||
minor = Minor,
|
||||
build = Build,
|
||||
revision = Revision
|
||||
};
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
|
||||
@@ -22,12 +22,13 @@ namespace DataUtils
|
||||
void ExecWB (
|
||||
OLECMDID cmdID,
|
||||
OLECMDEXECOPT cmdexecopt,
|
||||
ref object pvaIn,
|
||||
ref object pvaOut
|
||||
[In, Optional] object pvaIn,
|
||||
[Out, Optional] object pvaOut
|
||||
);
|
||||
}
|
||||
public static class WebBrowserHelper
|
||||
{
|
||||
static Guid CGID_MSHTML = new Guid ("DE4BA900-59CA-11CF-9592-444553540000");
|
||||
public static IWebBrowser2 GetWebBrowser2 (WebBrowser browser)
|
||||
{
|
||||
return browser.ActiveXInstance as IWebBrowser2;
|
||||
@@ -37,4 +38,20 @@ namespace DataUtils
|
||||
{
|
||||
int PageScale { get; set; }
|
||||
}
|
||||
[ComImport]
|
||||
[Guid ("B722BCCB-4E68-101B-A2BC-00AA00404770")]
|
||||
[InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IOleCommandTarget
|
||||
{
|
||||
[PreserveSig]
|
||||
int Exec (
|
||||
ref Guid pguidCmdGroup,
|
||||
uint nCmdID,
|
||||
uint nCmdexecopt,
|
||||
ref object pvaIn,
|
||||
ref object pvaOut
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Binary file not shown.
38
IEHelper/AssemblyInfo.cpp
Normal file
38
IEHelper/AssemblyInfo.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
using namespace System;
|
||||
using namespace System::Reflection;
|
||||
using namespace System::Runtime::CompilerServices;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
using namespace System::Security::Permissions;
|
||||
|
||||
//
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
//
|
||||
[assembly:AssemblyTitleAttribute(L"IEHelper")];
|
||||
[assembly:AssemblyDescriptionAttribute(L"")];
|
||||
[assembly:AssemblyConfigurationAttribute(L"")];
|
||||
[assembly:AssemblyCompanyAttribute(L"")];
|
||||
[assembly:AssemblyProductAttribute(L"IEHelper")];
|
||||
[assembly:AssemblyCopyrightAttribute(L"Copyright (c) 2026")];
|
||||
[assembly:AssemblyTrademarkAttribute(L"")];
|
||||
[assembly:AssemblyCultureAttribute(L"")];
|
||||
|
||||
//
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
// 您可以指定所有值,也可以使用“修订号”和“生成号”的默认值,
|
||||
// 方法是按如下所示使用“*”: :
|
||||
|
||||
[assembly:AssemblyVersionAttribute("1.0.*")];
|
||||
|
||||
[assembly:ComVisible(false)];
|
||||
|
||||
[assembly:CLSCompliantAttribute(true)];
|
||||
43
IEHelper/IEHelper.cpp
Normal file
43
IEHelper/IEHelper.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
// ÕâÊÇÖ÷ DLL Îļþ¡£
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "IEHelper.h"
|
||||
|
||||
using namespace System::Runtime::InteropServices;
|
||||
HRESULT GetWebBrowser2Interface (System::Windows::Forms::WebBrowser ^fwb, IWebBrowser2 **output)
|
||||
{
|
||||
if (fwb == nullptr || output == nullptr) return E_INVALIDARG;
|
||||
*output = nullptr;
|
||||
Object ^activeX = fwb->ActiveXInstance;
|
||||
if (activeX == nullptr) return E_FAIL;
|
||||
IntPtr pUnk = Marshal::GetIUnknownForObject (activeX);
|
||||
if (pUnk == IntPtr::Zero) return E_FAIL;
|
||||
HRESULT hr = ((IUnknown *)pUnk.ToPointer ())->QueryInterface (IID_IWebBrowser2, (void **)output);
|
||||
Marshal::Release (pUnk);
|
||||
return hr;
|
||||
}
|
||||
int IEHelper::WebBrowserHelper::GetPageScale (IEWebView ^webui)
|
||||
{
|
||||
CComPtr <IWebBrowser2> web2;
|
||||
HRESULT hr = GetWebBrowser2Interface (webui, &web2);
|
||||
if (FAILED (hr)) return 0;
|
||||
VARIANT v;
|
||||
VariantInit (&v);
|
||||
hr = web2->ExecWB (OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DODEFAULT, nullptr, &v);
|
||||
if (FAILED (hr) || v.vt != VT_I4) return 0;
|
||||
int val = v.lVal;
|
||||
VariantClear (&v);
|
||||
return val;
|
||||
}
|
||||
void IEHelper::WebBrowserHelper::SetPageScale (IEWebView ^webui, int value)
|
||||
{
|
||||
CComPtr <IWebBrowser2> web2;
|
||||
HRESULT hr = GetWebBrowser2Interface (webui, &web2);
|
||||
if (FAILED (hr)) return;
|
||||
VARIANT v;
|
||||
VariantInit (&v);
|
||||
v.vt = VT_I4;
|
||||
v.lVal = value;
|
||||
web2->ExecWB (OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, &v, nullptr);
|
||||
}
|
||||
14
IEHelper/IEHelper.h
Normal file
14
IEHelper/IEHelper.h
Normal file
@@ -0,0 +1,14 @@
|
||||
// IEHelper.h
|
||||
|
||||
#pragma once
|
||||
|
||||
using namespace System;
|
||||
using IEWebView = System::Windows::Forms::WebBrowser;
|
||||
namespace IEHelper {
|
||||
public ref class WebBrowserHelper
|
||||
{
|
||||
public:
|
||||
static int GetPageScale (IEWebView ^webui);
|
||||
static void SetPageScale (IEWebView ^webui, int zoom);
|
||||
};
|
||||
}
|
||||
162
IEHelper/IEHelper.vcxproj
Normal file
162
IEHelper/IEHelper.vcxproj
Normal file
@@ -0,0 +1,162 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{E4CA78A9-9408-4F5F-ADD6-730FD501FF8E}</ProjectGuid>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<Keyword>ManagedCProj</Keyword>
|
||||
<RootNamespace>IEHelper</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies />
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies />
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies />
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies />
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="IEHelper.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="Stdafx.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AssemblyInfo.cpp" />
|
||||
<ClCompile Include="IEHelper.cpp" />
|
||||
<ClCompile Include="Stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="app.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="app.ico" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
52
IEHelper/IEHelper.vcxproj.filters
Normal file
52
IEHelper/IEHelper.vcxproj.filters
Normal file
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="IEHelper.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Stdafx.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="IEHelper.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AssemblyInfo.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Stdafx.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="app.rc">
|
||||
<Filter>资源文件</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="app.ico">
|
||||
<Filter>资源文件</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
38
IEHelper/ReadMe.txt
Normal file
38
IEHelper/ReadMe.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
========================================================================
|
||||
DYNAMIC LINK LIBRARY : IEHelper Project Overview
|
||||
========================================================================
|
||||
|
||||
AppWizard has created this IEHelper DLL for you.
|
||||
|
||||
This file contains a summary of what you will find in each of the files that
|
||||
make up your IEHelper application.
|
||||
|
||||
IEHelper.vcxproj
|
||||
This is the main project file for VC++ projects generated using an Application Wizard.
|
||||
It contains information about the version of Visual C++ that generated the file, and
|
||||
information about the platforms, configurations, and project features selected with the
|
||||
Application Wizard.
|
||||
|
||||
IEHelper.vcxproj.filters
|
||||
This is the filters file for VC++ projects generated using an Application Wizard.
|
||||
It contains information about the association between the files in your project
|
||||
and the filters. This association is used in the IDE to show grouping of files with
|
||||
similar extensions under a specific node (for e.g. ".cpp" files are associated with the
|
||||
"Source Files" filter).
|
||||
|
||||
IEHelper.cpp
|
||||
This is the main DLL source file.
|
||||
|
||||
IEHelper.h
|
||||
This file contains a class declaration.
|
||||
|
||||
AssemblyInfo.cpp
|
||||
Contains custom attributes for modifying assembly metadata.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Other notes:
|
||||
|
||||
AppWizard uses "TODO:" to indicate parts of the source code you
|
||||
should add to or customize.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
5
IEHelper/Stdafx.cpp
Normal file
5
IEHelper/Stdafx.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
// stdafx.cpp : 只包括标准包含文件的源文件
|
||||
// IEHelper.pch 将作为预编译头
|
||||
// stdafx.obj 将包含预编译类型信息
|
||||
|
||||
#include "stdafx.h"
|
||||
9
IEHelper/Stdafx.h
Normal file
9
IEHelper/Stdafx.h
Normal file
@@ -0,0 +1,9 @@
|
||||
// stdafx.h : 标准系统包含文件的包含文件,
|
||||
// 或是经常使用但不常更改的
|
||||
// 特定于项目的包含文件
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <atlbase.h>
|
||||
#include <ExDisp.h>
|
||||
BIN
IEHelper/app.ico
Normal file
BIN
IEHelper/app.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
BIN
IEHelper/app.rc
Normal file
BIN
IEHelper/app.rc
Normal file
Binary file not shown.
3
IEHelper/resource.h
Normal file
3
IEHelper/resource.h
Normal file
@@ -0,0 +1,3 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by app.rc
|
||||
63
LICENSE.Newtonsoft.Json
Normal file
63
LICENSE.Newtonsoft.Json
Normal file
@@ -0,0 +1,63 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" href="/Content/Site.css" />
|
||||
<title>'MIT' reference</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main-content">
|
||||
|
||||
|
||||
|
||||
<h1>MIT License</h1>
|
||||
|
||||
<h2>SPDX identifier</h2>
|
||||
<div id="license-expression">MIT</div>
|
||||
|
||||
<h2>License text</h2>
|
||||
|
||||
<div class="optional-license-text">
|
||||
<p>MIT License</p>
|
||||
|
||||
</div>
|
||||
<div class="replaceable-license-text">
|
||||
<p>Copyright (c) <year> <copyright holders>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<p>Permission is hereby granted, free of charge, to any person obtaining a copy of <var class="replaceable-license-text"> this software and
|
||||
associated documentation files</var> (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:</p>
|
||||
|
||||
<p>The above copyright notice and this permission notice
|
||||
<var class="optional-license-text"> (including the next paragraph)</var>
|
||||
shall be included in all copies or substantial
|
||||
portions of the Software.</p>
|
||||
|
||||
<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
NO EVENT SHALL <var class="replaceable-license-text"> THE AUTHORS OR COPYRIGHT HOLDERS</var> BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>SPDX web page</h2>
|
||||
<ul>
|
||||
<li><a href="https://spdx.org/licenses/MIT.html">https://spdx.org/licenses/MIT.html</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Notice</h2>
|
||||
<p>This license content is provided by the <a href="https://spdx.dev/">SPDX project</a>. For more information about <b>licenses.nuget.org</b>, see <a href="https://aka.ms/licenses.nuget.org">our documentation</a>.
|
||||
|
||||
<p><i>Data pulled from <a href="https://github.com/spdx/license-list-data">spdx/license-list-data</a> on November 6, 2024.</i></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
90
Launch/Launch.csproj
Normal file
90
Launch/Launch.csproj
Normal file
@@ -0,0 +1,90 @@
|
||||
<?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>{F0288B24-7B84-42A5-9A92-2E16A012E4DE}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Launch</RootNamespace>
|
||||
<AssemblyName>Launch</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<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' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<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="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.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<None Include="app.manifest" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
</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>
|
||||
</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>
|
||||
68
Launch/Program.cs
Normal file
68
Launch/Program.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Launch
|
||||
{
|
||||
static class Program
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 从 args[startIndex..] 生成安全的命令行字符串
|
||||
/// </summary>
|
||||
private static string BuildCommandLine (string [] args, int startIndex)
|
||||
{
|
||||
if (args.Length <= startIndex) return null;
|
||||
var sb = new StringBuilder ();
|
||||
for (int i = startIndex; i < args.Length; i++)
|
||||
{
|
||||
if (i > startIndex) sb.Append (' ');
|
||||
sb.Append (EscapeArgument (args [i]));
|
||||
}
|
||||
return sb.ToString ();
|
||||
}
|
||||
/// <summary>
|
||||
/// 按 Win32 命令行规则转义单个参数
|
||||
/// </summary>
|
||||
private static string EscapeArgument (string arg)
|
||||
{
|
||||
if (string.IsNullOrEmpty (arg)) return "\"\"";
|
||||
bool needQuotes = false;
|
||||
foreach (char c in arg)
|
||||
{
|
||||
if (char.IsWhiteSpace (c) || c == '"')
|
||||
{
|
||||
needQuotes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!needQuotes) return arg;
|
||||
var sb = new StringBuilder ();
|
||||
sb.Append ('"');
|
||||
foreach (char c in arg)
|
||||
{
|
||||
if (c == '"') sb.Append ("\\\"");
|
||||
else sb.Append (c);
|
||||
}
|
||||
sb.Append ('"');
|
||||
return sb.ToString ();
|
||||
}
|
||||
/// <summary>
|
||||
/// 应用程序的主入口点。
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main (string [] args)
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
{
|
||||
MessageBox.Show ("Missing AppUserModelId.", "Launch Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
string appUserModelId = args [0];
|
||||
string argumentLine = BuildCommandLine (args, 1);
|
||||
AppxPackage.PackageManager.ActiveApp (appUserModelId, string.IsNullOrEmpty (argumentLine) ? null : argumentLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Launch/Properties/AssemblyInfo.cs
Normal file
36
Launch/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle ("Launch")]
|
||||
[assembly: AssemblyDescription ("")]
|
||||
[assembly: AssemblyConfiguration ("")]
|
||||
[assembly: AssemblyCompany ("")]
|
||||
[assembly: AssemblyProduct ("Launch")]
|
||||
[assembly: AssemblyCopyright ("Copyright © 2026")]
|
||||
[assembly: AssemblyTrademark ("")]
|
||||
[assembly: AssemblyCulture ("")]
|
||||
|
||||
//将 ComVisible 设置为 false 将使此程序集中的类型
|
||||
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible (false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid ("f0288b24-7b84-42a5-9a92-2e16a012e4de")]
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
|
||||
// 方法是按如下所示使用“*”: :
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion ("1.0.0.0")]
|
||||
71
Launch/Properties/Resources.Designer.cs
generated
Normal file
71
Launch/Properties/Resources.Designer.cs
generated
Normal file
@@ -0,0 +1,71 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本: 4.0.30319.42000
|
||||
//
|
||||
// 对此文件的更改可能导致不正确的行为,如果
|
||||
// 重新生成代码,则所做更改将丢失。
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Launch.Properties
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 强类型资源类,用于查找本地化字符串等。
|
||||
/// </summary>
|
||||
// 此类是由 StronglyTypedResourceBuilder
|
||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute ("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute ()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute ()]
|
||||
internal class Resources
|
||||
{
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute ("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources ()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回此类使用的缓存 ResourceManager 实例。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute (global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((resourceMan == null))
|
||||
{
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager ("Launch.Properties.Resources", typeof (Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 覆盖当前线程的 CurrentUICulture 属性
|
||||
/// 使用此强类型的资源类的资源查找。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute (global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture
|
||||
{
|
||||
get
|
||||
{
|
||||
return resourceCulture;
|
||||
}
|
||||
set
|
||||
{
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
117
Launch/Properties/Resources.resx
Normal file
117
Launch/Properties/Resources.resx
Normal file
@@ -0,0 +1,117 @@
|
||||
<?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.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: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" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</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" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</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=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
30
Launch/Properties/Settings.Designer.cs
generated
Normal file
30
Launch/Properties/Settings.Designer.cs
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Launch.Properties
|
||||
{
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute ()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute ("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||
internal sealed partial class Settings: global::System.Configuration.ApplicationSettingsBase
|
||||
{
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized (new Settings ())));
|
||||
|
||||
public static Settings Default
|
||||
{
|
||||
get
|
||||
{
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Launch/Properties/Settings.settings
Normal file
7
Launch/Properties/Settings.settings
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
75
Launch/app.manifest
Normal file
75
Launch/app.manifest
Normal 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>
|
||||
85
Manager/BridgeExt.cs
Normal file
85
Manager/BridgeExt.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using DataUtils;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Manager
|
||||
{
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class BridgeExt: Bridge._I_BridgeBase
|
||||
{
|
||||
Form currentWnd = null;
|
||||
public BridgeExt (Form wnd, IScriptBridge isc, IWebBrowserPageScale iwbps, ITaskbarProgress itp) : base (wnd, isc, iwbps, itp)
|
||||
{
|
||||
currentWnd = wnd;
|
||||
}
|
||||
private static void CallJS (object jsFunc, params object [] args)
|
||||
{
|
||||
if (jsFunc == null) return;
|
||||
try
|
||||
{
|
||||
// 这里固定第一个参数为 thisArg(比如 1)
|
||||
object [] realArgs = new object [args.Length + 1];
|
||||
realArgs [0] = jsFunc; // thisArg
|
||||
Array.Copy (args, 0, realArgs, 1, args.Length);
|
||||
|
||||
jsFunc.GetType ().InvokeMember (
|
||||
"call",
|
||||
BindingFlags.InvokeMethod,
|
||||
null,
|
||||
jsFunc,
|
||||
realArgs
|
||||
);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore errors in callback invocation
|
||||
}
|
||||
}
|
||||
public Task CreateAppShortcut (string installLocation, string appUserModelId, object successCallback, object failedCallback)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<bool> ();
|
||||
var scf = new ShortcutCreateForm ();
|
||||
scf.Owner = currentWnd;
|
||||
scf.FormClosed += (s, e) =>
|
||||
{
|
||||
bool success = scf.IsSuccess;
|
||||
tcs.TrySetResult (success);
|
||||
var data = new
|
||||
{
|
||||
succeeded = scf.IsSuccess,
|
||||
message = scf.Message
|
||||
};
|
||||
string json = JsonConvert.SerializeObject (data);
|
||||
if (currentWnd.InvokeRequired)
|
||||
{
|
||||
currentWnd.BeginInvoke (new Action (() =>
|
||||
{
|
||||
if (success)
|
||||
CallJS (successCallback, json);
|
||||
else
|
||||
CallJS (failedCallback, json);
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (success)
|
||||
CallJS (successCallback, json);
|
||||
else
|
||||
CallJS (failedCallback, json);
|
||||
}
|
||||
scf.Dispose ();
|
||||
};
|
||||
scf.Show (currentWnd);
|
||||
scf.InitCreater (installLocation, appUserModelId);
|
||||
return tcs.Task;
|
||||
}
|
||||
}
|
||||
}
|
||||
126
Manager/ImageDisplay.Designer.cs
generated
Normal file
126
Manager/ImageDisplay.Designer.cs
generated
Normal file
@@ -0,0 +1,126 @@
|
||||
namespace Manager
|
||||
{
|
||||
partial class ImageDisplay
|
||||
{
|
||||
/// <summary>
|
||||
/// 必需的设计器变量。
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有正在使用的资源。
|
||||
/// </summary>
|
||||
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose ();
|
||||
}
|
||||
base.Dispose (disposing);
|
||||
}
|
||||
|
||||
#region 组件设计器生成的代码
|
||||
|
||||
/// <summary>
|
||||
/// 设计器支持所需的方法 - 不要修改
|
||||
/// 使用代码编辑器修改此方法的内容。
|
||||
/// </summary>
|
||||
private void InitializeComponent ()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ImageDisplay));
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.sizeDisplay = new System.Windows.Forms.Label();
|
||||
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.backgroundPanel = new System.Windows.Forms.Panel();
|
||||
this.foregroundPicture = new System.Windows.Forms.PictureBox();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.flowLayoutPanel1.SuspendLayout();
|
||||
this.backgroundPanel.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.foregroundPicture)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 1;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.Controls.Add(this.sizeDisplay, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.flowLayoutPanel1, 0, 1);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 2;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(30, 60);
|
||||
this.tableLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// sizeDisplay
|
||||
//
|
||||
this.sizeDisplay.AutoSize = true;
|
||||
this.sizeDisplay.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.sizeDisplay.Location = new System.Drawing.Point(3, 0);
|
||||
this.sizeDisplay.Name = "sizeDisplay";
|
||||
this.sizeDisplay.Size = new System.Drawing.Size(24, 15);
|
||||
this.sizeDisplay.TabIndex = 0;
|
||||
this.sizeDisplay.Text = "16";
|
||||
this.sizeDisplay.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
|
||||
//
|
||||
// flowLayoutPanel1
|
||||
//
|
||||
this.flowLayoutPanel1.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("flowLayoutPanel1.BackgroundImage")));
|
||||
this.flowLayoutPanel1.Controls.Add(this.backgroundPanel);
|
||||
this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 15);
|
||||
this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
|
||||
this.flowLayoutPanel1.Size = new System.Drawing.Size(30, 45);
|
||||
this.flowLayoutPanel1.TabIndex = 1;
|
||||
//
|
||||
// backgroundPanel
|
||||
//
|
||||
this.backgroundPanel.BackColor = System.Drawing.Color.Transparent;
|
||||
this.backgroundPanel.Controls.Add(this.foregroundPicture);
|
||||
this.backgroundPanel.Location = new System.Drawing.Point(0, 0);
|
||||
this.backgroundPanel.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.backgroundPanel.Name = "backgroundPanel";
|
||||
this.backgroundPanel.Size = new System.Drawing.Size(24, 24);
|
||||
this.backgroundPanel.TabIndex = 0;
|
||||
//
|
||||
// foregroundPicture
|
||||
//
|
||||
this.foregroundPicture.BackColor = System.Drawing.Color.Transparent;
|
||||
this.foregroundPicture.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
|
||||
this.foregroundPicture.Location = new System.Drawing.Point(3, 4);
|
||||
this.foregroundPicture.Name = "foregroundPicture";
|
||||
this.foregroundPicture.Size = new System.Drawing.Size(16, 16);
|
||||
this.foregroundPicture.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.foregroundPicture.TabIndex = 0;
|
||||
this.foregroundPicture.TabStop = false;
|
||||
//
|
||||
// ImageDisplay
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.MinimumSize = new System.Drawing.Size(30, 0);
|
||||
this.Name = "ImageDisplay";
|
||||
this.Size = new System.Drawing.Size(30, 60);
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
this.flowLayoutPanel1.ResumeLayout(false);
|
||||
this.backgroundPanel.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.foregroundPicture)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.Label sizeDisplay;
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
|
||||
private System.Windows.Forms.Panel backgroundPanel;
|
||||
private System.Windows.Forms.PictureBox foregroundPicture;
|
||||
}
|
||||
}
|
||||
69
Manager/ImageDisplay.cs
Normal file
69
Manager/ImageDisplay.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Manager
|
||||
{
|
||||
public partial class ImageDisplay: UserControl
|
||||
{
|
||||
public ImageDisplay ()
|
||||
{
|
||||
InitializeComponent ();
|
||||
IconSize = 16;
|
||||
Ratio = (decimal)(8.0 / 7.0);
|
||||
}
|
||||
private Size iconSize = new Size (16, 16);
|
||||
private decimal ratio = (decimal)(8.0 / 7.0);
|
||||
private bool originImgSize = false;
|
||||
public void RefreshPictureDisplay ()
|
||||
{
|
||||
if (originImgSize)
|
||||
{
|
||||
var backSizeWidth = (foregroundPicture.Image?.Size.Width ?? 0) * ratio;
|
||||
var backSizeHeight = (foregroundPicture.Image?.Size.Width ?? 0) * ratio;
|
||||
foregroundPicture.Size = ForegroundImage.Size;
|
||||
backgroundPanel.Size = new Size ((int)backSizeWidth, (int)backSizeHeight);
|
||||
sizeDisplay.Text = backgroundPanel.Size.ToString ();
|
||||
}
|
||||
else
|
||||
{
|
||||
foregroundPicture.Size = new Size (
|
||||
(int)(iconSize.Width / ratio),
|
||||
(int)(iconSize.Height / ratio)
|
||||
);
|
||||
backgroundPanel.Size = iconSize;
|
||||
}
|
||||
foregroundPicture.Left = (int)((backgroundPanel.Width - foregroundPicture.Width) * 0.5);
|
||||
foregroundPicture.Top = (int)((backgroundPanel.Height - foregroundPicture.Height) * 0.5);
|
||||
this.Size = new Size (
|
||||
(int)(iconSize.Width * 1),
|
||||
(int)((iconSize.Height + sizeDisplay.Height) * 1)
|
||||
);
|
||||
}
|
||||
public decimal Ratio
|
||||
{
|
||||
get { return ratio; }
|
||||
set
|
||||
{
|
||||
ratio = value;
|
||||
RefreshPictureDisplay ();
|
||||
}
|
||||
}
|
||||
public int IconSize
|
||||
{
|
||||
get { return iconSize.Width; }
|
||||
set
|
||||
{
|
||||
sizeDisplay.Text = value.ToString ();
|
||||
iconSize = new Size (value, value);
|
||||
RefreshPictureDisplay ();
|
||||
}
|
||||
}
|
||||
public bool IsOriginPicSize
|
||||
{
|
||||
get { return originImgSize; }
|
||||
set { originImgSize = true; RefreshPictureDisplay (); }
|
||||
}
|
||||
public Color BackgroundColor { get { return backgroundPanel.BackColor; } set { backgroundPanel.BackColor = value; } }
|
||||
public Image ForegroundImage { get { return foregroundPicture.Image; } set { foregroundPicture.Image = value; } }
|
||||
}
|
||||
}
|
||||
129
Manager/ImageDisplay.resx
Normal file
129
Manager/ImageDisplay.resx
Normal file
@@ -0,0 +1,129 @@
|
||||
<?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>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="flowLayoutPanel1.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAS
|
||||
dAAAEnQB3mYfeAAAAGdJREFUWEftzrENgFAQw9C//1qscv2tQBMGsEiBkF+TLvLZnqvHLMIswizCLMIs
|
||||
wizCLMIswizCLOK/WfPIZYNZxMk2pG4mvS+YRTSzctlgFmEWYRZhFmEWYRZhFmEWYRZhFvHJrN0bfh7U
|
||||
g5LtRRcAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
324
Manager/ImageSetForm.Designer.cs
generated
Normal file
324
Manager/ImageSetForm.Designer.cs
generated
Normal file
@@ -0,0 +1,324 @@
|
||||
namespace Manager
|
||||
{
|
||||
partial class ImageSetForm
|
||||
{
|
||||
/// <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 ()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ImageSetForm));
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.textBox1 = new System.Windows.Forms.TextBox();
|
||||
this.radioButton1 = new System.Windows.Forms.RadioButton();
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.initImgsSizeList = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.radioButton2 = new System.Windows.Forms.RadioButton();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.textBox2 = new System.Windows.Forms.TextBox();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.button1 = new System.Windows.Forms.Button();
|
||||
this.pictureBox1 = new System.Windows.Forms.PictureBox();
|
||||
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.button2 = new System.Windows.Forms.Button();
|
||||
this.button3 = new System.Windows.Forms.Button();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.panel1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
|
||||
this.tableLayoutPanel2.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 5;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 109F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel1.Controls.Add(this.label1, 1, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.textBox1, 2, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.radioButton1, 1, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.panel1, 1, 3);
|
||||
this.tableLayoutPanel1.Controls.Add(this.radioButton2, 1, 4);
|
||||
this.tableLayoutPanel1.Controls.Add(this.label2, 1, 5);
|
||||
this.tableLayoutPanel1.Controls.Add(this.textBox2, 2, 5);
|
||||
this.tableLayoutPanel1.Controls.Add(this.label3, 1, 6);
|
||||
this.tableLayoutPanel1.Controls.Add(this.button1, 3, 5);
|
||||
this.tableLayoutPanel1.Controls.Add(this.pictureBox1, 1, 7);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 1, 9);
|
||||
this.tableLayoutPanel1.Controls.Add(this.label4, 3, 6);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 11;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 32F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 60F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 36F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 10F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(454, 439);
|
||||
this.tableLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label1.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.label1.Location = new System.Drawing.Point(23, 20);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(97, 32);
|
||||
this.label1.TabIndex = 0;
|
||||
this.label1.Text = "Current Size";
|
||||
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// textBox1
|
||||
//
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.textBox1, 2);
|
||||
this.textBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.textBox1.Location = new System.Drawing.Point(126, 24);
|
||||
this.textBox1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.textBox1.Name = "textBox1";
|
||||
this.textBox1.ReadOnly = true;
|
||||
this.textBox1.Size = new System.Drawing.Size(305, 27);
|
||||
this.textBox1.TabIndex = 1;
|
||||
//
|
||||
// radioButton1
|
||||
//
|
||||
this.radioButton1.AutoSize = true;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.radioButton1, 3);
|
||||
this.radioButton1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.radioButton1.Location = new System.Drawing.Point(23, 56);
|
||||
this.radioButton1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.radioButton1.Name = "radioButton1";
|
||||
this.radioButton1.Size = new System.Drawing.Size(408, 24);
|
||||
this.radioButton1.TabIndex = 2;
|
||||
this.radioButton1.TabStop = true;
|
||||
this.radioButton1.Text = "Use Default Resources";
|
||||
this.radioButton1.UseVisualStyleBackColor = true;
|
||||
this.radioButton1.CheckedChanged += new System.EventHandler(this.radioButton1_CheckedChanged);
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.panel1, 3);
|
||||
this.panel1.Controls.Add(this.initImgsSizeList);
|
||||
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.panel1.Location = new System.Drawing.Point(23, 88);
|
||||
this.panel1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Size = new System.Drawing.Size(408, 52);
|
||||
this.panel1.TabIndex = 3;
|
||||
//
|
||||
// initImgsSizeList
|
||||
//
|
||||
this.initImgsSizeList.AutoScroll = true;
|
||||
this.initImgsSizeList.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.initImgsSizeList.Location = new System.Drawing.Point(0, 0);
|
||||
this.initImgsSizeList.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.initImgsSizeList.Name = "initImgsSizeList";
|
||||
this.initImgsSizeList.Size = new System.Drawing.Size(408, 52);
|
||||
this.initImgsSizeList.TabIndex = 0;
|
||||
//
|
||||
// radioButton2
|
||||
//
|
||||
this.radioButton2.AutoSize = true;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.radioButton2, 3);
|
||||
this.radioButton2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.radioButton2.Location = new System.Drawing.Point(23, 148);
|
||||
this.radioButton2.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.radioButton2.Name = "radioButton2";
|
||||
this.radioButton2.Size = new System.Drawing.Size(408, 24);
|
||||
this.radioButton2.TabIndex = 4;
|
||||
this.radioButton2.TabStop = true;
|
||||
this.radioButton2.Text = "Use File";
|
||||
this.radioButton2.UseVisualStyleBackColor = true;
|
||||
this.radioButton2.CheckedChanged += new System.EventHandler(this.radioButton2_CheckedChanged);
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label2.Location = new System.Drawing.Point(23, 176);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(97, 36);
|
||||
this.label2.TabIndex = 5;
|
||||
this.label2.Text = "File Path";
|
||||
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// textBox2
|
||||
//
|
||||
this.textBox2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.textBox2.Location = new System.Drawing.Point(126, 180);
|
||||
this.textBox2.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.textBox2.Name = "textBox2";
|
||||
this.textBox2.Size = new System.Drawing.Size(196, 27);
|
||||
this.textBox2.TabIndex = 6;
|
||||
this.textBox2.TextChanged += new System.EventHandler(this.textBox2_TextChanged);
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.label3, 2);
|
||||
this.label3.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label3.Location = new System.Drawing.Point(23, 212);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(299, 20);
|
||||
this.label3.TabIndex = 7;
|
||||
this.label3.Text = "Preview";
|
||||
this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// button1
|
||||
//
|
||||
this.button1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.button1.Location = new System.Drawing.Point(325, 176);
|
||||
this.button1.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.button1.Name = "button1";
|
||||
this.button1.Size = new System.Drawing.Size(109, 36);
|
||||
this.button1.TabIndex = 8;
|
||||
this.button1.Text = "Browse...";
|
||||
this.button1.UseVisualStyleBackColor = true;
|
||||
this.button1.Click += new System.EventHandler(this.button1_Click);
|
||||
//
|
||||
// pictureBox1
|
||||
//
|
||||
this.pictureBox1.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("pictureBox1.BackgroundImage")));
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.pictureBox1, 3);
|
||||
this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.pictureBox1.Location = new System.Drawing.Point(23, 236);
|
||||
this.pictureBox1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.pictureBox1.Name = "pictureBox1";
|
||||
this.pictureBox1.Size = new System.Drawing.Size(408, 129);
|
||||
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.pictureBox1.TabIndex = 9;
|
||||
this.pictureBox1.TabStop = false;
|
||||
this.pictureBox1.LoadCompleted += new System.ComponentModel.AsyncCompletedEventHandler(this.pictureBox1_LoadCompleted);
|
||||
//
|
||||
// tableLayoutPanel2
|
||||
//
|
||||
this.tableLayoutPanel2.ColumnCount = 5;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.tableLayoutPanel2, 3);
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
|
||||
this.tableLayoutPanel2.Controls.Add(this.button2, 1, 1);
|
||||
this.tableLayoutPanel2.Controls.Add(this.button3, 3, 1);
|
||||
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(20, 379);
|
||||
this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
this.tableLayoutPanel2.RowCount = 3;
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 36F));
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel2.Size = new System.Drawing.Size(414, 40);
|
||||
this.tableLayoutPanel2.TabIndex = 10;
|
||||
//
|
||||
// button2
|
||||
//
|
||||
this.button2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.button2.Location = new System.Drawing.Point(84, 2);
|
||||
this.button2.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.button2.Name = "button2";
|
||||
this.button2.Size = new System.Drawing.Size(80, 36);
|
||||
this.button2.TabIndex = 0;
|
||||
this.button2.Text = "Set";
|
||||
this.button2.UseVisualStyleBackColor = true;
|
||||
this.button2.Click += new System.EventHandler(this.button2_Click);
|
||||
//
|
||||
// button3
|
||||
//
|
||||
this.button3.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.button3.Location = new System.Drawing.Point(248, 2);
|
||||
this.button3.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.button3.Name = "button3";
|
||||
this.button3.Size = new System.Drawing.Size(80, 36);
|
||||
this.button3.TabIndex = 1;
|
||||
this.button3.Text = "Cancel";
|
||||
this.button3.UseVisualStyleBackColor = true;
|
||||
this.button3.Click += new System.EventHandler(this.button3_Click);
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label4.Location = new System.Drawing.Point(328, 212);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(103, 20);
|
||||
this.label4.TabIndex = 11;
|
||||
this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// ImageSetForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = System.Drawing.Color.White;
|
||||
this.ClientSize = new System.Drawing.Size(454, 439);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.Name = "ImageSetForm";
|
||||
this.ShowIcon = false;
|
||||
this.Text = "Setting Current Image";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ImageSetForm_FormClosing);
|
||||
this.Load += new System.EventHandler(this.ImageSetForm_Load);
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
this.panel1.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
|
||||
this.tableLayoutPanel2.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.TextBox textBox1;
|
||||
private System.Windows.Forms.RadioButton radioButton1;
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.FlowLayoutPanel initImgsSizeList;
|
||||
private System.Windows.Forms.RadioButton radioButton2;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.TextBox textBox2;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.Button button1;
|
||||
private System.Windows.Forms.PictureBox pictureBox1;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
|
||||
private System.Windows.Forms.Button button2;
|
||||
private System.Windows.Forms.Button button3;
|
||||
private System.Windows.Forms.Label label4;
|
||||
}
|
||||
}
|
||||
178
Manager/ImageSetForm.cs
Normal file
178
Manager/ImageSetForm.cs
Normal file
@@ -0,0 +1,178 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using Bridge;
|
||||
|
||||
namespace Manager
|
||||
{
|
||||
public partial class ImageSetForm: Form
|
||||
{
|
||||
public ImageSetForm ()
|
||||
{
|
||||
InitializeComponent ();
|
||||
Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_SETIMG_TITLE");
|
||||
label1.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_SETIMG_CURRSIZE");
|
||||
radioButton1.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_SETIMG_USEDEF");
|
||||
radioButton2.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_SETIMG_USEFILE");
|
||||
label2.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_SETIMG_FILEPATH");
|
||||
button1.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_BROWSE");
|
||||
label3.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_PREVIEW");
|
||||
button2.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_SETIMG_SET");
|
||||
button3.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_CANCEL");
|
||||
}
|
||||
private Dictionary<int, Image> defimages = new Dictionary<int, Image> ();
|
||||
private void RefreshDefaultImagesSettings ()
|
||||
{
|
||||
try
|
||||
{
|
||||
initImgsSizeList.Controls.Clear ();
|
||||
foreach (var kv in defimages)
|
||||
{
|
||||
RadioButton rb = new RadioButton ();
|
||||
rb.Text = kv.Key.ToString ();
|
||||
rb.CheckedChanged += DefaultImgsRadio_CheckedChanged;
|
||||
initImgsSizeList.Controls.Add (rb);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
public Dictionary <int, Image> DefaultImages
|
||||
{
|
||||
get { return defimages; }
|
||||
set { defimages = value; RefreshDefaultImagesSettings (); }
|
||||
}
|
||||
public int CurrentSize { set { textBox1.Text = value.ToString (); } }
|
||||
private void RefreshImagesType ()
|
||||
{
|
||||
initImgsSizeList.Enabled = radioButton1.Checked;
|
||||
textBox2.Enabled = button1.Enabled = radioButton2.Checked;
|
||||
}
|
||||
private Image finalUse = null;
|
||||
private void RefreshImagesPreview ()
|
||||
{
|
||||
pictureBox1.Image = null;
|
||||
try
|
||||
{
|
||||
if (radioButton1.Checked)
|
||||
{
|
||||
foreach (RadioButton ctrl in initImgsSizeList.Controls)
|
||||
{
|
||||
if (ctrl.Checked)
|
||||
{
|
||||
int value = int.Parse (ctrl.Text);
|
||||
pictureBox1.Image = defimages [value];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
pictureBox1.Image = Image.FromFile (textBox2.Text);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
catch { pictureBox1.Image = null; }
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
label4.Text = $"{pictureBox1.Image.Width} x {pictureBox1.Image.Height}";
|
||||
}
|
||||
catch { label4.Text = ""; }
|
||||
}
|
||||
}
|
||||
private void DefaultImgsRadio_CheckedChanged (object sender, EventArgs e)
|
||||
{
|
||||
RefreshImagesPreview ();
|
||||
}
|
||||
private void ImageSetForm_Load (object sender, EventArgs e)
|
||||
{
|
||||
RefreshImagesType ();
|
||||
//RefreshImagesPreview ();
|
||||
}
|
||||
private void textBox2_TextChanged (object sender, EventArgs e)
|
||||
{
|
||||
RefreshImagesPreview ();
|
||||
}
|
||||
private void radioButton1_CheckedChanged (object sender, EventArgs e)
|
||||
{
|
||||
RefreshImagesType ();
|
||||
RefreshImagesPreview ();
|
||||
}
|
||||
private void radioButton2_CheckedChanged (object sender, EventArgs e)
|
||||
{
|
||||
RefreshImagesType ();
|
||||
RefreshImagesPreview ();
|
||||
}
|
||||
public Image FinalImage
|
||||
{
|
||||
set
|
||||
{
|
||||
pictureBox1.Image = value;
|
||||
try
|
||||
{
|
||||
label4.Text = $"{pictureBox1.Image.Width} x {pictureBox1.Image.Height}";
|
||||
}
|
||||
catch { label4.Text = ""; }
|
||||
}
|
||||
get { return finalUse; }
|
||||
}
|
||||
private void button3_Click (object sender, EventArgs e)
|
||||
{
|
||||
this.Close ();
|
||||
}
|
||||
private void button2_Click (object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (radioButton1.Checked)
|
||||
{
|
||||
foreach (RadioButton ctrl in initImgsSizeList.Controls)
|
||||
{
|
||||
if (ctrl.Checked)
|
||||
{
|
||||
int value = int.Parse (ctrl.Text);
|
||||
finalUse = defimages [value];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
finalUse = Image.FromFile (textBox2.Text);
|
||||
}
|
||||
if (finalUse == null) throw new Exception ("Error: none valid image.");
|
||||
this.Close ();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show (ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
private void ImageSetForm_FormClosing (object sender, FormClosingEventArgs e)
|
||||
{
|
||||
}
|
||||
private void pictureBox1_LoadCompleted (object sender, System.ComponentModel.AsyncCompletedEventArgs e)
|
||||
{
|
||||
label4.Text = $"{pictureBox1.Image.Width} x {pictureBox1.Image.Height}";
|
||||
}
|
||||
private void button1_Click (object sender, EventArgs e)
|
||||
{
|
||||
using (OpenFileDialog ofd = new OpenFileDialog ())
|
||||
{
|
||||
ofd.Title = "Please select the image file: ";
|
||||
ofd.Filter = "Image Files (*.png;*.bmp;*.jpg;*.jpeg)|*.png;*.bmp;*.jpg;*.jpeg";
|
||||
ofd.Multiselect = false;
|
||||
ofd.CheckFileExists = true;
|
||||
ofd.CheckPathExists = true;
|
||||
if (ofd.ShowDialog (this) == DialogResult.OK)
|
||||
{
|
||||
textBox2.Text = ofd.FileName;
|
||||
radioButton2.Checked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
129
Manager/ImageSetForm.resx
Normal file
129
Manager/ImageSetForm.resx
Normal file
@@ -0,0 +1,129 @@
|
||||
<?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>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="pictureBox1.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAS
|
||||
dAAAEnQB3mYfeAAAAGlJREFUWEftzrENACEQA0H6r4SG6OAKAfHXwOodEOwkzqwdlTNzzCLMIswizCLM
|
||||
IswizCLMIswizCLMIjJZ6+rLhFezehO+uKNjfzCLSGb1ZYJZhFmEWYRZhFmEWYRZhFmEWYRZxJNZVRvc
|
||||
pafKc4vMkgAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
89
Manager/LoadingStatusForm.Designer.cs
generated
Normal file
89
Manager/LoadingStatusForm.Designer.cs
generated
Normal file
@@ -0,0 +1,89 @@
|
||||
namespace Manager
|
||||
{
|
||||
partial class LoadingStatusForm
|
||||
{
|
||||
/// <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.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 3;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel1.Controls.Add(this.label1, 1, 1);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 3;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(241, 123);
|
||||
this.tableLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label1.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.label1.Location = new System.Drawing.Point(55, 48);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(131, 27);
|
||||
this.label1.TabIndex = 1;
|
||||
this.label1.Text = "Please wait...";
|
||||
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// LoadingStatusForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(241, 123);
|
||||
this.ControlBox = false;
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "LoadingStatusForm";
|
||||
this.ShowIcon = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Please wait...";
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.Label label1;
|
||||
}
|
||||
}
|
||||
19
Manager/LoadingStatusForm.cs
Normal file
19
Manager/LoadingStatusForm.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Windows.Forms;
|
||||
using Bridge;
|
||||
|
||||
namespace Manager
|
||||
{
|
||||
public partial class LoadingStatusForm: Form
|
||||
{
|
||||
public LoadingStatusForm ()
|
||||
{
|
||||
InitializeComponent ();
|
||||
label1.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_LOADING");
|
||||
}
|
||||
public string TipText
|
||||
{
|
||||
get { return label1.Text; }
|
||||
set { label1.Text = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
120
Manager/LoadingStatusForm.resx
Normal file
120
Manager/LoadingStatusForm.resx
Normal 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>
|
||||
181
Manager/Manager.csproj
Normal file
181
Manager/Manager.csproj
Normal file
@@ -0,0 +1,181 @@
|
||||
<?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>{DC074727-72E4-43C5-BAAF-E0D548104797}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Manager</RootNamespace>
|
||||
<AssemblyName>Manager</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<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' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<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>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\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>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>Project1.ico</ApplicationIcon>
|
||||
</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.DirectoryServices" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BridgeExt.cs" />
|
||||
<Compile Include="ImageDisplay.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ImageDisplay.Designer.cs">
|
||||
<DependentUpon>ImageDisplay.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ImageSetForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ImageSetForm.Designer.cs">
|
||||
<DependentUpon>ImageSetForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="LoadingStatusForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="LoadingStatusForm.Designer.cs">
|
||||
<DependentUpon>LoadingStatusForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ManagerShell.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ManagerShell.Designer.cs">
|
||||
<DependentUpon>ManagerShell.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Polyfill.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ShortcutCreateForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ShortcutCreateForm.Designer.cs">
|
||||
<DependentUpon>ShortcutCreateForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ShortcutHelper.cs" />
|
||||
<EmbeddedResource Include="ImageDisplay.resx">
|
||||
<DependentUpon>ImageDisplay.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="ImageSetForm.resx">
|
||||
<DependentUpon>ImageSetForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="LoadingStatusForm.resx">
|
||||
<DependentUpon>LoadingStatusForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="ManagerShell.resx">
|
||||
<DependentUpon>ManagerShell.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="ShortcutCreateForm.resx">
|
||||
<DependentUpon>ShortcutCreateForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<None Include="app.manifest" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</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>
|
||||
<ProjectReference Include="..\WAShell\WAShell.csproj">
|
||||
<Project>{4ec16578-efbf-41e6-8d7f-976e3646dd1d}</Project>
|
||||
<Name>WAShell</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Project1.ico" />
|
||||
</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>
|
||||
53
Manager/ManagerShell.Designer.cs
generated
Normal file
53
Manager/ManagerShell.Designer.cs
generated
Normal file
@@ -0,0 +1,53 @@
|
||||
namespace Manager
|
||||
{
|
||||
partial class ManagerShell
|
||||
{
|
||||
/// <summary>
|
||||
/// 必需的设计器变量。
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有正在使用的资源。
|
||||
/// </summary>
|
||||
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose ();
|
||||
}
|
||||
base.Dispose (disposing);
|
||||
}
|
||||
|
||||
#region Windows 窗体设计器生成的代码
|
||||
|
||||
/// <summary>
|
||||
/// 设计器支持所需的方法 - 不要修改
|
||||
/// 使用代码编辑器修改此方法的内容。
|
||||
/// </summary>
|
||||
private void InitializeComponent ()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ManagerShell));
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// ManagerShell
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(661, 416);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Location = new System.Drawing.Point(0, 0);
|
||||
this.Name = "ManagerShell";
|
||||
this.PageScale = 125;
|
||||
this.Text = "Form1";
|
||||
this.Load += new System.EventHandler(this.ManagerShell_Load);
|
||||
this.Resize += new System.EventHandler(this.ManagerShell_Resize);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
88
Manager/ManagerShell.cs
Normal file
88
Manager/ManagerShell.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using System.IO;
|
||||
namespace Manager
|
||||
{
|
||||
public partial class ManagerShell: WAShell.WebAppForm
|
||||
{
|
||||
public ManagerShell ()
|
||||
{
|
||||
InitializeComponent ();
|
||||
this.PublicObjectForScripting = new BridgeExt (this, this, this, this);
|
||||
try
|
||||
{
|
||||
var relativePath = DataUtils.VisualElementsStore.Vemanifest.SplashScreenImage (Program.g_appId);
|
||||
var img = Image.FromFile (relativePath);
|
||||
SplashScreen.SplashImage = img;
|
||||
} catch (Exception e) {
|
||||
var ex = e;
|
||||
}
|
||||
try
|
||||
{
|
||||
SplashScreen.SplashBackgroundColor = DataUtils.UITheme.StringToColor (DataUtils.VisualElementsStore.Vemanifest.SplashScreenBackgroundColor (Program.g_appId));
|
||||
}
|
||||
catch { }
|
||||
InitSize ();
|
||||
Text = Bridge.ResXmlStore.StringRes.Get ("MANAGER_APPTITLE");
|
||||
}
|
||||
private void InitSize ()
|
||||
{
|
||||
uint ww = 0, wh = 0;
|
||||
var ini = Bridge.InitFileStore.Config;
|
||||
var setsect = ini ["Settings"];
|
||||
var savepos = setsect.GetKey ("PackageManager:SavePosAndSizeBeforeCancel");
|
||||
var lastw = setsect.GetKey ("PackageManager:LastWidth");
|
||||
var lasth = setsect.GetKey ("PackageManager:LastHeight");
|
||||
var defw = setsect.GetKey ("PackageManager:DefaultWidth");
|
||||
var defh = setsect.GetKey ("PackageManager:DefaultHeight");
|
||||
var minw = setsect.GetKey ("PackageManager:MinimumWidth");
|
||||
var minh = setsect.GetKey ("PackageManager:MinimumHeight");
|
||||
var lasts = setsect.GetKey ("PackageManager:LastWndState");
|
||||
if (savepos.ReadBool ())
|
||||
{
|
||||
ww = lastw.ReadUInt (defw.ReadUInt (Properties.Resources.IDS_DEFAULTWIDTH.ParseTo <uint> ()));
|
||||
wh = lasth.ReadUInt (defh.ReadUInt (Properties.Resources.IDS_DEFAULTHEIGHT.ParseTo <uint> ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ww = defw.ReadUInt (Properties.Resources.IDS_DEFAULTWIDTH.ParseTo<uint> ());
|
||||
wh = defh.ReadUInt (Properties.Resources.IDS_DEFAULTHEIGHT.ParseTo<uint> ());
|
||||
}
|
||||
ClientSize = new Size ((int)(ww * DataUtils.UITheme.DPIDouble), (int)(wh * DataUtils.UITheme.DPIDouble));
|
||||
int hborder = Size.Width - ClientSize.Width,
|
||||
vborder = Size.Height - ClientSize.Height;
|
||||
MinimumSize = new Size (
|
||||
(int)(minw.ReadUInt (Properties.Resources.IDS_MINWIDTH.ParseTo <uint> ()) * DataUtils.UITheme.DPIDouble) + hborder,
|
||||
(int)(minh.ReadUInt (Properties.Resources.IDS_MINHEIGHT.ParseTo <uint> ()) * DataUtils.UITheme.DPIDouble) + vborder
|
||||
);
|
||||
WindowState = (FormWindowState)lasts.ReadInt ((int)FormWindowState.Normal);
|
||||
}
|
||||
private void ManagerShell_Load (object sender, EventArgs e)
|
||||
{
|
||||
var root = Path.GetDirectoryName (DataUtils.Utilities.GetCurrentProgramPath ());
|
||||
WebUI.Navigate (Path.Combine (root, "html\\manager.html"));
|
||||
}
|
||||
private void ManagerShell_Resize (object sender, EventArgs e)
|
||||
{
|
||||
var ini = Bridge.InitFileStore.Config;
|
||||
var setsect = ini ["Settings"];
|
||||
var savepos = setsect.GetKey ("PackageManager:SavePosAndSizeBeforeCancel");
|
||||
var lastw = setsect.GetKey ("PackageManager:LastWidth");
|
||||
var lasth = setsect.GetKey ("PackageManager:LastHeight");
|
||||
var lasts = setsect.GetKey ("PackageManager:LastWndState");
|
||||
switch (WindowState)
|
||||
{
|
||||
case FormWindowState.Normal:
|
||||
case FormWindowState.Maximized:
|
||||
lasts.Write ((int)WindowState);
|
||||
break;
|
||||
}
|
||||
if (WindowState == FormWindowState.Normal && savepos.ReadBool ())
|
||||
{
|
||||
lastw.Write ((int)(ClientSize.Width / DataUtils.UITheme.DPIDouble));
|
||||
lasth.Write ((int)(ClientSize.Height / DataUtils.UITheme.DPIDouble));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
4704
Manager/ManagerShell.resx
Normal file
4704
Manager/ManagerShell.resx
Normal file
File diff suppressed because it is too large
Load Diff
40
Manager/Polyfill.cs
Normal file
40
Manager/Polyfill.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Manager
|
||||
{
|
||||
public static class Polyfill
|
||||
{
|
||||
public static T ParseTo <T> (this string src, T dflt = default (T))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace (src)) return dflt;
|
||||
try
|
||||
{
|
||||
Type targetType = typeof (T);
|
||||
Type underlying = Nullable.GetUnderlyingType (targetType);
|
||||
if (underlying != null)
|
||||
{
|
||||
object v = Convert.ChangeType (src, underlying, CultureInfo.InvariantCulture);
|
||||
return (T)v;
|
||||
}
|
||||
if (targetType.IsEnum)
|
||||
{
|
||||
object enumValue = Enum.Parse (targetType, src, true);
|
||||
return (T)enumValue;
|
||||
}
|
||||
TypeConverter converter = TypeDescriptor.GetConverter (targetType);
|
||||
if (converter != null && converter.CanConvertFrom (typeof (string)))
|
||||
{
|
||||
object v = converter.ConvertFrom (null, CultureInfo.InvariantCulture, src);
|
||||
return (T)v;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
return dflt;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
Manager/Program.cs
Normal file
30
Manager/Program.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Manager
|
||||
{
|
||||
static class Program
|
||||
{
|
||||
static public readonly string g_appUserId = "WindowsModern.PracticalToolsProject!Manager";
|
||||
static public readonly string g_appId = "Manager";
|
||||
/// <summary>
|
||||
/// 应用程序的主入口点。
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main ()
|
||||
{
|
||||
Directory.SetCurrentDirectory (AppDomain.CurrentDomain.BaseDirectory);
|
||||
//System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo ("en-US");
|
||||
//System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo ("en-US");
|
||||
AppxPackage.PackageReader.AddApplicationItem ("SmallLogo");
|
||||
AppxPackage.PackageReader.AddApplicationItem ("Square30x30Logo");
|
||||
AppxPackage.PackageReader.AddApplicationItem ("Logo");
|
||||
AppxPackage.PackageReader.AddApplicationItem ("Square44x44Logo");
|
||||
DataUtils.BrowserEmulation.SetWebBrowserEmulation ();
|
||||
Application.EnableVisualStyles ();
|
||||
Application.SetCompatibleTextRenderingDefault (false);
|
||||
Application.Run (new ManagerShell ());
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
Manager/Project1.ico
Normal file
BIN
Manager/Project1.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 268 KiB |
36
Manager/Properties/AssemblyInfo.cs
Normal file
36
Manager/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle ("Manager")]
|
||||
[assembly: AssemblyDescription ("")]
|
||||
[assembly: AssemblyConfiguration ("")]
|
||||
[assembly: AssemblyCompany ("")]
|
||||
[assembly: AssemblyProduct ("Manager")]
|
||||
[assembly: AssemblyCopyright ("Copyright © 2026")]
|
||||
[assembly: AssemblyTrademark ("")]
|
||||
[assembly: AssemblyCulture ("")]
|
||||
|
||||
//将 ComVisible 设置为 false 将使此程序集中的类型
|
||||
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible (false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid ("dc074727-72e4-43c5-baaf-e0d548104797")]
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
|
||||
// 方法是按如下所示使用“*”: :
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion ("1.0.0.0")]
|
||||
99
Manager/Properties/Resources.Designer.cs
generated
Normal file
99
Manager/Properties/Resources.Designer.cs
generated
Normal file
@@ -0,0 +1,99 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本:4.0.30319.42000
|
||||
//
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||
// 重新生成代码,这些更改将会丢失。
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Manager.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 一个强类型的资源类,用于查找本地化的字符串等。
|
||||
/// </summary>
|
||||
// 此类是由 StronglyTypedResourceBuilder
|
||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回此类使用的缓存的 ResourceManager 实例。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Manager.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用此强类型资源类,为所有资源查找
|
||||
/// 重写当前线程的 CurrentUICulture 属性。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 600 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string IDS_DEFAULTHEIGHT {
|
||||
get {
|
||||
return ResourceManager.GetString("IDS_DEFAULTHEIGHT", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 800 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string IDS_DEFAULTWIDTH {
|
||||
get {
|
||||
return ResourceManager.GetString("IDS_DEFAULTWIDTH", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 412 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string IDS_MINHEIGHT {
|
||||
get {
|
||||
return ResourceManager.GetString("IDS_MINHEIGHT", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 504 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string IDS_MINWIDTH {
|
||||
get {
|
||||
return ResourceManager.GetString("IDS_MINWIDTH", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
136
Manager/Properties/Resources.resx
Normal file
136
Manager/Properties/Resources.resx
Normal file
@@ -0,0 +1,136 @@
|
||||
<?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>
|
||||
<data name="IDS_DEFAULTHEIGHT" xml:space="preserve">
|
||||
<value>600</value>
|
||||
<comment>默认窗口高度</comment>
|
||||
</data>
|
||||
<data name="IDS_DEFAULTWIDTH" xml:space="preserve">
|
||||
<value>800</value>
|
||||
<comment>默认窗口宽度</comment>
|
||||
</data>
|
||||
<data name="IDS_MINHEIGHT" xml:space="preserve">
|
||||
<value>412</value>
|
||||
<comment>默认最小窗口高度</comment>
|
||||
</data>
|
||||
<data name="IDS_MINWIDTH" xml:space="preserve">
|
||||
<value>504</value>
|
||||
<comment>默认最小窗口宽度</comment>
|
||||
</data>
|
||||
</root>
|
||||
30
Manager/Properties/Settings.Designer.cs
generated
Normal file
30
Manager/Properties/Settings.Designer.cs
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Manager.Properties
|
||||
{
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute ()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute ("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||
internal sealed partial class Settings: global::System.Configuration.ApplicationSettingsBase
|
||||
{
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized (new Settings ())));
|
||||
|
||||
public static Settings Default
|
||||
{
|
||||
get
|
||||
{
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Manager/Properties/Settings.settings
Normal file
7
Manager/Properties/Settings.settings
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
663
Manager/ShortcutCreateForm.Designer.cs
generated
Normal file
663
Manager/ShortcutCreateForm.Designer.cs
generated
Normal file
@@ -0,0 +1,663 @@
|
||||
namespace Manager
|
||||
{
|
||||
partial class ShortcutCreateForm
|
||||
{
|
||||
/// <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 ()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ShortcutCreateForm));
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.iconSetGen = new System.Windows.Forms.RadioButton();
|
||||
this.iconSetFromFile = new System.Windows.Forms.RadioButton();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.iconFileInput = new System.Windows.Forms.TextBox();
|
||||
this.iconFileBrowser = new System.Windows.Forms.Button();
|
||||
this.label7 = new System.Windows.Forms.Label();
|
||||
this.customIconDisplay = new System.Windows.Forms.PictureBox();
|
||||
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.label5 = new System.Windows.Forms.Label();
|
||||
this.colorPickerButton = new System.Windows.Forms.Button();
|
||||
this.colorInputAndPreview = new System.Windows.Forms.TextBox();
|
||||
this.label6 = new System.Windows.Forms.Label();
|
||||
this.ratio8_7 = new System.Windows.Forms.RadioButton();
|
||||
this.ratio3_2 = new System.Windows.Forms.RadioButton();
|
||||
this.ratio1_1 = new System.Windows.Forms.RadioButton();
|
||||
this.ratioCustom = new System.Windows.Forms.RadioButton();
|
||||
this.label10 = new System.Windows.Forms.Label();
|
||||
this.tableLayoutPanel6 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.ratioCustomBack = new System.Windows.Forms.TextBox();
|
||||
this.ratioCustomFore = new System.Windows.Forms.TextBox();
|
||||
this.label11 = new System.Windows.Forms.Label();
|
||||
this.label12 = new System.Windows.Forms.Label();
|
||||
this.shortcutNameInput = new System.Windows.Forms.TextBox();
|
||||
this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.label8 = new System.Windows.Forms.Label();
|
||||
this.label9 = new System.Windows.Forms.Label();
|
||||
this.imageSizeList = new System.Windows.Forms.DataGridView();
|
||||
this.Column1 = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.Column2 = new System.Windows.Forms.DataGridViewImageColumn();
|
||||
this.imagesPreview = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.tableLayoutPanel5 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.buttonGen = new System.Windows.Forms.Button();
|
||||
this.buttonCancel = new System.Windows.Forms.Button();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.tableLayoutPanel2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.customIconDisplay)).BeginInit();
|
||||
this.tableLayoutPanel3.SuspendLayout();
|
||||
this.tableLayoutPanel6.SuspendLayout();
|
||||
this.tableLayoutPanel4.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.imageSizeList)).BeginInit();
|
||||
this.tableLayoutPanel5.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 7;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 24F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 5F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 5F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 25F));
|
||||
this.tableLayoutPanel1.Controls.Add(this.label1, 1, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.label2, 1, 3);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 1, 5);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel3, 3, 5);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel4, 5, 5);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel5, 1, 7);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 9;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 10F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 10F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 10F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F));
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(782, 553);
|
||||
this.tableLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.label1, 5);
|
||||
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label1.Font = new System.Drawing.Font("微软雅黑 Light", 20F);
|
||||
this.label1.Location = new System.Drawing.Point(27, 24);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(727, 45);
|
||||
this.label1.TabIndex = 0;
|
||||
this.label1.Text = "Create Desktop Shortcut";
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.label2, 5);
|
||||
this.label2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label2.Location = new System.Drawing.Point(27, 79);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(727, 60);
|
||||
this.label2.TabIndex = 1;
|
||||
this.label2.Text = resources.GetString("label2.Text");
|
||||
//
|
||||
// tableLayoutPanel2
|
||||
//
|
||||
this.tableLayoutPanel2.ColumnCount = 2;
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 103F));
|
||||
this.tableLayoutPanel2.Controls.Add(this.label3, 0, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.iconSetGen, 0, 2);
|
||||
this.tableLayoutPanel2.Controls.Add(this.iconSetFromFile, 0, 3);
|
||||
this.tableLayoutPanel2.Controls.Add(this.label4, 0, 5);
|
||||
this.tableLayoutPanel2.Controls.Add(this.iconFileInput, 0, 6);
|
||||
this.tableLayoutPanel2.Controls.Add(this.iconFileBrowser, 1, 7);
|
||||
this.tableLayoutPanel2.Controls.Add(this.label7, 0, 8);
|
||||
this.tableLayoutPanel2.Controls.Add(this.customIconDisplay, 0, 9);
|
||||
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(27, 152);
|
||||
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
this.tableLayoutPanel2.RowCount = 10;
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 8F));
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 8F));
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 34F));
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 39F));
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 18F));
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 13F));
|
||||
this.tableLayoutPanel2.Size = new System.Drawing.Size(235, 324);
|
||||
this.tableLayoutPanel2.TabIndex = 2;
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.tableLayoutPanel2.SetColumnSpan(this.label3, 2);
|
||||
this.label3.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label3.Location = new System.Drawing.Point(3, 0);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(229, 40);
|
||||
this.label3.TabIndex = 0;
|
||||
this.label3.Text = "Please select the method for setting the icon.";
|
||||
//
|
||||
// iconSetGen
|
||||
//
|
||||
this.iconSetGen.AutoSize = true;
|
||||
this.iconSetGen.Checked = true;
|
||||
this.tableLayoutPanel2.SetColumnSpan(this.iconSetGen, 2);
|
||||
this.iconSetGen.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.iconSetGen.Location = new System.Drawing.Point(3, 51);
|
||||
this.iconSetGen.Name = "iconSetGen";
|
||||
this.iconSetGen.Size = new System.Drawing.Size(229, 24);
|
||||
this.iconSetGen.TabIndex = 1;
|
||||
this.iconSetGen.TabStop = true;
|
||||
this.iconSetGen.Text = "Generate an icon";
|
||||
this.iconSetGen.UseVisualStyleBackColor = true;
|
||||
this.iconSetGen.CheckedChanged += new System.EventHandler(this.iconSetGen_CheckedChanged);
|
||||
//
|
||||
// iconSetFromFile
|
||||
//
|
||||
this.iconSetFromFile.AutoSize = true;
|
||||
this.tableLayoutPanel2.SetColumnSpan(this.iconSetFromFile, 2);
|
||||
this.iconSetFromFile.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.iconSetFromFile.Location = new System.Drawing.Point(3, 81);
|
||||
this.iconSetFromFile.Name = "iconSetFromFile";
|
||||
this.iconSetFromFile.Size = new System.Drawing.Size(229, 24);
|
||||
this.iconSetFromFile.TabIndex = 2;
|
||||
this.iconSetFromFile.Text = "Use existing icons";
|
||||
this.iconSetFromFile.UseVisualStyleBackColor = true;
|
||||
this.iconSetFromFile.CheckedChanged += new System.EventHandler(this.iconSetFromFile_CheckedChanged);
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.tableLayoutPanel2.SetColumnSpan(this.label4, 2);
|
||||
this.label4.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label4.Location = new System.Drawing.Point(3, 116);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(229, 20);
|
||||
this.label4.TabIndex = 3;
|
||||
this.label4.Text = "Custom icon file path:";
|
||||
//
|
||||
// iconFileInput
|
||||
//
|
||||
this.tableLayoutPanel2.SetColumnSpan(this.iconFileInput, 2);
|
||||
this.iconFileInput.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.iconFileInput.Location = new System.Drawing.Point(3, 139);
|
||||
this.iconFileInput.Name = "iconFileInput";
|
||||
this.iconFileInput.Size = new System.Drawing.Size(229, 27);
|
||||
this.iconFileInput.TabIndex = 4;
|
||||
this.iconFileInput.TextChanged += new System.EventHandler(this.iconFileInput_TextChanged);
|
||||
//
|
||||
// iconFileBrowser
|
||||
//
|
||||
this.iconFileBrowser.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.iconFileBrowser.Location = new System.Drawing.Point(135, 173);
|
||||
this.iconFileBrowser.Name = "iconFileBrowser";
|
||||
this.iconFileBrowser.Size = new System.Drawing.Size(97, 33);
|
||||
this.iconFileBrowser.TabIndex = 5;
|
||||
this.iconFileBrowser.Text = "Browser...";
|
||||
this.iconFileBrowser.UseVisualStyleBackColor = true;
|
||||
this.iconFileBrowser.Click += new System.EventHandler(this.iconFileBrowser_Click);
|
||||
//
|
||||
// label7
|
||||
//
|
||||
this.label7.AutoSize = true;
|
||||
this.label7.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label7.Location = new System.Drawing.Point(3, 209);
|
||||
this.label7.Name = "label7";
|
||||
this.label7.Size = new System.Drawing.Size(126, 18);
|
||||
this.label7.TabIndex = 6;
|
||||
this.label7.Text = "Preview:";
|
||||
//
|
||||
// customIconDisplay
|
||||
//
|
||||
this.customIconDisplay.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center;
|
||||
this.tableLayoutPanel2.SetColumnSpan(this.customIconDisplay, 2);
|
||||
this.customIconDisplay.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.customIconDisplay.Location = new System.Drawing.Point(3, 230);
|
||||
this.customIconDisplay.Name = "customIconDisplay";
|
||||
this.customIconDisplay.Size = new System.Drawing.Size(229, 91);
|
||||
this.customIconDisplay.TabIndex = 7;
|
||||
this.customIconDisplay.TabStop = false;
|
||||
//
|
||||
// tableLayoutPanel3
|
||||
//
|
||||
this.tableLayoutPanel3.ColumnCount = 2;
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 97F));
|
||||
this.tableLayoutPanel3.Controls.Add(this.label5, 0, 0);
|
||||
this.tableLayoutPanel3.Controls.Add(this.colorPickerButton, 1, 1);
|
||||
this.tableLayoutPanel3.Controls.Add(this.colorInputAndPreview, 0, 1);
|
||||
this.tableLayoutPanel3.Controls.Add(this.label6, 0, 2);
|
||||
this.tableLayoutPanel3.Controls.Add(this.ratio8_7, 0, 3);
|
||||
this.tableLayoutPanel3.Controls.Add(this.ratio3_2, 0, 4);
|
||||
this.tableLayoutPanel3.Controls.Add(this.ratio1_1, 0, 5);
|
||||
this.tableLayoutPanel3.Controls.Add(this.ratioCustom, 0, 6);
|
||||
this.tableLayoutPanel3.Controls.Add(this.label10, 0, 7);
|
||||
this.tableLayoutPanel3.Controls.Add(this.tableLayoutPanel6, 0, 8);
|
||||
this.tableLayoutPanel3.Controls.Add(this.label12, 0, 9);
|
||||
this.tableLayoutPanel3.Controls.Add(this.shortcutNameInput, 0, 10);
|
||||
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel3.Location = new System.Drawing.Point(273, 152);
|
||||
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
|
||||
this.tableLayoutPanel3.RowCount = 11;
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 35F));
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 32F));
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 18F));
|
||||
this.tableLayoutPanel3.Size = new System.Drawing.Size(235, 324);
|
||||
this.tableLayoutPanel3.TabIndex = 3;
|
||||
//
|
||||
// label5
|
||||
//
|
||||
this.label5.AutoSize = true;
|
||||
this.tableLayoutPanel3.SetColumnSpan(this.label5, 2);
|
||||
this.label5.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label5.Location = new System.Drawing.Point(3, 0);
|
||||
this.label5.Name = "label5";
|
||||
this.label5.Size = new System.Drawing.Size(229, 20);
|
||||
this.label5.TabIndex = 0;
|
||||
this.label5.Text = "Background Color:";
|
||||
//
|
||||
// colorPickerButton
|
||||
//
|
||||
this.colorPickerButton.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.colorPickerButton.Location = new System.Drawing.Point(141, 23);
|
||||
this.colorPickerButton.Name = "colorPickerButton";
|
||||
this.colorPickerButton.Size = new System.Drawing.Size(91, 29);
|
||||
this.colorPickerButton.TabIndex = 1;
|
||||
this.colorPickerButton.Text = "Select";
|
||||
this.colorPickerButton.UseVisualStyleBackColor = true;
|
||||
this.colorPickerButton.Click += new System.EventHandler(this.colorPickerButton_Click);
|
||||
//
|
||||
// colorInputAndPreview
|
||||
//
|
||||
this.colorInputAndPreview.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.colorInputAndPreview.Location = new System.Drawing.Point(3, 23);
|
||||
this.colorInputAndPreview.Name = "colorInputAndPreview";
|
||||
this.colorInputAndPreview.Size = new System.Drawing.Size(132, 27);
|
||||
this.colorInputAndPreview.TabIndex = 2;
|
||||
this.colorInputAndPreview.TextChanged += new System.EventHandler(this.colorInputAndPreview_TextChanged);
|
||||
//
|
||||
// label6
|
||||
//
|
||||
this.label6.AutoSize = true;
|
||||
this.tableLayoutPanel3.SetColumnSpan(this.label6, 2);
|
||||
this.label6.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label6.Location = new System.Drawing.Point(3, 55);
|
||||
this.label6.Name = "label6";
|
||||
this.label6.Size = new System.Drawing.Size(229, 40);
|
||||
this.label6.TabIndex = 3;
|
||||
this.label6.Text = "Background-to-foreground edge ratio";
|
||||
//
|
||||
// ratio8_7
|
||||
//
|
||||
this.ratio8_7.AutoSize = true;
|
||||
this.ratio8_7.Checked = true;
|
||||
this.tableLayoutPanel3.SetColumnSpan(this.ratio8_7, 2);
|
||||
this.ratio8_7.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ratio8_7.Location = new System.Drawing.Point(3, 98);
|
||||
this.ratio8_7.Name = "ratio8_7";
|
||||
this.ratio8_7.Size = new System.Drawing.Size(229, 24);
|
||||
this.ratio8_7.TabIndex = 4;
|
||||
this.ratio8_7.TabStop = true;
|
||||
this.ratio8_7.Text = "8:7";
|
||||
this.ratio8_7.UseVisualStyleBackColor = true;
|
||||
this.ratio8_7.CheckedChanged += new System.EventHandler(this.ratio8_7_CheckedChanged);
|
||||
//
|
||||
// ratio3_2
|
||||
//
|
||||
this.ratio3_2.AutoSize = true;
|
||||
this.tableLayoutPanel3.SetColumnSpan(this.ratio3_2, 2);
|
||||
this.ratio3_2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ratio3_2.Location = new System.Drawing.Point(3, 128);
|
||||
this.ratio3_2.Name = "ratio3_2";
|
||||
this.ratio3_2.Size = new System.Drawing.Size(229, 24);
|
||||
this.ratio3_2.TabIndex = 5;
|
||||
this.ratio3_2.Text = "3:2";
|
||||
this.ratio3_2.UseVisualStyleBackColor = true;
|
||||
this.ratio3_2.CheckedChanged += new System.EventHandler(this.ratio3_2_CheckedChanged);
|
||||
//
|
||||
// ratio1_1
|
||||
//
|
||||
this.ratio1_1.AutoSize = true;
|
||||
this.tableLayoutPanel3.SetColumnSpan(this.ratio1_1, 2);
|
||||
this.ratio1_1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ratio1_1.Location = new System.Drawing.Point(3, 158);
|
||||
this.ratio1_1.Name = "ratio1_1";
|
||||
this.ratio1_1.Size = new System.Drawing.Size(229, 24);
|
||||
this.ratio1_1.TabIndex = 6;
|
||||
this.ratio1_1.Text = "1:1";
|
||||
this.ratio1_1.UseVisualStyleBackColor = true;
|
||||
this.ratio1_1.CheckedChanged += new System.EventHandler(this.ratio1_1_CheckedChanged);
|
||||
//
|
||||
// ratioCustom
|
||||
//
|
||||
this.ratioCustom.AutoSize = true;
|
||||
this.tableLayoutPanel3.SetColumnSpan(this.ratioCustom, 2);
|
||||
this.ratioCustom.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ratioCustom.Location = new System.Drawing.Point(3, 188);
|
||||
this.ratioCustom.Name = "ratioCustom";
|
||||
this.ratioCustom.Size = new System.Drawing.Size(229, 24);
|
||||
this.ratioCustom.TabIndex = 7;
|
||||
this.ratioCustom.Text = "Custom";
|
||||
this.ratioCustom.UseVisualStyleBackColor = true;
|
||||
this.ratioCustom.CheckedChanged += new System.EventHandler(this.ratioCustom_CheckedChanged);
|
||||
//
|
||||
// label10
|
||||
//
|
||||
this.label10.AutoSize = true;
|
||||
this.tableLayoutPanel3.SetColumnSpan(this.label10, 2);
|
||||
this.label10.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label10.Location = new System.Drawing.Point(3, 215);
|
||||
this.label10.Name = "label10";
|
||||
this.label10.Size = new System.Drawing.Size(229, 20);
|
||||
this.label10.TabIndex = 8;
|
||||
this.label10.Text = "Custom Ratio:";
|
||||
//
|
||||
// tableLayoutPanel6
|
||||
//
|
||||
this.tableLayoutPanel6.ColumnCount = 3;
|
||||
this.tableLayoutPanel3.SetColumnSpan(this.tableLayoutPanel6, 2);
|
||||
this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel6.Controls.Add(this.ratioCustomBack, 0, 0);
|
||||
this.tableLayoutPanel6.Controls.Add(this.ratioCustomFore, 2, 0);
|
||||
this.tableLayoutPanel6.Controls.Add(this.label11, 1, 0);
|
||||
this.tableLayoutPanel6.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel6.Location = new System.Drawing.Point(0, 235);
|
||||
this.tableLayoutPanel6.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.tableLayoutPanel6.Name = "tableLayoutPanel6";
|
||||
this.tableLayoutPanel6.RowCount = 1;
|
||||
this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel6.Size = new System.Drawing.Size(235, 32);
|
||||
this.tableLayoutPanel6.TabIndex = 9;
|
||||
//
|
||||
// ratioCustomBack
|
||||
//
|
||||
this.ratioCustomBack.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ratioCustomBack.Location = new System.Drawing.Point(3, 3);
|
||||
this.ratioCustomBack.Name = "ratioCustomBack";
|
||||
this.ratioCustomBack.Size = new System.Drawing.Size(101, 27);
|
||||
this.ratioCustomBack.TabIndex = 0;
|
||||
this.ratioCustomBack.Text = "8";
|
||||
this.ratioCustomBack.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// ratioCustomFore
|
||||
//
|
||||
this.ratioCustomFore.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ratioCustomFore.Location = new System.Drawing.Point(130, 3);
|
||||
this.ratioCustomFore.Name = "ratioCustomFore";
|
||||
this.ratioCustomFore.Size = new System.Drawing.Size(102, 27);
|
||||
this.ratioCustomFore.TabIndex = 1;
|
||||
this.ratioCustomFore.Text = "7";
|
||||
this.ratioCustomFore.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// label11
|
||||
//
|
||||
this.label11.AutoSize = true;
|
||||
this.label11.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label11.Location = new System.Drawing.Point(110, 0);
|
||||
this.label11.Name = "label11";
|
||||
this.label11.Size = new System.Drawing.Size(14, 32);
|
||||
this.label11.TabIndex = 2;
|
||||
this.label11.Text = ":";
|
||||
this.label11.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// label12
|
||||
//
|
||||
this.label12.AutoSize = true;
|
||||
this.tableLayoutPanel3.SetColumnSpan(this.label12, 2);
|
||||
this.label12.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label12.Location = new System.Drawing.Point(3, 267);
|
||||
this.label12.Name = "label12";
|
||||
this.label12.Size = new System.Drawing.Size(229, 20);
|
||||
this.label12.TabIndex = 10;
|
||||
this.label12.Text = "Shortcut Display Name";
|
||||
//
|
||||
// shortcutNameInput
|
||||
//
|
||||
this.tableLayoutPanel3.SetColumnSpan(this.shortcutNameInput, 2);
|
||||
this.shortcutNameInput.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.shortcutNameInput.Location = new System.Drawing.Point(3, 290);
|
||||
this.shortcutNameInput.Name = "shortcutNameInput";
|
||||
this.shortcutNameInput.Size = new System.Drawing.Size(229, 27);
|
||||
this.shortcutNameInput.TabIndex = 11;
|
||||
//
|
||||
// tableLayoutPanel4
|
||||
//
|
||||
this.tableLayoutPanel4.ColumnCount = 1;
|
||||
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel4.Controls.Add(this.label8, 0, 0);
|
||||
this.tableLayoutPanel4.Controls.Add(this.label9, 0, 2);
|
||||
this.tableLayoutPanel4.Controls.Add(this.imageSizeList, 0, 1);
|
||||
this.tableLayoutPanel4.Controls.Add(this.imagesPreview, 0, 3);
|
||||
this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel4.Location = new System.Drawing.Point(519, 152);
|
||||
this.tableLayoutPanel4.Name = "tableLayoutPanel4";
|
||||
this.tableLayoutPanel4.RowCount = 4;
|
||||
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel4.Size = new System.Drawing.Size(235, 324);
|
||||
this.tableLayoutPanel4.TabIndex = 4;
|
||||
//
|
||||
// label8
|
||||
//
|
||||
this.label8.AutoSize = true;
|
||||
this.label8.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label8.Location = new System.Drawing.Point(3, 0);
|
||||
this.label8.Name = "label8";
|
||||
this.label8.Size = new System.Drawing.Size(229, 20);
|
||||
this.label8.TabIndex = 0;
|
||||
this.label8.Text = "Image List:";
|
||||
//
|
||||
// label9
|
||||
//
|
||||
this.label9.AutoSize = true;
|
||||
this.label9.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label9.Location = new System.Drawing.Point(3, 162);
|
||||
this.label9.Name = "label9";
|
||||
this.label9.Size = new System.Drawing.Size(229, 20);
|
||||
this.label9.TabIndex = 1;
|
||||
this.label9.Text = "Preview:";
|
||||
//
|
||||
// imageSizeList
|
||||
//
|
||||
this.imageSizeList.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.imageSizeList.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
|
||||
this.Column1,
|
||||
this.Column2});
|
||||
this.imageSizeList.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.imageSizeList.Location = new System.Drawing.Point(3, 23);
|
||||
this.imageSizeList.Name = "imageSizeList";
|
||||
this.imageSizeList.RowTemplate.Height = 27;
|
||||
this.imageSizeList.Size = new System.Drawing.Size(229, 136);
|
||||
this.imageSizeList.TabIndex = 2;
|
||||
this.imageSizeList.CellDoubleClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.imageSizeList_CellDoubleClick);
|
||||
//
|
||||
// Column1
|
||||
//
|
||||
this.Column1.HeaderText = "Size";
|
||||
this.Column1.Name = "Column1";
|
||||
this.Column1.Width = 50;
|
||||
//
|
||||
// Column2
|
||||
//
|
||||
this.Column2.HeaderText = "Image";
|
||||
this.Column2.Name = "Column2";
|
||||
//
|
||||
// imagesPreview
|
||||
//
|
||||
this.imagesPreview.AutoScroll = true;
|
||||
this.imagesPreview.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.imagesPreview.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
|
||||
this.imagesPreview.Location = new System.Drawing.Point(3, 185);
|
||||
this.imagesPreview.Name = "imagesPreview";
|
||||
this.imagesPreview.Size = new System.Drawing.Size(229, 136);
|
||||
this.imagesPreview.TabIndex = 3;
|
||||
//
|
||||
// tableLayoutPanel5
|
||||
//
|
||||
this.tableLayoutPanel5.ColumnCount = 5;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.tableLayoutPanel5, 5);
|
||||
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 100F));
|
||||
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 172F));
|
||||
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 100F));
|
||||
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel5.Controls.Add(this.buttonGen, 1, 1);
|
||||
this.tableLayoutPanel5.Controls.Add(this.buttonCancel, 3, 1);
|
||||
this.tableLayoutPanel5.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel5.Location = new System.Drawing.Point(24, 489);
|
||||
this.tableLayoutPanel5.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.tableLayoutPanel5.Name = "tableLayoutPanel5";
|
||||
this.tableLayoutPanel5.RowCount = 3;
|
||||
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 32F));
|
||||
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel5.Size = new System.Drawing.Size(733, 40);
|
||||
this.tableLayoutPanel5.TabIndex = 5;
|
||||
//
|
||||
// buttonGen
|
||||
//
|
||||
this.buttonGen.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.buttonGen.Location = new System.Drawing.Point(180, 4);
|
||||
this.buttonGen.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.buttonGen.Name = "buttonGen";
|
||||
this.buttonGen.Size = new System.Drawing.Size(100, 32);
|
||||
this.buttonGen.TabIndex = 0;
|
||||
this.buttonGen.Text = "Generate";
|
||||
this.buttonGen.UseVisualStyleBackColor = true;
|
||||
this.buttonGen.Click += new System.EventHandler(this.buttonGen_Click);
|
||||
//
|
||||
// buttonCancel
|
||||
//
|
||||
this.buttonCancel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.buttonCancel.Location = new System.Drawing.Point(452, 4);
|
||||
this.buttonCancel.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.buttonCancel.Name = "buttonCancel";
|
||||
this.buttonCancel.Size = new System.Drawing.Size(100, 32);
|
||||
this.buttonCancel.TabIndex = 1;
|
||||
this.buttonCancel.Text = "Cancel";
|
||||
this.buttonCancel.UseVisualStyleBackColor = true;
|
||||
this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click);
|
||||
//
|
||||
// ShortcutCreateForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = System.Drawing.Color.White;
|
||||
this.ClientSize = new System.Drawing.Size(782, 553);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.Name = "ShortcutCreateForm";
|
||||
this.ShowIcon = false;
|
||||
this.Text = "ShortcutCreateForm";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ShortcutCreateForm_FormClosing);
|
||||
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ShortcutCreateForm_FormClosed);
|
||||
this.Load += new System.EventHandler(this.ShortcutCreateForm_Load);
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
this.tableLayoutPanel2.ResumeLayout(false);
|
||||
this.tableLayoutPanel2.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.customIconDisplay)).EndInit();
|
||||
this.tableLayoutPanel3.ResumeLayout(false);
|
||||
this.tableLayoutPanel3.PerformLayout();
|
||||
this.tableLayoutPanel6.ResumeLayout(false);
|
||||
this.tableLayoutPanel6.PerformLayout();
|
||||
this.tableLayoutPanel4.ResumeLayout(false);
|
||||
this.tableLayoutPanel4.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.imageSizeList)).EndInit();
|
||||
this.tableLayoutPanel5.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.RadioButton iconSetGen;
|
||||
private System.Windows.Forms.RadioButton iconSetFromFile;
|
||||
private System.Windows.Forms.Label label4;
|
||||
private System.Windows.Forms.TextBox iconFileInput;
|
||||
private System.Windows.Forms.Button iconFileBrowser;
|
||||
private System.Windows.Forms.Label label7;
|
||||
private System.Windows.Forms.PictureBox customIconDisplay;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
|
||||
private System.Windows.Forms.Label label5;
|
||||
private System.Windows.Forms.Button colorPickerButton;
|
||||
private System.Windows.Forms.TextBox colorInputAndPreview;
|
||||
private System.Windows.Forms.Label label6;
|
||||
private System.Windows.Forms.RadioButton ratio8_7;
|
||||
private System.Windows.Forms.RadioButton ratio3_2;
|
||||
private System.Windows.Forms.RadioButton ratio1_1;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4;
|
||||
private System.Windows.Forms.Label label8;
|
||||
private System.Windows.Forms.Label label9;
|
||||
private System.Windows.Forms.RadioButton ratioCustom;
|
||||
private System.Windows.Forms.Label label10;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel6;
|
||||
private System.Windows.Forms.TextBox ratioCustomBack;
|
||||
private System.Windows.Forms.TextBox ratioCustomFore;
|
||||
private System.Windows.Forms.Label label11;
|
||||
private System.Windows.Forms.DataGridView imageSizeList;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn Column1;
|
||||
private System.Windows.Forms.DataGridViewImageColumn Column2;
|
||||
private System.Windows.Forms.FlowLayoutPanel imagesPreview;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel5;
|
||||
private System.Windows.Forms.Button buttonGen;
|
||||
private System.Windows.Forms.Button buttonCancel;
|
||||
private System.Windows.Forms.Label label12;
|
||||
private System.Windows.Forms.TextBox shortcutNameInput;
|
||||
}
|
||||
}
|
||||
571
Manager/ShortcutCreateForm.cs
Normal file
571
Manager/ShortcutCreateForm.cs
Normal file
@@ -0,0 +1,571 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Bridge;
|
||||
namespace Manager
|
||||
{
|
||||
public partial class ShortcutCreateForm: Form
|
||||
{
|
||||
public ShortcutCreateForm ()
|
||||
{
|
||||
InitializeComponent ();
|
||||
Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_TITLE");
|
||||
label1.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_TITLE");
|
||||
label2.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_DESC");
|
||||
label3.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_ICONTYPE");
|
||||
iconSetGen.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_ICONTYPE_GEN");
|
||||
iconSetFromFile.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_ICONTYPE_SEL");
|
||||
label4.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_ICONTYPE_SEL_ICONPATH");
|
||||
iconFileBrowser.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_BROWSE");
|
||||
label7.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_PREVIEW");
|
||||
label5.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_BACKGROUNDCOLOR");
|
||||
colorPickerButton.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_SELECT");
|
||||
label6.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_RATIO");
|
||||
ratioCustom.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_RATIO_CUSTOM");
|
||||
label10.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_RATIO_CUSTOMRATIO");
|
||||
label12.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_DISPLAYNAME");
|
||||
label8.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_IMAGELIST");
|
||||
label9.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_PREVIEW");
|
||||
buttonGen.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_GENERATE");
|
||||
buttonCancel.Text = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_CANCEL");
|
||||
Column1.HeaderText = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_SIZE");
|
||||
Column2.HeaderText = ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_IMAGE");
|
||||
_imageItems.ListChanged += ImageItems_ListChanged;
|
||||
RefreshCustomRatioStatus ();
|
||||
RefreshIconSourceMode ();
|
||||
}
|
||||
private void ImageItems_ListChanged (object sender, ListChangedEventArgs e) { RefreshImagePreview (); }
|
||||
void RefreshImagePreview ()
|
||||
{
|
||||
imagesPreview.SuspendLayout ();
|
||||
imagesPreview.Controls.Clear ();
|
||||
foreach (var item in _imageItems.OrderBy (i => i.Size))
|
||||
{
|
||||
var display = new ImageDisplay
|
||||
{
|
||||
IconSize = item.Size,
|
||||
ForegroundImage = item.Image,
|
||||
BackgroundColor = GetCurrentBackgroundColor (),
|
||||
Ratio = GetCurrentRatio ()
|
||||
};
|
||||
imagesPreview.Controls.Add (display);
|
||||
}
|
||||
imagesPreview.ResumeLayout ();
|
||||
}
|
||||
void UpdateRatio (decimal ratio)
|
||||
{
|
||||
foreach (ImageDisplay d in imagesPreview.Controls) d.Ratio = ratio;
|
||||
}
|
||||
void UpdateBackgroundColor (Color color)
|
||||
{
|
||||
foreach (ImageDisplay d in imagesPreview.Controls) d.BackgroundColor = color;
|
||||
}
|
||||
public Color GetCurrentBackgroundColor () => DataUtils.UITheme.StringToColor (colorInputAndPreview.Text);
|
||||
public decimal GetCurrentRatio ()
|
||||
{
|
||||
if (ratio8_7.Checked) return (decimal)(8m / 7m);
|
||||
if (ratio3_2.Checked) return 1.5m;
|
||||
if (ratio1_1.Checked) return 1m;
|
||||
try
|
||||
{
|
||||
if (ratioCustom.Checked)
|
||||
{
|
||||
decimal l = 0m, r = 0m;
|
||||
decimal.TryParse (ratioCustomBack.Text, out l);
|
||||
decimal.TryParse (ratioCustomFore.Text, out r);
|
||||
return l / r;
|
||||
}
|
||||
} catch { }
|
||||
return 0m;
|
||||
}
|
||||
class ImageItem
|
||||
{
|
||||
public int Size { get; set; }
|
||||
public Image Image { get; set; }
|
||||
}
|
||||
private BindingList<ImageItem> _imageItems = new BindingList<ImageItem>();
|
||||
Dictionary<int, string> ExtractBest (Dictionary<AppxPackage.PriResourceKey, string> source, int baseSize)
|
||||
{
|
||||
if (source == null || source.Count == 0) return null;
|
||||
var result = new Dictionary<int, string> ();
|
||||
foreach (var kv in source)
|
||||
{
|
||||
if (kv.Key.IsTargetSize &&
|
||||
kv.Key.Contrast == AppxPackage.PriResourceKey.PriContrast.None)
|
||||
{
|
||||
result [kv.Key.Value] = kv.Value;
|
||||
}
|
||||
}
|
||||
if (result.Count > 0) return result;
|
||||
foreach (var kv in source)
|
||||
{
|
||||
if (kv.Key.IsTargetSize)
|
||||
{
|
||||
result [kv.Key.Value] = kv.Value;
|
||||
}
|
||||
}
|
||||
if (result.Count > 0) return result;
|
||||
foreach (var kv in source)
|
||||
{
|
||||
if (kv.Key.IsScale &&
|
||||
kv.Key.Contrast == AppxPackage.PriResourceKey.PriContrast.None)
|
||||
{
|
||||
int size = (int)(kv.Key.Value * 0.01 * baseSize);
|
||||
result [size] = kv.Value;
|
||||
}
|
||||
}
|
||||
if (result.Count > 0)
|
||||
return result;
|
||||
foreach (var kv in source)
|
||||
{
|
||||
if (kv.Key.IsScale)
|
||||
{
|
||||
int size = (int)(kv.Key.Value * 0.01 * baseSize);
|
||||
result [size] = kv.Value;
|
||||
}
|
||||
}
|
||||
return result.Count > 0 ? result : null;
|
||||
}
|
||||
void InitImageList (Dictionary<int, Image> images)
|
||||
{
|
||||
_imageItems = new BindingList<ImageItem> (
|
||||
images.Select (kv => new ImageItem
|
||||
{
|
||||
Size = kv.Key,
|
||||
Image = kv.Value
|
||||
}).ToList ()
|
||||
);
|
||||
imageSizeList.AutoGenerateColumns = false;
|
||||
Column1.DataPropertyName = nameof (ImageItem.Size);
|
||||
Column2.DataPropertyName = nameof (ImageItem.Image);
|
||||
imageSizeList.DataSource = _imageItems;
|
||||
|
||||
}
|
||||
private string installLocation = "";
|
||||
private string genAppUserId = "";
|
||||
private Dictionary<int, Image> _initList = new Dictionary<int, Image> ();
|
||||
private void InitInfos ()
|
||||
{
|
||||
try
|
||||
{
|
||||
_initList?.Clear ();
|
||||
_initList = null;
|
||||
using (var m = new AppxPackage.ManifestReader (Path.Combine (installLocation, "AppxManifest.xml")))
|
||||
{
|
||||
m.EnablePri = false;
|
||||
m.UsePri = true;
|
||||
AppxPackage.MRApplication app = null;
|
||||
string logo_30 = "",
|
||||
smallLogo = "",
|
||||
logo = "",
|
||||
logo_44 = "";
|
||||
foreach (var i in m.Applications)
|
||||
{
|
||||
if (i.UserModelID?.Trim ()?.ToLowerInvariant () == genAppUserId?.Trim ()?.ToLowerInvariant ())
|
||||
{
|
||||
app = i;
|
||||
logo_44 = app ["Square44x44Logo"];
|
||||
logo_30 = app ["Square30x30Logo"];
|
||||
logo = app ["Logo"];
|
||||
smallLogo = app ["SmallLogo"];
|
||||
break;
|
||||
}
|
||||
}
|
||||
m.EnablePri = true;
|
||||
foreach (var i in m.Applications)
|
||||
{
|
||||
if (i.UserModelID?.Trim ()?.ToLowerInvariant () == genAppUserId?.Trim ()?.ToLowerInvariant ())
|
||||
{
|
||||
app = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.Invoke ((Action)(() =>
|
||||
{
|
||||
colorInputAndPreview.Text = app ["BackgroundColor"];
|
||||
shortcutNameInput.Text = app ["DisplayName"];
|
||||
if (string.IsNullOrWhiteSpace (shortcutNameInput.Text))
|
||||
shortcutNameInput.Text = app ["SmallLogo"];
|
||||
}));
|
||||
Dictionary<AppxPackage.PriResourceKey, string> logo_30list = m.PriFile.ResourceAllValues (logo_30),
|
||||
logo_smalllist = m.PriFile.ResourceAllValues (smallLogo),
|
||||
logo_list = m.PriFile.ResourceAllValues (logo),
|
||||
logo_44list = m.PriFile.ResourceAllValues (logo_44);
|
||||
Dictionary<int, string> filteredlist = null;
|
||||
filteredlist =
|
||||
ExtractBest (logo_44list, 44)
|
||||
?? ExtractBest (logo_30list, 30)
|
||||
?? ExtractBest (logo_smalllist, 30)
|
||||
?? ExtractBest (logo_list, 150);
|
||||
Dictionary<int, Image> imageList = new Dictionary<int, Image> ();
|
||||
foreach (var kv in filteredlist)
|
||||
{
|
||||
try
|
||||
{
|
||||
var imgPath = Path.Combine (installLocation, kv.Value);
|
||||
var img = Image.FromFile (imgPath);
|
||||
if (img == null) continue;
|
||||
imageList [kv.Key] = img;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
_initList = imageList;
|
||||
this.Invoke ((Action)(() =>
|
||||
{
|
||||
InitImageList (imageList);
|
||||
RefreshImagePreview ();
|
||||
RefreshCustomRatioStatus ();
|
||||
RefreshIconSourceMode ();
|
||||
}));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.Invoke ((Action)(() => _imageItems.Clear ()));
|
||||
}
|
||||
}
|
||||
private void InitAsync ()
|
||||
{
|
||||
var loading = new LoadingStatusForm ();
|
||||
{
|
||||
loading.Show (this);
|
||||
loading.Refresh ();
|
||||
this.Invoke ((Action)(() => { Enabled = false; }));
|
||||
|
||||
Task.Factory.StartNew (() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
InitInfos ();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Invoke ((Action)(() =>
|
||||
{
|
||||
MessageBox.Show ($"Initialization failed: {ex.Message}");
|
||||
}));
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.Invoke ((Action)(() =>
|
||||
{
|
||||
loading.Close ();
|
||||
Enabled = true;
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
public string InstallLocation
|
||||
{
|
||||
get { return installLocation; }
|
||||
set { installLocation = value; InitAsync (); }
|
||||
}
|
||||
public string AppUserModelID
|
||||
{
|
||||
get { return genAppUserId; }
|
||||
set { genAppUserId = value; InitAsync (); }
|
||||
}
|
||||
public void InitCreater (string inslocation, string appUserId)
|
||||
{
|
||||
installLocation = inslocation;
|
||||
genAppUserId = appUserId;
|
||||
InitAsync ();
|
||||
}
|
||||
private void ShortcutCreateForm_Load (object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
private void ratio8_7_CheckedChanged (object sender, EventArgs e) { RefreshCustomRatioStatus (); }
|
||||
private void ratio3_2_CheckedChanged (object sender, EventArgs e) { RefreshCustomRatioStatus (); }
|
||||
private void ratio1_1_CheckedChanged (object sender, EventArgs e) { RefreshCustomRatioStatus (); }
|
||||
private void ratioCustom_CheckedChanged (object sender, EventArgs e) { RefreshCustomRatioStatus (); }
|
||||
private void RefreshCustomRatioStatus ()
|
||||
{
|
||||
ratioCustomBack.Enabled = ratioCustomFore.Enabled = ratioCustom.Checked;
|
||||
UpdateRatio (GetCurrentRatio ());
|
||||
}
|
||||
private void iconSetGen_CheckedChanged (object sender, EventArgs e) { RefreshIconSourceMode (); }
|
||||
private void iconSetFromFile_CheckedChanged (object sender, EventArgs e) { RefreshIconSourceMode (); }
|
||||
private void RefreshIconSourceMode ()
|
||||
{
|
||||
iconFileInput.Enabled = iconFileBrowser.Enabled = iconSetFromFile.Checked;
|
||||
colorInputAndPreview.Enabled = colorPickerButton.Enabled =
|
||||
ratio8_7.Enabled = ratio3_2.Enabled = ratio1_1.Enabled =
|
||||
ratioCustom.Enabled = ratioCustomBack.Enabled = ratioCustomFore.Enabled =
|
||||
iconSetGen.Checked;
|
||||
if (iconSetGen.Checked)
|
||||
{
|
||||
RefreshCustomRatioStatus ();
|
||||
}
|
||||
if (iconSetFromFile.Checked)
|
||||
{
|
||||
try
|
||||
{
|
||||
customIconDisplay.Image = new Icon (iconFileInput.Text)?.ToBitmap ();
|
||||
}
|
||||
catch
|
||||
{
|
||||
customIconDisplay.Image = null;
|
||||
}
|
||||
}
|
||||
else customIconDisplay.Image = null;
|
||||
}
|
||||
private void colorInputAndPreview_TextChanged (object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Color nowColor = DataUtils.UITheme.StringToColor (colorInputAndPreview.Text);
|
||||
double luminance = nowColor.R * 0.299 + nowColor.G * 0.587 + nowColor.B * 0.114;
|
||||
Color foreground = luminance < 128 ? Color.White : Color.Black;
|
||||
colorInputAndPreview.BackColor = nowColor;
|
||||
colorInputAndPreview.ForeColor = foreground;
|
||||
UpdateBackgroundColor (nowColor);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
private Bitmap GenerateIconBitmap (int size, Image foreground, Color background, decimal ratio)
|
||||
{
|
||||
var bmp = new Bitmap (size, size);
|
||||
using (var g = Graphics.FromImage (bmp))
|
||||
{
|
||||
g.Clear (background);
|
||||
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
|
||||
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
|
||||
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
|
||||
float foreSize = (float)(size / ratio);
|
||||
float x = (size - foreSize) / 2f;
|
||||
float y = (size - foreSize) / 2f;
|
||||
var destRect = new RectangleF (x, y, foreSize, foreSize);
|
||||
g.DrawImage (foreground, destRect);
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
Dictionary<int, Image> GenerateAllIconImages ()
|
||||
{
|
||||
var result = new Dictionary<int, Image> ();
|
||||
Color bg = GetCurrentBackgroundColor ();
|
||||
decimal ratio = GetCurrentRatio ();
|
||||
foreach (var item in _imageItems)
|
||||
{
|
||||
var bmp = GenerateIconBitmap (item.Size, item.Image, bg, ratio);
|
||||
result [item.Size] = bmp;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public static void SaveAsIcon (Dictionary<int, Image> images, string filePath)
|
||||
{
|
||||
using (var fs = new FileStream (filePath, FileMode.Create))
|
||||
using (var bw = new BinaryWriter (fs))
|
||||
{
|
||||
bw.Write ((short)0); // reserved
|
||||
bw.Write ((short)1); // type = icon
|
||||
bw.Write ((short)images.Count);
|
||||
int offset = 6 + (16 * images.Count);
|
||||
var imageData = new List<byte []> ();
|
||||
foreach (var kv in images.OrderBy (i => i.Key))
|
||||
{
|
||||
using (var ms = new MemoryStream ())
|
||||
{
|
||||
kv.Value.Save (ms, System.Drawing.Imaging.ImageFormat.Png);
|
||||
byte [] data = ms.ToArray ();
|
||||
imageData.Add (data);
|
||||
bw.Write ((byte)(kv.Key >= 256 ? 0 : kv.Key)); // width
|
||||
bw.Write ((byte)(kv.Key >= 256 ? 0 : kv.Key)); // height
|
||||
bw.Write ((byte)0); // color count
|
||||
bw.Write ((byte)0); // reserved
|
||||
bw.Write ((short)1); // planes
|
||||
bw.Write ((short)32); // bit count
|
||||
bw.Write (data.Length);
|
||||
bw.Write (offset);
|
||||
offset += data.Length;
|
||||
}
|
||||
}
|
||||
foreach (var data in imageData) bw.Write (data);
|
||||
}
|
||||
}
|
||||
private void iconFileInput_TextChanged (object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
customIconDisplay.Image = new Icon (iconFileInput.Text)?.ToBitmap ();
|
||||
}
|
||||
catch
|
||||
{
|
||||
customIconDisplay.Image = null;
|
||||
}
|
||||
}
|
||||
private void imageSizeList_CellDoubleClick (object sender, DataGridViewCellEventArgs e)
|
||||
{
|
||||
if (e.RowIndex < 0) return;
|
||||
if (imageSizeList.Columns [e.ColumnIndex] != Column2) return;
|
||||
var item = _imageItems [e.RowIndex];
|
||||
var isf = new ImageSetForm ();
|
||||
isf.CurrentSize = item.Size;
|
||||
isf.DefaultImages = _initList;
|
||||
isf.FinalImage = item.Image;
|
||||
isf.ShowDialog (this);
|
||||
var newimg = isf.FinalImage;
|
||||
if (newimg != null)
|
||||
{
|
||||
item.Image = newimg;
|
||||
RefreshImagePreview ();
|
||||
}
|
||||
}
|
||||
public bool IsSuccess { get; private set; } = false;
|
||||
public string Message { get; private set; } = "";
|
||||
private void buttonCancel_Click (object sender, EventArgs e)
|
||||
{
|
||||
IsSuccess = false;
|
||||
Message = "User canceled.";
|
||||
this.Close ();
|
||||
}
|
||||
private void ShortcutCreateForm_FormClosed (object sender, FormClosedEventArgs e)
|
||||
{
|
||||
_imageItems?.Clear ();
|
||||
_imageItems = null;
|
||||
_initList?.Clear ();
|
||||
_initList = null;
|
||||
}
|
||||
public static bool IsValidFileName (string fileName, bool requireExtension = true)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace (fileName)) return false;
|
||||
if (fileName.IndexOfAny (Path.GetInvalidFileNameChars ()) >= 0) return false;
|
||||
if (fileName.EndsWith (" ") || fileName.EndsWith (".")) return false;
|
||||
if (requireExtension)
|
||||
{
|
||||
if (!Path.HasExtension (fileName)) return false;
|
||||
string ext = Path.GetExtension (fileName);
|
||||
if (string.IsNullOrWhiteSpace (ext) || ext == ".") return false;
|
||||
}
|
||||
string nameWithoutExtension = Path.GetFileNameWithoutExtension (fileName);
|
||||
string [] reservedNames =
|
||||
{
|
||||
"CON", "PRN", "AUX", "NUL",
|
||||
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
|
||||
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"
|
||||
};
|
||||
if (reservedNames.Contains (nameWithoutExtension.ToUpper ())) return false;
|
||||
if (fileName.Length > 255) return false;
|
||||
return true;
|
||||
}
|
||||
private void buttonGen_Click (object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!IsValidFileName (shortcutNameInput.Text, false))
|
||||
{
|
||||
MessageBox.Show (this, "Invalid shortcut name.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
var iconfilename = "";
|
||||
var iconfilepath = "";
|
||||
if (iconSetGen.Checked)
|
||||
{
|
||||
iconfilename = genAppUserId.Replace ('!', '-') + ".ico";
|
||||
iconfilepath = Path.Combine (AppDomain.CurrentDomain.BaseDirectory, "icons", iconfilename);
|
||||
if (File.Exists (iconfilepath))
|
||||
{
|
||||
#region gen twice;
|
||||
var dlgres = MessageBox.Show (
|
||||
this,
|
||||
ResXmlStore.StringRes.Get ("MANAGER_APP_SHORTCUTCREATE_ASK_ICONEXISTS"),
|
||||
"Ask",
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Question
|
||||
);
|
||||
if (dlgres == DialogResult.Yes)
|
||||
{
|
||||
try
|
||||
{
|
||||
iconfilename = genAppUserId.Replace ('!', '-') + "-" + DateTime.Now.GetHashCode () + ".ico";
|
||||
iconfilepath = Path.Combine (AppDomain.CurrentDomain.BaseDirectory, "icons", iconfilename);
|
||||
var icons = GenerateAllIconImages ();
|
||||
SaveAsIcon (icons, iconfilepath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show (this, "Cannot create icon, we will fallback. Message: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
iconfilename = genAppUserId.Replace ('!', '-') + ".ico";
|
||||
iconfilepath = Path.Combine (AppDomain.CurrentDomain.BaseDirectory, "icons", iconfilename);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
else
|
||||
{
|
||||
var icons = GenerateAllIconImages ();
|
||||
SaveAsIcon (icons, iconfilepath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iconfilepath = iconFileInput.Text;
|
||||
}
|
||||
var shortcutname = shortcutNameInput.Text + ".lnk";
|
||||
var shortcutpath = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Desktop), shortcutname);
|
||||
ShortcutHelper.CreateShortcut (
|
||||
shortcutpath,
|
||||
Path.Combine (AppDomain.CurrentDomain.BaseDirectory, "Launch.exe"),
|
||||
genAppUserId,
|
||||
null,
|
||||
iconfilepath,
|
||||
shortcutNameInput.Text,
|
||||
genAppUserId
|
||||
);
|
||||
IsSuccess = true;
|
||||
Message = "";
|
||||
this.Close ();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsSuccess = false;
|
||||
Message = ex.Message;
|
||||
this.Close ();
|
||||
}
|
||||
}
|
||||
private void ShortcutCreateForm_FormClosing (object sender, FormClosingEventArgs e)
|
||||
{
|
||||
if (!IsSuccess && string.IsNullOrWhiteSpace (Message))
|
||||
{
|
||||
IsSuccess = false;
|
||||
Message = "User canceled.";
|
||||
}
|
||||
}
|
||||
|
||||
private void colorPickerButton_Click (object sender, EventArgs e)
|
||||
{
|
||||
using (var colorpicker = new ColorDialog ())
|
||||
{
|
||||
colorpicker.Color = GetCurrentBackgroundColor ();
|
||||
var dlgres = colorpicker.ShowDialog (this);
|
||||
if (dlgres == DialogResult.OK)
|
||||
{
|
||||
colorInputAndPreview.Text = DataUtils.UITheme.ColorToHtml (colorpicker.Color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void iconFileBrowser_Click (object sender, EventArgs e)
|
||||
{
|
||||
using (OpenFileDialog dlg = new OpenFileDialog ())
|
||||
{
|
||||
dlg.Title = "Please select the icon file:";
|
||||
dlg.Filter = "Icon File (*.ico)|*.ico";
|
||||
dlg.CheckFileExists = true;
|
||||
dlg.CheckPathExists = true;
|
||||
dlg.Multiselect = false;
|
||||
dlg.InitialDirectory = AppDomain.CurrentDomain.BaseDirectory;
|
||||
if (dlg.ShowDialog () == DialogResult.OK)
|
||||
{
|
||||
iconFileInput.Text = dlg.FileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
129
Manager/ShortcutCreateForm.resx
Normal file
129
Manager/ShortcutCreateForm.resx
Normal file
@@ -0,0 +1,129 @@
|
||||
<?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>
|
||||
<data name="label2.Text" xml:space="preserve">
|
||||
<value>A shortcut to the Windows Store app will be created on the desktop as the entry point for launching the app. Due to limitations in Windows 8.x, this will be achieved through launching the program (using parameters); please do not pin it to the Start Menu.</value>
|
||||
</data>
|
||||
<metadata name="Column1.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="Column2.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
</root>
|
||||
155
Manager/ShortcutHelper.cs
Normal file
155
Manager/ShortcutHelper.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Manager
|
||||
{
|
||||
public static class ShortcutHelper
|
||||
{
|
||||
public static void CreateShortcut (
|
||||
string shortcutPath,
|
||||
string targetPath,
|
||||
string arguments,
|
||||
string workingDirectory,
|
||||
string iconPath,
|
||||
string description,
|
||||
string appUserModelID)
|
||||
{
|
||||
IShellLinkW link = (IShellLinkW)new CShellLink ();
|
||||
|
||||
link.SetPath (targetPath);
|
||||
|
||||
if (!string.IsNullOrEmpty (arguments))
|
||||
link.SetArguments (arguments);
|
||||
|
||||
if (!string.IsNullOrEmpty (workingDirectory))
|
||||
link.SetWorkingDirectory (workingDirectory);
|
||||
|
||||
if (!string.IsNullOrEmpty (description))
|
||||
link.SetDescription (description);
|
||||
|
||||
if (!string.IsNullOrEmpty (iconPath))
|
||||
link.SetIconLocation (iconPath, 0);
|
||||
|
||||
if (!string.IsNullOrEmpty (appUserModelID))
|
||||
{
|
||||
IPropertyStore propertyStore = (IPropertyStore)link;
|
||||
|
||||
PROPERTYKEY key = PROPERTYKEY.AppUserModel_ID;
|
||||
|
||||
using (PropVariant pv = new PropVariant (appUserModelID))
|
||||
{
|
||||
propertyStore.SetValue (ref key, pv);
|
||||
propertyStore.Commit ();
|
||||
}
|
||||
}
|
||||
|
||||
IPersistFile file = (IPersistFile)link;
|
||||
file.Save (shortcutPath, false);
|
||||
|
||||
Marshal.ReleaseComObject (link);
|
||||
}
|
||||
|
||||
#region COM 定义(全部放进类内部)
|
||||
|
||||
[ComImport]
|
||||
[Guid ("00021401-0000-0000-C000-000000000046")]
|
||||
internal class CShellLink
|
||||
{
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid ("000214F9-0000-0000-C000-000000000046")]
|
||||
internal interface IShellLinkW
|
||||
{
|
||||
void GetPath ([Out, MarshalAs (UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, IntPtr pfd, int fFlags);
|
||||
void GetIDList (out IntPtr ppidl);
|
||||
void SetIDList (IntPtr pidl);
|
||||
void GetDescription ([Out, MarshalAs (UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
|
||||
void SetDescription ([MarshalAs (UnmanagedType.LPWStr)] string pszName);
|
||||
void GetWorkingDirectory ([Out, MarshalAs (UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
|
||||
void SetWorkingDirectory ([MarshalAs (UnmanagedType.LPWStr)] string pszDir);
|
||||
void GetArguments ([Out, MarshalAs (UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
|
||||
void SetArguments ([MarshalAs (UnmanagedType.LPWStr)] string pszArgs);
|
||||
void GetHotkey (out short pwHotkey);
|
||||
void SetHotkey (short wHotkey);
|
||||
void GetShowCmd (out int piShowCmd);
|
||||
void SetShowCmd (int iShowCmd);
|
||||
void GetIconLocation ([Out, MarshalAs (UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon);
|
||||
void SetIconLocation ([MarshalAs (UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
|
||||
void SetRelativePath ([MarshalAs (UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
|
||||
void Resolve (IntPtr hwnd, int fFlags);
|
||||
void SetPath ([MarshalAs (UnmanagedType.LPWStr)] string pszFile);
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid ("0000010b-0000-0000-C000-000000000046")]
|
||||
internal interface IPersistFile
|
||||
{
|
||||
void GetClassID (out Guid pClassID);
|
||||
void IsDirty ();
|
||||
void Load ([MarshalAs (UnmanagedType.LPWStr)] string pszFileName, uint dwMode);
|
||||
void Save ([MarshalAs (UnmanagedType.LPWStr)] string pszFileName, bool fRemember);
|
||||
void SaveCompleted ([MarshalAs (UnmanagedType.LPWStr)] string pszFileName);
|
||||
void GetCurFile ([MarshalAs (UnmanagedType.LPWStr)] out string ppszFileName);
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid ("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
|
||||
internal interface IPropertyStore
|
||||
{
|
||||
uint GetCount (out uint cProps);
|
||||
uint GetAt (uint iProp, out PROPERTYKEY pkey);
|
||||
uint GetValue (ref PROPERTYKEY key, out PropVariant pv);
|
||||
uint SetValue (ref PROPERTYKEY key, PropVariant pv);
|
||||
uint Commit ();
|
||||
}
|
||||
|
||||
[StructLayout (LayoutKind.Sequential, Pack = 4)]
|
||||
internal struct PROPERTYKEY
|
||||
{
|
||||
public Guid fmtid;
|
||||
public uint pid;
|
||||
|
||||
public static PROPERTYKEY AppUserModel_ID =
|
||||
new PROPERTYKEY
|
||||
{
|
||||
fmtid = new Guid ("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"),
|
||||
pid = 5
|
||||
};
|
||||
}
|
||||
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
internal sealed class PropVariant: IDisposable
|
||||
{
|
||||
short vt;
|
||||
short wReserved1;
|
||||
short wReserved2;
|
||||
short wReserved3;
|
||||
IntPtr ptr;
|
||||
int int32;
|
||||
|
||||
private const short VT_LPWSTR = 31;
|
||||
|
||||
public PropVariant (string value)
|
||||
{
|
||||
vt = VT_LPWSTR;
|
||||
ptr = Marshal.StringToCoTaskMemUni (value);
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
if (ptr != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeCoTaskMem (ptr);
|
||||
ptr = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
75
Manager/app.manifest
Normal file
75
Manager/app.manifest
Normal 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
Manager/packages.config
Normal file
4
Manager/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="13.0.4" targetFramework="net40" />
|
||||
</packages>
|
||||
62
ModernNotice/ModernNotice.csproj
Normal file
62
ModernNotice/ModernNotice.csproj
Normal file
@@ -0,0 +1,62 @@
|
||||
<?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>{C5587B6E-19C4-4484-AA97-5C20FBB07E43}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ModernNotice</RootNamespace>
|
||||
<AssemblyName>ModernNotice</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>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</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>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</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="Notice.cs" />
|
||||
<Compile Include="NoticeNative.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DataUtils\DataUtils.csproj">
|
||||
<Project>{ffd3fd52-37a8-4f43-883c-de8d996cb0e0}</Project>
|
||||
<Name>DataUtils</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.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
120
ModernNotice/Notice.cs
Normal file
120
ModernNotice/Notice.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using System.Xml;
|
||||
using System.Runtime.InteropServices;
|
||||
using HResult = DataUtils._I_HResult;
|
||||
using System;
|
||||
|
||||
namespace ModernNotice
|
||||
{
|
||||
public static class Notice
|
||||
{
|
||||
private static XmlDocument XmlStringToDom (string xmlContent)
|
||||
{
|
||||
var ret = new XmlDocument ();
|
||||
ret.LoadXml (xmlContent);
|
||||
return ret;
|
||||
}
|
||||
private static string XmlDomToString (XmlDocument xmlDom) { return xmlDom.OuterXml; }
|
||||
private static HResult BuildHResult (int hr, IntPtr err, IntPtr msg) { return new HResult (hr, Marshal.PtrToStringUni (err), Marshal.PtrToStringUni (msg)); }
|
||||
private static HResult BuildHResult (HRESULT hr, IntPtr err, IntPtr msg) { return BuildHResult (hr.Value, err, msg); }
|
||||
private static HResult BuildHResult (int hr, IntPtr msg) { return new HResult (hr, "", Marshal.PtrToStringUni (msg)); }
|
||||
private static HResult BuildHResult (HRESULT hr, IntPtr msg) { return BuildHResult (hr.Value, msg); }
|
||||
private static HResult BuildHResult (int hr) { return new HResult (hr); }
|
||||
private static HResult BuildHResult (HRESULT hr) { return BuildHResult (hr.Value); }
|
||||
public static string GetTemplateString (string templateName)
|
||||
{
|
||||
var ptr = Native.GetToastNoticeXml (templateName);
|
||||
try { var ret = Marshal.PtrToStringUni (ptr) ?? ""; return ret; }
|
||||
finally { Native.NoticeApiFreeString (ptr); }
|
||||
}
|
||||
public static XmlDocument GetTemplate (string templateName) { return XmlStringToDom (GetTemplateString (templateName)); }
|
||||
public static string GetSimpleTemplateString (string content, string imagePath)
|
||||
{
|
||||
var ptr = Native.GenerateSimpleToastNoticeXml (content, imagePath);
|
||||
try { var ret = Marshal.PtrToStringUni (ptr) ?? ""; return ret; }
|
||||
finally { Native.NoticeApiFreeString (ptr); }
|
||||
}
|
||||
public static XmlDocument GetSimpleTemplate (string content, string imagePath = null) { return XmlStringToDom (GetSimpleTemplateString (content, imagePath)); }
|
||||
public static string GetSimpleTemplateString2 (string title, string content = null, string imagePath = null)
|
||||
{
|
||||
var ptr = Native.GenerateSimpleToastNoticeXml2 (title, content, imagePath);
|
||||
try { var ret = Marshal.PtrToStringUni (ptr) ?? ""; return ret; }
|
||||
finally { Native.NoticeApiFreeString (ptr); }
|
||||
}
|
||||
public static XmlDocument GetSimpleTemplate2 (string title, string content = null, string imagePath = null) { return XmlStringToDom (GetSimpleTemplateString2 (title, content, imagePath)); }
|
||||
public static HResult Create (string appUserId, XmlDocument xml)
|
||||
{
|
||||
IntPtr dt = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
var hr = Native.CreateToastNoticeFromXmlDocument (appUserId, XmlDomToString (xml), null, IntPtr.Zero, out dt);
|
||||
return BuildHResult (hr, dt);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (dt != IntPtr.Zero) Native.NoticeApiFreeString (dt);
|
||||
}
|
||||
}
|
||||
public static HResult Create (string appUserId, string content, string imagePath = null)
|
||||
{
|
||||
var xml = GetSimpleTemplate (content, imagePath);
|
||||
return Create (appUserId, xml);
|
||||
}
|
||||
public static HResult Create (string appUserId, string title, string content, string imagePath = null)
|
||||
{
|
||||
var xml = GetSimpleTemplate2 (title, content, imagePath);
|
||||
return Create (appUserId, xml);
|
||||
}
|
||||
public static HResult Create (string appUserId, string content, IntPtr img)
|
||||
{
|
||||
IntPtr dt = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
var hr = Native.CreateToastNoticeWithIStream (appUserId, content, img, null, IntPtr.Zero, out dt);
|
||||
return BuildHResult (hr, dt);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (dt != IntPtr.Zero) Native.NoticeApiFreeString (dt);
|
||||
}
|
||||
}
|
||||
public static HResult Create (string appUserId, string title, string content, IntPtr img)
|
||||
{
|
||||
IntPtr dt = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
var hr = Native.CreateToastNoticeWithIStream2 (appUserId, title, content, img, null, IntPtr.Zero, out dt);
|
||||
return BuildHResult (hr, dt);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (dt != IntPtr.Zero) Native.NoticeApiFreeString (dt);
|
||||
}
|
||||
}
|
||||
public static HResult CreateWithImgBase64 (string appUserId, string content, string imageBase64)
|
||||
{
|
||||
IntPtr dt = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
var hr = Native.CreateToastNoticeWithImgBase64 (appUserId, content, imageBase64, null, IntPtr.Zero, out dt);
|
||||
return BuildHResult (hr, dt);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (dt != IntPtr.Zero) Native.NoticeApiFreeString (dt);
|
||||
}
|
||||
}
|
||||
public static HResult CreateWithImgBase64 (string appUserId, string title, string content, string imageBase64)
|
||||
{
|
||||
IntPtr dt = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
var hr = Native.CreateToastNotice2WithImgBase64 (appUserId, title, content, imageBase64, null, IntPtr.Zero, out dt);
|
||||
return BuildHResult (hr, dt);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (dt != IntPtr.Zero) Native.NoticeApiFreeString (dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
122
ModernNotice/NoticeNative.cs
Normal file
122
ModernNotice/NoticeNative.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace ModernNotice
|
||||
{
|
||||
// HRESULT = int
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
public struct HRESULT
|
||||
{
|
||||
public int Value;
|
||||
}
|
||||
|
||||
// Callback delegate
|
||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||
public delegate void NOTICE_ACTIVECALLBACK (IntPtr pCustom);
|
||||
|
||||
public static class Native
|
||||
{
|
||||
private const string DLL = "notice.dll"; // 改成你的 dll 名称
|
||||
|
||||
[DllImport (DLL, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr GetToastNoticeXml (string lpTemplateName);
|
||||
|
||||
[DllImport (DLL, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr GenerateSimpleToastNoticeXml (string lpText, string lpImagePath);
|
||||
|
||||
[DllImport (DLL, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr GenerateSimpleToastNoticeXml2 (string lpTitle, string lpText, string lpImagePath);
|
||||
|
||||
[DllImport (DLL, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int CreateToastNoticeFromXmlDocument (
|
||||
string lpIdName,
|
||||
string lpXmlString,
|
||||
NOTICE_ACTIVECALLBACK pfCallback,
|
||||
IntPtr pCustom,
|
||||
out IntPtr lpExceptMsg
|
||||
);
|
||||
|
||||
[DllImport (DLL, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int CreateToastNotice (
|
||||
string lpIdName,
|
||||
string lpText,
|
||||
string lpImgPath,
|
||||
NOTICE_ACTIVECALLBACK pfCallback,
|
||||
IntPtr pCustom,
|
||||
out IntPtr lpExceptMsg
|
||||
);
|
||||
|
||||
[DllImport (DLL, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int CreateToastNotice2 (
|
||||
string lpIdName,
|
||||
string lpTitle,
|
||||
string lpText,
|
||||
string lpImgPath,
|
||||
NOTICE_ACTIVECALLBACK pfCallback,
|
||||
IntPtr pCustom,
|
||||
out IntPtr lpExceptMsg
|
||||
);
|
||||
|
||||
[DllImport (DLL, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int CreateToastNoticeWithIStream2 (
|
||||
string lpIdName,
|
||||
string lpTitle,
|
||||
string lpText,
|
||||
IntPtr pIImgStream,
|
||||
NOTICE_ACTIVECALLBACK pfCallback,
|
||||
IntPtr pCustom,
|
||||
out IntPtr lpExceptMsg
|
||||
);
|
||||
|
||||
[DllImport (DLL, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int CreateToastNoticeWithIStream (
|
||||
string lpIdName,
|
||||
string lpText,
|
||||
IntPtr pIImgStream,
|
||||
NOTICE_ACTIVECALLBACK pfCallback,
|
||||
IntPtr pCustom,
|
||||
out IntPtr lpExceptMsg
|
||||
);
|
||||
|
||||
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int NoticeGetLastHResult ();
|
||||
|
||||
[DllImport (DLL, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr NoticeGetLastDetailMessage ();
|
||||
|
||||
[DllImport (DLL, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int CreateShortcutWithAppIdW (
|
||||
string pszShortcutPath,
|
||||
string pszTargetPath,
|
||||
string pszAppId,
|
||||
out IntPtr lpException
|
||||
);
|
||||
|
||||
[DllImport (DLL, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void NoticeApiFreeString (IntPtr lpstr);
|
||||
|
||||
[DllImport (DLL, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int CreateToastNoticeWithImgBase64 (
|
||||
string lpIdName,
|
||||
string lpText,
|
||||
string lpImgBase64,
|
||||
NOTICE_ACTIVECALLBACK pfCallback,
|
||||
IntPtr pCustom,
|
||||
out IntPtr lpExceptMsg
|
||||
);
|
||||
|
||||
[DllImport (DLL, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int CreateToastNotice2WithImgBase64 (
|
||||
string lpIdName,
|
||||
string lpTitle,
|
||||
string lpText,
|
||||
string lpImgBase64,
|
||||
NOTICE_ACTIVECALLBACK pfCallback,
|
||||
IntPtr pCustom,
|
||||
out IntPtr lpExceptMsg
|
||||
);
|
||||
}
|
||||
}
|
||||
36
ModernNotice/Properties/AssemblyInfo.cs
Normal file
36
ModernNotice/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("ModernNotice")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("ModernNotice")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2026")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
//将 ComVisible 设置为 false 将使此程序集中的类型
|
||||
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible (true)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("c5587b6e-19c4-4484-aa97-5c20fbb07e43")]
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
|
||||
// 方法是按如下所示使用“*”: :
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -8,6 +8,7 @@ namespace PriFileFormat
|
||||
public class ComStreamWrapper: Stream
|
||||
{
|
||||
private IStream comStream;
|
||||
private object _sync = new object ();
|
||||
public ComStreamWrapper (IStream stream)
|
||||
{
|
||||
if (stream == null)
|
||||
@@ -30,20 +31,102 @@ namespace PriFileFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
System.Runtime.InteropServices.ComTypes.STATSTG stat;
|
||||
comStream.Stat (out stat, 1); // STATFLAG_NONAME = 1
|
||||
return stat.cbSize;
|
||||
lock (_sync)
|
||||
{
|
||||
System.Runtime.InteropServices.ComTypes.STATSTG stat;
|
||||
comStream.Stat (out stat, 1); // STATFLAG_NONAME = 1
|
||||
return stat.cbSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
IntPtr posPtr = Marshal.AllocHGlobal (sizeof (long));
|
||||
try
|
||||
{
|
||||
// SEEK_CUR = 1
|
||||
comStream.Seek (0, 1, posPtr);
|
||||
return Marshal.ReadInt64 (posPtr);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal (posPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
// SEEK_SET = 0
|
||||
comStream.Seek (value, 0, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void Flush ()
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
comStream.Commit (0); // STGC_DEFAULT = 0
|
||||
}
|
||||
}
|
||||
public override int Read (byte [] buffer, int offset, int count)
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
if (offset != 0)
|
||||
throw new NotSupportedException ("Offset != 0 not supported in this wrapper.");
|
||||
|
||||
IntPtr bytesRead = Marshal.AllocHGlobal (sizeof (int));
|
||||
try
|
||||
{
|
||||
comStream.Read (buffer, count, bytesRead);
|
||||
return Marshal.ReadInt32 (bytesRead);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal (bytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void Write (byte [] buffer, int offset, int count)
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
if (offset != 0)
|
||||
throw new NotSupportedException ("Offset != 0 not supported in this wrapper.");
|
||||
|
||||
IntPtr bytesWritten = Marshal.AllocHGlobal (sizeof (int));
|
||||
try
|
||||
{
|
||||
comStream.Write (buffer, count, bytesWritten);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal (bytesWritten);
|
||||
}
|
||||
}
|
||||
}
|
||||
public override long Seek (long offset, SeekOrigin origin)
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
int originInt = 0;
|
||||
switch (origin)
|
||||
{
|
||||
case SeekOrigin.Begin: originInt = 0; break; // STREAM_SEEK_SET
|
||||
case SeekOrigin.Current: originInt = 1; break; // STREAM_SEEK_CUR
|
||||
case SeekOrigin.End: originInt = 2; break; // STREAM_SEEK_END
|
||||
}
|
||||
|
||||
IntPtr posPtr = Marshal.AllocHGlobal (sizeof (long));
|
||||
try
|
||||
{
|
||||
// SEEK_CUR = 1
|
||||
comStream.Seek (0, 1, posPtr);
|
||||
comStream.Seek (offset, originInt, posPtr);
|
||||
return Marshal.ReadInt64 (posPtr);
|
||||
}
|
||||
finally
|
||||
@@ -51,71 +134,13 @@ namespace PriFileFormat
|
||||
Marshal.FreeHGlobal (posPtr);
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
// SEEK_SET = 0
|
||||
comStream.Seek (value, 0, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
public override void Flush ()
|
||||
{
|
||||
comStream.Commit (0); // STGC_DEFAULT = 0
|
||||
}
|
||||
public override int Read (byte [] buffer, int offset, int count)
|
||||
{
|
||||
if (offset != 0)
|
||||
throw new NotSupportedException ("Offset != 0 not supported in this wrapper.");
|
||||
|
||||
IntPtr bytesRead = Marshal.AllocHGlobal (sizeof (int));
|
||||
try
|
||||
{
|
||||
comStream.Read (buffer, count, bytesRead);
|
||||
return Marshal.ReadInt32 (bytesRead);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal (bytesRead);
|
||||
}
|
||||
}
|
||||
public override void Write (byte [] buffer, int offset, int count)
|
||||
{
|
||||
if (offset != 0)
|
||||
throw new NotSupportedException ("Offset != 0 not supported in this wrapper.");
|
||||
|
||||
IntPtr bytesWritten = Marshal.AllocHGlobal (sizeof (int));
|
||||
try
|
||||
{
|
||||
comStream.Write (buffer, count, bytesWritten);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal (bytesWritten);
|
||||
}
|
||||
}
|
||||
public override long Seek (long offset, SeekOrigin origin)
|
||||
{
|
||||
int originInt = 0;
|
||||
switch (origin)
|
||||
{
|
||||
case SeekOrigin.Begin: originInt = 0; break; // STREAM_SEEK_SET
|
||||
case SeekOrigin.Current: originInt = 1; break; // STREAM_SEEK_CUR
|
||||
case SeekOrigin.End: originInt = 2; break; // STREAM_SEEK_END
|
||||
}
|
||||
|
||||
IntPtr posPtr = Marshal.AllocHGlobal (sizeof (long));
|
||||
try
|
||||
{
|
||||
comStream.Seek (offset, originInt, posPtr);
|
||||
return Marshal.ReadInt64 (posPtr);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal (posPtr);
|
||||
}
|
||||
}
|
||||
public override void SetLength (long value)
|
||||
{
|
||||
comStream.SetSize (value);
|
||||
lock (_sync)
|
||||
{
|
||||
comStream.SetSize (value);
|
||||
}
|
||||
}
|
||||
~ComStreamWrapper () { comStream = null;}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,11 @@ namespace PriFileFormat
|
||||
return priFile;
|
||||
}
|
||||
|
||||
public static PriFile Parse (System.Runtime.InteropServices.ComTypes.IStream stream)
|
||||
public static PriFile Parse (System.Runtime.InteropServices.ComTypes.IStream stream, out Stream output)
|
||||
{
|
||||
|
||||
ComStreamWrapper csw = new ComStreamWrapper (stream);
|
||||
output = csw;
|
||||
PriFile priFile = new PriFile ();
|
||||
priFile.ParseInternal (csw, true);
|
||||
return priFile;
|
||||
|
||||
22
PriFormat/ByteSpan.cs
Normal file
22
PriFormat/ByteSpan.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
public struct ByteSpan
|
||||
{
|
||||
public long Offset { get; private set; }
|
||||
public uint Length { get; private set; }
|
||||
public ByteSpan (long offset, uint length)
|
||||
{
|
||||
Offset = offset;
|
||||
Length = length;
|
||||
}
|
||||
public override string ToString ()
|
||||
{
|
||||
return "ByteSpan | Offset = " + Offset + "\t, Length = " + Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
82
PriFormat/DataItemSection.cs
Normal file
82
PriFormat/DataItemSection.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
public class DataItemSection: Section
|
||||
{
|
||||
public IList<ByteSpan> DataItems { get; private set; }
|
||||
|
||||
internal const string Identifier = "[mrm_dataitem] \0";
|
||||
|
||||
internal DataItemSection (PriFile priFile)
|
||||
: base (Identifier, priFile)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool ParseSectionContent (BinaryReader binaryReader)
|
||||
{
|
||||
long sectionPosition = 0;
|
||||
SubStream sub = binaryReader.BaseStream as SubStream;
|
||||
if (sub != null)
|
||||
sectionPosition = sub.Position;
|
||||
|
||||
binaryReader.ExpectUInt32 (0);
|
||||
|
||||
ushort numStrings = binaryReader.ReadUInt16 ();
|
||||
ushort numBlobs = binaryReader.ReadUInt16 ();
|
||||
uint totalDataLength = binaryReader.ReadUInt32 ();
|
||||
|
||||
List<ByteSpan> dataItems = new List<ByteSpan> (numStrings + numBlobs);
|
||||
|
||||
long dataStartOffset =
|
||||
binaryReader.BaseStream.Position +
|
||||
numStrings * 2 * sizeof (ushort) +
|
||||
numBlobs * 2 * sizeof (uint);
|
||||
|
||||
for (int i = 0; i < numStrings; i++)
|
||||
{
|
||||
ushort stringOffset = binaryReader.ReadUInt16 ();
|
||||
ushort stringLength = binaryReader.ReadUInt16 ();
|
||||
dataItems.Add (new ByteSpan (sectionPosition + dataStartOffset + stringOffset, stringLength));
|
||||
}
|
||||
|
||||
for (int i = 0; i < numBlobs; i++)
|
||||
{
|
||||
uint blobOffset = binaryReader.ReadUInt32 ();
|
||||
uint blobLength = binaryReader.ReadUInt32 ();
|
||||
dataItems.Add (new ByteSpan (sectionPosition + dataStartOffset + blobOffset, blobLength));
|
||||
}
|
||||
|
||||
DataItems = new ReadOnlyCollection<ByteSpan> (dataItems);
|
||||
|
||||
return true;
|
||||
}
|
||||
public override void Dispose ()
|
||||
{
|
||||
DataItems?.Clear ();
|
||||
DataItems = null;
|
||||
base.Dispose ();
|
||||
}
|
||||
}
|
||||
|
||||
public class DataItemRef
|
||||
{
|
||||
internal SectionRef<DataItemSection> dataItemSection;
|
||||
internal int itemIndex;
|
||||
public SectionRef<DataItemSection> DataItemSection => dataItemSection;
|
||||
public int ItemIndex => itemIndex;
|
||||
internal DataItemRef (SectionRef<DataItemSection> dataItemSection, int itemIndex)
|
||||
{
|
||||
this.dataItemSection = dataItemSection;
|
||||
this.itemIndex = itemIndex;
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return string.Format ("Data item {0} in section {1}", itemIndex, dataItemSection.SectionIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
819
PriFormat/Datas.cs
Normal file
819
PriFormat/Datas.cs
Normal file
@@ -0,0 +1,819 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
public struct SectionRef<T> where T : Section
|
||||
{
|
||||
internal int SectionIndex;
|
||||
internal SectionRef (int sectionIndex)
|
||||
{
|
||||
SectionIndex = sectionIndex;
|
||||
}
|
||||
public override string ToString ()
|
||||
{
|
||||
return "Section " + typeof (T).Name + " at index " + SectionIndex;
|
||||
}
|
||||
}
|
||||
public static class LocaleExt
|
||||
{
|
||||
// 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);
|
||||
// Current locale name like "en-US"
|
||||
public static 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 static int CurrentLCID
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return CultureInfo.CurrentCulture.LCID;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return CultureInfo.InvariantCulture.LCID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert LCID -> locale name (e.g. 1033 -> "en-US")
|
||||
public static 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 = LCIDToLocaleName (lcid, sb, sb.Capacity, 0);
|
||||
if (res > 0) return sb.ToString ();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// Convert locale name -> LCID
|
||||
public static 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 = 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 static 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 = 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 static 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 = 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 static 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 static 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 static 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 static 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 static 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 static 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 static 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
|
||||
}
|
||||
public static class UIExt
|
||||
{
|
||||
// GetDeviceCaps index for DPI X
|
||||
private const int LOGPIXELSX = 88;
|
||||
|
||||
[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);
|
||||
|
||||
/// <summary>
|
||||
/// Gets system DPI as percentage (100 = 96 DPI, 125 = 120 DPI, etc.)
|
||||
/// </summary>
|
||||
public static int DPI
|
||||
{
|
||||
get { return GetDPI (); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets system DPI as scale factor (1.0 = 100%, 1.25 = 125%)
|
||||
/// </summary>
|
||||
public static double DPIScale
|
||||
{
|
||||
get { return DPI * 0.01; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets system DPI percentage based on 96 DPI baseline.
|
||||
/// </summary>
|
||||
public static int GetDPI ()
|
||||
{
|
||||
IntPtr hdc = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
hdc = GetDC (IntPtr.Zero);
|
||||
if (hdc == IntPtr.Zero)
|
||||
return 100; // safe default
|
||||
|
||||
int dpiX = GetDeviceCaps (hdc, LOGPIXELSX);
|
||||
if (dpiX <= 0)
|
||||
return 100;
|
||||
|
||||
// 96 DPI == 100%
|
||||
return (int)Math.Round (dpiX * 100.0 / 96.0);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (hdc != IntPtr.Zero)
|
||||
ReleaseDC (IntPtr.Zero, hdc);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static class MSRUriHelper
|
||||
{
|
||||
public const string MsResScheme = "ms-resource:";
|
||||
public static readonly int MsResSchemeLength = MsResScheme.Length;
|
||||
/// <summary>
|
||||
/// Converts ms-resource URI or file path to path segments.
|
||||
/// </summary>
|
||||
public static int KeyToPath (string key, IList<string> output)
|
||||
{
|
||||
output.Clear ();
|
||||
if (string.IsNullOrEmpty (key))
|
||||
return 0;
|
||||
key = key.Trim ();
|
||||
try
|
||||
{
|
||||
// URI
|
||||
if (IsMsResourceUri (key))
|
||||
{
|
||||
Uri uri = new Uri (key, UriKind.RelativeOrAbsolute);
|
||||
return UriToPath (uri, output);
|
||||
}
|
||||
|
||||
// File path
|
||||
SplitPath (key, '\\', output);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// fallback: treat as file path
|
||||
SplitPath (key, '\\', output);
|
||||
}
|
||||
|
||||
return output.Count;
|
||||
}
|
||||
public static List<string> KeyToPath (string key)
|
||||
{
|
||||
List<string> ret = new List<string> ();
|
||||
KeyToPath (key, ret);
|
||||
return ret;
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts System.Uri to path segments.
|
||||
/// </summary>
|
||||
public static int UriToPath (Uri uri, IList<string> output)
|
||||
{
|
||||
output.Clear ();
|
||||
if (uri == null)
|
||||
return 0;
|
||||
try
|
||||
{
|
||||
string path = uri.AbsolutePath;
|
||||
string [] parts = path.Split (new [] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (string p in parts)
|
||||
output.Add (p);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
return output.Count;
|
||||
}
|
||||
public static int UriToPath (string uristr, IList<string> output)
|
||||
{
|
||||
var uri = new Uri (uristr);
|
||||
return UriToPath (uri, output);
|
||||
}
|
||||
public static List<string> UriToPath (Uri uri)
|
||||
{
|
||||
List<string> ret = new List<string> ();
|
||||
UriToPath (uri, ret);
|
||||
return ret;
|
||||
}
|
||||
public static List<string> UriToPath (string uristr)
|
||||
{
|
||||
var uri = new Uri (uristr);
|
||||
return UriToPath (uri);
|
||||
}
|
||||
/// <summary>
|
||||
/// Checks whether key starts with ms-resource:
|
||||
/// </summary>
|
||||
public static bool IsMsResourceUri (string key)
|
||||
{
|
||||
if (string.IsNullOrEmpty (key))
|
||||
return false;
|
||||
|
||||
return key.TrimStart ().StartsWith (MsResScheme, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
/// <summary>
|
||||
/// ms-resource://... (full uri)
|
||||
/// </summary>
|
||||
public static bool IsFullMsResourceUri (string key)
|
||||
{
|
||||
if (!IsMsResourceUri (key))
|
||||
return false;
|
||||
|
||||
return key.TrimStart ().StartsWith (
|
||||
MsResScheme + "//",
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
/// <summary>
|
||||
/// ms-resource:foo/bar (relative uri)
|
||||
/// </summary>
|
||||
public static bool IsRelativeMsResourceUri (string key)
|
||||
{
|
||||
return IsMsResourceUri (key) && !IsFullMsResourceUri (key);
|
||||
}
|
||||
private static void SplitPath (string value, char sep, IList<string> output)
|
||||
{
|
||||
string [] parts = value.Split (new [] { sep }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (string p in parts)
|
||||
output.Add (p);
|
||||
}
|
||||
}
|
||||
public enum PriPathSeparator
|
||||
{
|
||||
Backslash, // "\"
|
||||
Slash // "/"
|
||||
}
|
||||
|
||||
public sealed class PriPath: IList<string>, IEquatable<PriPath>
|
||||
{
|
||||
private readonly List<string> _segments;
|
||||
|
||||
public bool IgnoreCase { get; }
|
||||
|
||||
public PriPath (bool ignoreCase = true)
|
||||
{
|
||||
_segments = new List<string> ();
|
||||
IgnoreCase = ignoreCase;
|
||||
}
|
||||
|
||||
public PriPath (IEnumerable<string> segments, bool ignoreCase = true)
|
||||
{
|
||||
_segments = new List<string> (segments ?? Enumerable.Empty<string> ());
|
||||
IgnoreCase = ignoreCase;
|
||||
}
|
||||
public PriPath (Uri resuri, bool ignoreCase = true) :
|
||||
this (MSRUriHelper.UriToPath (resuri), ignoreCase)
|
||||
{ }
|
||||
public PriPath (string resname, bool ignoreCase = true) :
|
||||
this (MSRUriHelper.KeyToPath (resname), ignoreCase)
|
||||
{ }
|
||||
public int Count => _segments.Count;
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public string this [int index]
|
||||
{
|
||||
get { return _segments [index]; }
|
||||
set { _segments [index] = value; }
|
||||
}
|
||||
public void Add (string item) => _segments.Add (item);
|
||||
public void Clear () => _segments.Clear ();
|
||||
public bool Contains (string item) =>
|
||||
_segments.Contains (item, IgnoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal);
|
||||
|
||||
public void CopyTo (string [] array, int arrayIndex) => _segments.CopyTo (array, arrayIndex);
|
||||
public IEnumerator<string> GetEnumerator () => _segments.GetEnumerator ();
|
||||
IEnumerator IEnumerable.GetEnumerator () => _segments.GetEnumerator ();
|
||||
|
||||
public int IndexOf (string item) =>
|
||||
_segments.FindIndex (x =>
|
||||
string.Equals (x, item,
|
||||
IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal));
|
||||
|
||||
public void Insert (int index, string item) => _segments.Insert (index, item);
|
||||
public bool Remove (string item) => _segments.Remove (item);
|
||||
public void RemoveAt (int index) => _segments.RemoveAt (index);
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return ToString (PriPathSeparator.Backslash);
|
||||
}
|
||||
|
||||
public string ToString (PriPathSeparator sep)
|
||||
{
|
||||
string s = sep == PriPathSeparator.Backslash ? "\\" : "/";
|
||||
return string.Join (s, _segments);
|
||||
}
|
||||
|
||||
public string ToUriString ()
|
||||
{
|
||||
// ms-resource: URI style (relative)
|
||||
return "ms-resource:" + ToString (PriPathSeparator.Slash);
|
||||
}
|
||||
|
||||
public static PriPath FromString (string path, bool ignoreCase = true)
|
||||
{
|
||||
if (path == null) return new PriPath (ignoreCase: ignoreCase);
|
||||
|
||||
// detect URI
|
||||
if (path.StartsWith ("ms-resource:", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string rest = path.Substring ("ms-resource:".Length);
|
||||
rest = rest.TrimStart ('/');
|
||||
var segs = rest.Split (new [] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return new PriPath (segs, ignoreCase);
|
||||
}
|
||||
|
||||
// file path
|
||||
var parts = path.Split (new [] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return new PriPath (parts, ignoreCase);
|
||||
}
|
||||
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
return Equals (obj as PriPath);
|
||||
}
|
||||
|
||||
public bool Equals (PriPath other)
|
||||
{
|
||||
if (ReferenceEquals (other, null)) return false;
|
||||
if (ReferenceEquals (this, other)) return true;
|
||||
if (Count != other.Count) return false;
|
||||
|
||||
var comparer = IgnoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal;
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
if (!comparer.Equals (_segments [i], other._segments [i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
var comparer = IgnoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal;
|
||||
int hash = 17;
|
||||
foreach (var seg in _segments)
|
||||
{
|
||||
hash = hash * 31 + comparer.GetHashCode (seg?.Trim () ?? "");
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
// Operators
|
||||
public static bool operator == (PriPath a, PriPath b)
|
||||
{
|
||||
if (ReferenceEquals (a, b)) return true;
|
||||
if (ReferenceEquals (a, null) || ReferenceEquals (b, null)) return false;
|
||||
return a.Equals (b);
|
||||
}
|
||||
|
||||
public static bool operator != (PriPath a, PriPath b) => !(a == b);
|
||||
|
||||
// Concat with another path
|
||||
public static PriPath operator + (PriPath a, PriPath b)
|
||||
{
|
||||
if (a == null) return b == null ? null : new PriPath (b, ignoreCase: true);
|
||||
if (b == null) return new PriPath (a, ignoreCase: a.IgnoreCase);
|
||||
|
||||
var result = new PriPath (a, a.IgnoreCase);
|
||||
result._segments.AddRange (b._segments);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Append segment
|
||||
public static PriPath operator / (PriPath a, string segment)
|
||||
{
|
||||
if (a == null) return new PriPath (new [] { segment });
|
||||
var result = new PriPath (a, a.IgnoreCase);
|
||||
result._segments.Add (segment);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
public sealed class PriResourceIdentifier: IEquatable<PriResourceIdentifier>
|
||||
{
|
||||
public string Key { get; private set; }
|
||||
public int TaskType { get; private set; } // 0: string (ms-resource), 1: file path
|
||||
public PriPath Path { get; private set; }
|
||||
public PriResourceIdentifier ()
|
||||
{
|
||||
Key = string.Empty;
|
||||
TaskType = 1;
|
||||
Path = new PriPath ();
|
||||
}
|
||||
public PriResourceIdentifier (string key, int type = -1)
|
||||
{
|
||||
SetKey (key, type);
|
||||
}
|
||||
public PriResourceIdentifier (Uri uri, int type = -1)
|
||||
{
|
||||
if (uri == null)
|
||||
{
|
||||
SetKey (string.Empty, type);
|
||||
return;
|
||||
}
|
||||
|
||||
SetKey (uri.ToString (), type);
|
||||
}
|
||||
public void SetKey (string value, int type = -1)
|
||||
{
|
||||
Key = value ?? string.Empty;
|
||||
|
||||
if (type < 0 || type > 1)
|
||||
{
|
||||
TaskType = MSRUriHelper.IsMsResourceUri (Key) ? 0 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskType = type;
|
||||
}
|
||||
var arr = MSRUriHelper.KeyToPath (Key);
|
||||
if (TaskType == 1) arr.Insert (0, "Files");
|
||||
else if (TaskType == 0)
|
||||
{
|
||||
if (MSRUriHelper.IsRelativeMsResourceUri (Key)) arr.Insert (0, "resources");
|
||||
}
|
||||
// build path segments
|
||||
Path = new PriPath (arr, ignoreCase: true);
|
||||
}
|
||||
public bool IsUri ()
|
||||
{
|
||||
return TaskType == 0;
|
||||
}
|
||||
public bool IsFilePath ()
|
||||
{
|
||||
return TaskType == 1;
|
||||
}
|
||||
public bool IsRelativeUri ()
|
||||
{
|
||||
return MSRUriHelper.IsRelativeMsResourceUri (Key);
|
||||
}
|
||||
public bool IsFullUri ()
|
||||
{
|
||||
return MSRUriHelper.IsFullMsResourceUri (Key);
|
||||
}
|
||||
public int GetPath (IList<string> output)
|
||||
{
|
||||
if (output == null)
|
||||
throw new ArgumentNullException ("output");
|
||||
|
||||
output.Clear ();
|
||||
if (Path != null)
|
||||
{
|
||||
foreach (var seg in Path)
|
||||
output.Add (seg);
|
||||
}
|
||||
return output.Count;
|
||||
}
|
||||
public override string ToString ()
|
||||
{
|
||||
return Key;
|
||||
}
|
||||
// Equals / HashCode
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
return Equals (obj as PriResourceIdentifier);
|
||||
}
|
||||
public bool Equals (PriResourceIdentifier other)
|
||||
{
|
||||
if (ReferenceEquals (other, null))
|
||||
return false;
|
||||
if (ReferenceEquals (this, other))
|
||||
return true;
|
||||
|
||||
// Key and Path should be equivalent
|
||||
return string.Equals (Key, other.Key, StringComparison.OrdinalIgnoreCase)
|
||||
&& ((Path == null && other.Path == null) ||
|
||||
(Path != null && Path.Equals (other.Path)));
|
||||
}
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
int hash = 17;
|
||||
hash = hash * 31 + (Key ?? "").ToLowerInvariant ().GetHashCode ();
|
||||
hash = hash * 31 + (Path != null ? Path.GetHashCode () : 0);
|
||||
return hash;
|
||||
}
|
||||
public static bool operator == (PriResourceIdentifier a, PriResourceIdentifier b)
|
||||
{
|
||||
if (ReferenceEquals (a, b))
|
||||
return true;
|
||||
if (ReferenceEquals (a, null) || ReferenceEquals (b, null))
|
||||
return false;
|
||||
return a.Equals (b);
|
||||
}
|
||||
public static bool operator != (PriResourceIdentifier a, PriResourceIdentifier b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
}
|
||||
}
|
||||
243
PriFormat/DecisionInfoSection.cs
Normal file
243
PriFormat/DecisionInfoSection.cs
Normal file
@@ -0,0 +1,243 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
public class DecisionInfoSection: Section
|
||||
{
|
||||
public IList<Decision> Decisions { get; private set; }
|
||||
public IList<QualifierSet> QualifierSets { get; private set; }
|
||||
public IList<Qualifier> Qualifiers { get; private set; }
|
||||
|
||||
internal const string Identifier = "[mrm_decn_info]\0";
|
||||
|
||||
internal DecisionInfoSection (PriFile priFile)
|
||||
: base (Identifier, priFile)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool ParseSectionContent (BinaryReader binaryReader)
|
||||
{
|
||||
ushort numDistinctQualifiers = binaryReader.ReadUInt16 ();
|
||||
ushort numQualifiers = binaryReader.ReadUInt16 ();
|
||||
ushort numQualifierSets = binaryReader.ReadUInt16 ();
|
||||
ushort numDecisions = binaryReader.ReadUInt16 ();
|
||||
ushort numIndexTableEntries = binaryReader.ReadUInt16 ();
|
||||
ushort totalDataLength = binaryReader.ReadUInt16 ();
|
||||
|
||||
List<DecisionInfo> decisionInfos = new List<DecisionInfo> (numDecisions);
|
||||
for (int i = 0; i < numDecisions; i++)
|
||||
{
|
||||
ushort firstQualifierSetIndexIndex = binaryReader.ReadUInt16 ();
|
||||
ushort numQualifierSetsInDecision = binaryReader.ReadUInt16 ();
|
||||
decisionInfos.Add (new DecisionInfo (firstQualifierSetIndexIndex, numQualifierSetsInDecision));
|
||||
}
|
||||
|
||||
List<QualifierSetInfo> qualifierSetInfos = new List<QualifierSetInfo> (numQualifierSets);
|
||||
for (int i = 0; i < numQualifierSets; i++)
|
||||
{
|
||||
ushort firstQualifierIndexIndex = binaryReader.ReadUInt16 ();
|
||||
ushort numQualifiersInSet = binaryReader.ReadUInt16 ();
|
||||
qualifierSetInfos.Add (new QualifierSetInfo (firstQualifierIndexIndex, numQualifiersInSet));
|
||||
}
|
||||
|
||||
List<QualifierInfo> qualifierInfos = new List<QualifierInfo> (numQualifiers);
|
||||
for (int i = 0; i < numQualifiers; i++)
|
||||
{
|
||||
ushort index = binaryReader.ReadUInt16 ();
|
||||
ushort priority = binaryReader.ReadUInt16 ();
|
||||
ushort fallbackScore = binaryReader.ReadUInt16 ();
|
||||
binaryReader.ExpectUInt16 (0);
|
||||
qualifierInfos.Add (new QualifierInfo (index, priority, fallbackScore));
|
||||
}
|
||||
|
||||
List<DistinctQualifierInfo> distinctQualifierInfos = new List<DistinctQualifierInfo> (numDistinctQualifiers);
|
||||
for (int i = 0; i < numDistinctQualifiers; i++)
|
||||
{
|
||||
binaryReader.ReadUInt16 ();
|
||||
QualifierType qualifierType = (QualifierType)binaryReader.ReadUInt16 ();
|
||||
binaryReader.ReadUInt16 ();
|
||||
binaryReader.ReadUInt16 ();
|
||||
uint operandValueOffset = binaryReader.ReadUInt32 ();
|
||||
distinctQualifierInfos.Add (new DistinctQualifierInfo (qualifierType, operandValueOffset));
|
||||
}
|
||||
|
||||
ushort [] indexTable = new ushort [numIndexTableEntries];
|
||||
for (int i = 0; i < numIndexTableEntries; i++)
|
||||
indexTable [i] = binaryReader.ReadUInt16 ();
|
||||
|
||||
long dataStartOffset = binaryReader.BaseStream.Position;
|
||||
|
||||
List<Qualifier> qualifiers = new List<Qualifier> (numQualifiers);
|
||||
|
||||
for (int i = 0; i < numQualifiers; i++)
|
||||
{
|
||||
DistinctQualifierInfo distinctQualifierInfo = distinctQualifierInfos [qualifierInfos [i].Index];
|
||||
|
||||
binaryReader.BaseStream.Seek (dataStartOffset + distinctQualifierInfo.OperandValueOffset * 2, SeekOrigin.Begin);
|
||||
|
||||
string value = binaryReader.ReadNullTerminatedString (Encoding.Unicode);
|
||||
|
||||
qualifiers.Add (new Qualifier (
|
||||
(ushort)i,
|
||||
distinctQualifierInfo.QualifierType,
|
||||
qualifierInfos [i].Priority,
|
||||
qualifierInfos [i].FallbackScore / 1000f,
|
||||
value));
|
||||
}
|
||||
|
||||
Qualifiers = qualifiers;
|
||||
|
||||
List<QualifierSet> qualifierSets = new List<QualifierSet> (numQualifierSets);
|
||||
|
||||
for (int i = 0; i < numQualifierSets; i++)
|
||||
{
|
||||
List<Qualifier> qualifiersInSet = new List<Qualifier> (qualifierSetInfos [i].NumQualifiersInSet);
|
||||
|
||||
for (int j = 0; j < qualifierSetInfos [i].NumQualifiersInSet; j++)
|
||||
qualifiersInSet.Add (qualifiers [indexTable [qualifierSetInfos [i].FirstQualifierIndexIndex + j]]);
|
||||
|
||||
qualifierSets.Add (new QualifierSet ((ushort)i, qualifiersInSet));
|
||||
}
|
||||
|
||||
QualifierSets = qualifierSets;
|
||||
|
||||
List<Decision> decisions = new List<Decision> (numDecisions);
|
||||
|
||||
for (int i = 0; i < numDecisions; i++)
|
||||
{
|
||||
List<QualifierSet> qualifierSetsInDecision = new List<QualifierSet> (decisionInfos [i].NumQualifierSetsInDecision);
|
||||
|
||||
for (int j = 0; j < decisionInfos [i].NumQualifierSetsInDecision; j++)
|
||||
qualifierSetsInDecision.Add (qualifierSets [indexTable [decisionInfos [i].FirstQualifierSetIndexIndex + j]]);
|
||||
|
||||
decisions.Add (new Decision ((ushort)i, qualifierSetsInDecision));
|
||||
}
|
||||
|
||||
Decisions = decisions;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private struct DecisionInfo
|
||||
{
|
||||
public ushort FirstQualifierSetIndexIndex;
|
||||
public ushort NumQualifierSetsInDecision;
|
||||
|
||||
public DecisionInfo (ushort first, ushort num)
|
||||
{
|
||||
FirstQualifierSetIndexIndex = first;
|
||||
NumQualifierSetsInDecision = num;
|
||||
}
|
||||
}
|
||||
|
||||
private struct QualifierSetInfo
|
||||
{
|
||||
public ushort FirstQualifierIndexIndex;
|
||||
public ushort NumQualifiersInSet;
|
||||
|
||||
public QualifierSetInfo (ushort first, ushort num)
|
||||
{
|
||||
FirstQualifierIndexIndex = first;
|
||||
NumQualifiersInSet = num;
|
||||
}
|
||||
}
|
||||
|
||||
private struct QualifierInfo
|
||||
{
|
||||
public ushort Index;
|
||||
public ushort Priority;
|
||||
public ushort FallbackScore;
|
||||
|
||||
public QualifierInfo (ushort index, ushort priority, ushort fallbackScore)
|
||||
{
|
||||
Index = index;
|
||||
Priority = priority;
|
||||
FallbackScore = fallbackScore;
|
||||
}
|
||||
}
|
||||
|
||||
private struct DistinctQualifierInfo
|
||||
{
|
||||
public QualifierType QualifierType;
|
||||
public uint OperandValueOffset;
|
||||
|
||||
public DistinctQualifierInfo (QualifierType type, uint offset)
|
||||
{
|
||||
QualifierType = type;
|
||||
OperandValueOffset = offset;
|
||||
}
|
||||
}
|
||||
public override void Dispose ()
|
||||
{
|
||||
Decisions?.Clear ();
|
||||
Decisions = null;
|
||||
QualifierSets?.Clear ();
|
||||
QualifierSets = null;
|
||||
Qualifiers?.Clear ();
|
||||
Qualifiers = null;
|
||||
base.Dispose ();
|
||||
}
|
||||
~DecisionInfoSection () { Dispose (); }
|
||||
}
|
||||
|
||||
public enum QualifierType
|
||||
{
|
||||
Language,
|
||||
Contrast,
|
||||
Scale,
|
||||
HomeRegion,
|
||||
TargetSize,
|
||||
LayoutDirection,
|
||||
Theme,
|
||||
AlternateForm,
|
||||
DXFeatureLevel,
|
||||
Configuration,
|
||||
DeviceFamily,
|
||||
Custom
|
||||
}
|
||||
|
||||
public struct Qualifier
|
||||
{
|
||||
public ushort Index;
|
||||
public QualifierType Type;
|
||||
public ushort Priority;
|
||||
public float FallbackScore;
|
||||
public string Value;
|
||||
|
||||
public Qualifier (ushort index, QualifierType type, ushort priority, float fallbackScore, string value)
|
||||
{
|
||||
Index = index;
|
||||
Type = type;
|
||||
Priority = priority;
|
||||
FallbackScore = fallbackScore;
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public struct QualifierSet
|
||||
{
|
||||
public ushort Index;
|
||||
public IList<Qualifier> Qualifiers;
|
||||
|
||||
public QualifierSet (ushort index, IList<Qualifier> qualifiers)
|
||||
{
|
||||
Index = index;
|
||||
Qualifiers = qualifiers;
|
||||
}
|
||||
}
|
||||
|
||||
public struct Decision
|
||||
{
|
||||
public ushort Index;
|
||||
public IList<QualifierSet> QualifierSets;
|
||||
|
||||
public Decision (ushort index, IList<QualifierSet> qualifierSets)
|
||||
{
|
||||
Index = index;
|
||||
QualifierSets = qualifierSets;
|
||||
}
|
||||
}
|
||||
}
|
||||
347
PriFormat/HierarchicalSchemaSection.cs
Normal file
347
PriFormat/HierarchicalSchemaSection.cs
Normal file
@@ -0,0 +1,347 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
public class HierarchicalSchemaSection: Section
|
||||
{
|
||||
public HierarchicalSchemaVersionInfo Version { get; private set; }
|
||||
public string UniqueName { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public IList<ResourceMapScope> Scopes { get; private set; }
|
||||
public IList<ResourceMapItem> Items { get; private set; }
|
||||
|
||||
readonly bool extendedVersion;
|
||||
|
||||
internal const string Identifier1 = "[mrm_hschema] \0";
|
||||
internal const string Identifier2 = "[mrm_hschemaex] ";
|
||||
|
||||
internal HierarchicalSchemaSection (PriFile priFile, bool extendedVersion)
|
||||
: base (extendedVersion ? Identifier2 : Identifier1, priFile)
|
||||
{
|
||||
this.extendedVersion = extendedVersion;
|
||||
}
|
||||
|
||||
protected override bool ParseSectionContent (BinaryReader binaryReader)
|
||||
{
|
||||
if (binaryReader.BaseStream.Length == 0)
|
||||
{
|
||||
Version = null;
|
||||
UniqueName = null;
|
||||
Name = null;
|
||||
Scopes = new List<ResourceMapScope> ();
|
||||
Items = new List<ResourceMapItem> ();
|
||||
return true;
|
||||
}
|
||||
|
||||
binaryReader.ExpectUInt16 (1);
|
||||
ushort uniqueNameLength = binaryReader.ReadUInt16 ();
|
||||
ushort nameLength = binaryReader.ReadUInt16 ();
|
||||
binaryReader.ExpectUInt16 (0);
|
||||
|
||||
bool extendedHNames;
|
||||
if (extendedVersion)
|
||||
{
|
||||
string def = new string (binaryReader.ReadChars (16));
|
||||
switch (def)
|
||||
{
|
||||
case "[def_hnamesx] \0":
|
||||
extendedHNames = true;
|
||||
break;
|
||||
case "[def_hnames] \0":
|
||||
extendedHNames = false;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidDataException ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
extendedHNames = false;
|
||||
}
|
||||
|
||||
// hierarchical schema version info
|
||||
ushort majorVersion = binaryReader.ReadUInt16 ();
|
||||
ushort minorVersion = binaryReader.ReadUInt16 ();
|
||||
binaryReader.ExpectUInt32 (0);
|
||||
uint checksum = binaryReader.ReadUInt32 ();
|
||||
uint numScopes = binaryReader.ReadUInt32 ();
|
||||
uint numItems = binaryReader.ReadUInt32 ();
|
||||
|
||||
Version = new HierarchicalSchemaVersionInfo (majorVersion, minorVersion, checksum, numScopes, numItems);
|
||||
|
||||
UniqueName = binaryReader.ReadNullTerminatedString (Encoding.Unicode);
|
||||
Name = binaryReader.ReadNullTerminatedString (Encoding.Unicode);
|
||||
|
||||
if (UniqueName.Length != uniqueNameLength - 1 || Name.Length != nameLength - 1)
|
||||
throw new InvalidDataException ();
|
||||
|
||||
binaryReader.ExpectUInt16 (0);
|
||||
ushort maxFullPathLength = binaryReader.ReadUInt16 ();
|
||||
binaryReader.ExpectUInt16 (0);
|
||||
binaryReader.ExpectUInt32 (numScopes + numItems);
|
||||
binaryReader.ExpectUInt32 (numScopes);
|
||||
binaryReader.ExpectUInt32 (numItems);
|
||||
uint unicodeDataLength = binaryReader.ReadUInt32 ();
|
||||
binaryReader.ReadUInt32 (); // meaning unknown
|
||||
|
||||
if (extendedHNames)
|
||||
binaryReader.ReadUInt32 (); // meaning unknown
|
||||
|
||||
List<ScopeAndItemInfo> scopeAndItemInfos = new List<ScopeAndItemInfo> ((int)(numScopes + numItems));
|
||||
|
||||
for (int i = 0; i < numScopes + numItems; i++)
|
||||
{
|
||||
ushort parent = binaryReader.ReadUInt16 ();
|
||||
ushort fullPathLength = binaryReader.ReadUInt16 ();
|
||||
char uppercaseFirstChar = (char)binaryReader.ReadUInt16 ();
|
||||
byte nameLength2 = binaryReader.ReadByte ();
|
||||
byte flags = binaryReader.ReadByte ();
|
||||
uint nameOffset = binaryReader.ReadUInt16 () | (uint)((flags & 0xF) << 16);
|
||||
ushort index = binaryReader.ReadUInt16 ();
|
||||
scopeAndItemInfos.Add (new ScopeAndItemInfo (parent, fullPathLength, flags, nameOffset, index));
|
||||
}
|
||||
|
||||
List<ScopeExInfo> scopeExInfos = new List<ScopeExInfo> ((int)numScopes);
|
||||
|
||||
for (int i = 0; i < numScopes; i++)
|
||||
{
|
||||
ushort scopeIndex = binaryReader.ReadUInt16 ();
|
||||
ushort childCount = binaryReader.ReadUInt16 ();
|
||||
ushort firstChildIndex = binaryReader.ReadUInt16 ();
|
||||
binaryReader.ExpectUInt16 (0);
|
||||
scopeExInfos.Add (new ScopeExInfo (scopeIndex, childCount, firstChildIndex));
|
||||
}
|
||||
|
||||
ushort [] itemIndexPropertyToIndex = new ushort [numItems];
|
||||
for (int i = 0; i < numItems; i++)
|
||||
itemIndexPropertyToIndex [i] = binaryReader.ReadUInt16 ();
|
||||
|
||||
long unicodeDataOffset = binaryReader.BaseStream.Position;
|
||||
long asciiDataOffset = binaryReader.BaseStream.Position + unicodeDataLength * 2;
|
||||
|
||||
ResourceMapScope [] scopes = new ResourceMapScope [numScopes];
|
||||
ResourceMapItem [] items = new ResourceMapItem [numItems];
|
||||
|
||||
for (int i = 0; i < numScopes + numItems; i++)
|
||||
{
|
||||
long pos;
|
||||
|
||||
if (scopeAndItemInfos [i].NameInAscii)
|
||||
pos = asciiDataOffset + scopeAndItemInfos [i].NameOffset;
|
||||
else
|
||||
pos = unicodeDataOffset + scopeAndItemInfos [i].NameOffset * 2;
|
||||
|
||||
binaryReader.BaseStream.Seek (pos, SeekOrigin.Begin);
|
||||
|
||||
string name;
|
||||
|
||||
if (scopeAndItemInfos [i].FullPathLength != 0)
|
||||
name = binaryReader.ReadNullTerminatedString (scopeAndItemInfos [i].NameInAscii ? Encoding.ASCII : Encoding.Unicode);
|
||||
else
|
||||
name = string.Empty;
|
||||
|
||||
ushort index = scopeAndItemInfos [i].Index;
|
||||
|
||||
if (scopeAndItemInfos [i].IsScope)
|
||||
{
|
||||
if (scopes [index] != null)
|
||||
throw new InvalidDataException ();
|
||||
|
||||
scopes [index] = new ResourceMapScope (index, null, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (items [index] != null)
|
||||
throw new InvalidDataException ();
|
||||
|
||||
items [index] = new ResourceMapItem (index, null, name);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numScopes + numItems; i++)
|
||||
{
|
||||
ushort index = scopeAndItemInfos [i].Index;
|
||||
ushort parent = scopeAndItemInfos [scopeAndItemInfos [i].Parent].Index;
|
||||
|
||||
if (parent != 0xFFFF)
|
||||
{
|
||||
if (scopeAndItemInfos [i].IsScope)
|
||||
{
|
||||
if (parent != index)
|
||||
scopes [index].Parent = scopes [parent];
|
||||
}
|
||||
else
|
||||
items [index].Parent = scopes [parent];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numScopes; i++)
|
||||
{
|
||||
List<ResourceMapEntry> children = new List<ResourceMapEntry> (scopeExInfos [i].ChildCount);
|
||||
|
||||
for (int j = 0; j < scopeExInfos [i].ChildCount; j++)
|
||||
{
|
||||
ScopeAndItemInfo saiInfo = scopeAndItemInfos [scopeExInfos [i].FirstChildIndex + j];
|
||||
|
||||
if (saiInfo.IsScope)
|
||||
children.Add (scopes [saiInfo.Index]);
|
||||
else
|
||||
children.Add (items [saiInfo.Index]);
|
||||
}
|
||||
|
||||
scopes [i].Children = children;
|
||||
}
|
||||
|
||||
Scopes = scopes;
|
||||
Items = items;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private struct ScopeAndItemInfo
|
||||
{
|
||||
public ushort Parent;
|
||||
public ushort FullPathLength;
|
||||
public byte Flags;
|
||||
public uint NameOffset;
|
||||
public ushort Index;
|
||||
|
||||
public ScopeAndItemInfo (ushort parent, ushort fullPathLength, byte flags, uint nameOffset, ushort index)
|
||||
{
|
||||
Parent = parent;
|
||||
FullPathLength = fullPathLength;
|
||||
Flags = flags;
|
||||
NameOffset = nameOffset;
|
||||
Index = index;
|
||||
}
|
||||
|
||||
public bool IsScope
|
||||
{
|
||||
get { return (Flags & 0x10) != 0; }
|
||||
}
|
||||
|
||||
public bool NameInAscii
|
||||
{
|
||||
get { return (Flags & 0x20) != 0; }
|
||||
}
|
||||
}
|
||||
|
||||
private struct ScopeExInfo
|
||||
{
|
||||
public ushort ScopeIndex;
|
||||
public ushort ChildCount;
|
||||
public ushort FirstChildIndex;
|
||||
|
||||
public ScopeExInfo (ushort scopeIndex, ushort childCount, ushort firstChildIndex)
|
||||
{
|
||||
ScopeIndex = scopeIndex;
|
||||
ChildCount = childCount;
|
||||
FirstChildIndex = firstChildIndex;
|
||||
}
|
||||
}
|
||||
public override void Dispose ()
|
||||
{
|
||||
this.Version = null;
|
||||
Scopes?.Clear ();
|
||||
Scopes = null;
|
||||
Items?.Clear ();
|
||||
Items = null;
|
||||
base.Dispose ();
|
||||
}
|
||||
}
|
||||
|
||||
public class HierarchicalSchemaVersionInfo
|
||||
{
|
||||
public ushort MajorVersion { get; private set; }
|
||||
public ushort MinorVersion { get; private set; }
|
||||
public uint Checksum { get; private set; }
|
||||
public uint NumScopes { get; private set; }
|
||||
public uint NumItems { get; private set; }
|
||||
|
||||
public HierarchicalSchemaVersionInfo (ushort major, ushort minor, uint checksum, uint numScopes, uint numItems)
|
||||
{
|
||||
MajorVersion = major;
|
||||
MinorVersion = minor;
|
||||
Checksum = checksum;
|
||||
NumScopes = numScopes;
|
||||
NumItems = numItems;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class ResourceMapEntry: IDisposable
|
||||
{
|
||||
public ushort Index { get; private set; }
|
||||
public ResourceMapScope Parent { get; internal set; }
|
||||
public string Name { get; private set; }
|
||||
|
||||
internal ResourceMapEntry (ushort index, ResourceMapScope parent, string name)
|
||||
{
|
||||
Index = index;
|
||||
Parent = parent;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
string fullName;
|
||||
|
||||
public string FullName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (fullName == null)
|
||||
{
|
||||
if (Parent == null)
|
||||
fullName = Name;
|
||||
else
|
||||
fullName = Parent.FullName + "\\" + Name;
|
||||
}
|
||||
return fullName;
|
||||
}
|
||||
}
|
||||
~ResourceMapEntry ()
|
||||
{
|
||||
Dispose ();
|
||||
}
|
||||
public virtual void Dispose ()
|
||||
{
|
||||
Parent = null;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ResourceMapScope: ResourceMapEntry
|
||||
{
|
||||
internal ResourceMapScope (ushort index, ResourceMapScope parent, string name)
|
||||
: base (index, parent, name)
|
||||
{
|
||||
}
|
||||
|
||||
public IList<ResourceMapEntry> Children { get; internal set; }
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return string.Format ("Scope {0} {1} ({2} children)", Index, FullName, Children.Count);
|
||||
}
|
||||
public override void Dispose ()
|
||||
{
|
||||
Children?.Clear ();
|
||||
Children = null;
|
||||
base.Dispose ();
|
||||
}
|
||||
~ResourceMapScope () { Dispose (); }
|
||||
}
|
||||
|
||||
public sealed class ResourceMapItem: ResourceMapEntry
|
||||
{
|
||||
internal ResourceMapItem (ushort index, ResourceMapScope parent, string name)
|
||||
: base (index, parent, name)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return string.Format ("Item {0} {1}", Index, FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
63
PriFormat/Polyfill.cs
Normal file
63
PriFormat/Polyfill.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
public static class Polyfill
|
||||
{
|
||||
public static string ReadString (this BinaryReader reader, Encoding encoding, int length)
|
||||
{
|
||||
//byte [] data = reader.ReadBytes (length * encoding.GetByteCount ("a"));
|
||||
//return encoding.GetString (data, 0, data.Length);
|
||||
// ==========
|
||||
if (length <= 0) return string.Empty;
|
||||
int maxBytes = encoding.GetMaxByteCount (length);
|
||||
byte [] buffer = reader.ReadBytes (maxBytes);
|
||||
if (buffer.Length == 0) return string.Empty;
|
||||
string decoded = encoding.GetString (buffer, 0, buffer.Length);
|
||||
if (decoded.Length > length) decoded = decoded.Substring (0, length);
|
||||
return decoded;
|
||||
}
|
||||
public static string ReadNullTerminatedString (this BinaryReader reader, Encoding encoding)
|
||||
{
|
||||
MemoryStream ms = new MemoryStream ();
|
||||
while (true)
|
||||
{
|
||||
byte b1 = reader.ReadByte ();
|
||||
byte b2 = reader.ReadByte ();
|
||||
|
||||
if (b1 == 0 && b2 == 0)
|
||||
break;
|
||||
|
||||
ms.WriteByte (b1);
|
||||
ms.WriteByte (b2);
|
||||
}
|
||||
return encoding.GetString (ms.ToArray ());
|
||||
// ==========
|
||||
List<byte> bytes = new List<byte> ();
|
||||
byte b;
|
||||
while ((b = reader.ReadByte ()) != 0) bytes.Add (b);
|
||||
return encoding.GetString (bytes.ToArray ());
|
||||
}
|
||||
public static void ExpectByte (this BinaryReader reader, byte expectedValue)
|
||||
{
|
||||
if (reader.ReadByte () != expectedValue) throw new InvalidDataException ("Unexpected value read.");
|
||||
}
|
||||
public static void ExpectUInt16 (this BinaryReader reader, ushort expectedValue)
|
||||
{
|
||||
if (reader.ReadUInt16 () != expectedValue) throw new InvalidDataException ("Unexpected value read.");
|
||||
}
|
||||
public static void ExpectUInt32 (this BinaryReader reader, uint expectedValue)
|
||||
{
|
||||
if (reader.ReadUInt32 () != expectedValue) throw new InvalidDataException ("Unexpected value read.");
|
||||
}
|
||||
public static void ExpectString (this BinaryReader reader, string s)
|
||||
{
|
||||
if (new string (reader.ReadChars (s.Length)) != s) throw new InvalidDataException ("Unexpected value read.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
139
PriFormat/PriDescriptorSection.cs
Normal file
139
PriFormat/PriDescriptorSection.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
public class PriDescriptorSection: Section
|
||||
{
|
||||
public PriDescriptorFlags PriFlags { get; private set; }
|
||||
|
||||
public IList<SectionRef<HierarchicalSchemaSection>> HierarchicalSchemaSections { get; private set; }
|
||||
public IList<SectionRef<DecisionInfoSection>> DecisionInfoSections { get; private set; }
|
||||
public IList<SectionRef<ResourceMapSection>> ResourceMapSections { get; private set; }
|
||||
public IList<SectionRef<ReferencedFileSection>> ReferencedFileSections { get; private set; }
|
||||
public IList<SectionRef<DataItemSection>> DataItemSections { get; private set; }
|
||||
|
||||
public SectionRef<ResourceMapSection> PrimaryResourceMapSection { get; private set; }
|
||||
public bool HasPrimaryResourceMapSection { get; private set; }
|
||||
|
||||
internal const string Identifier = "[mrm_pridescex]\0";
|
||||
|
||||
internal PriDescriptorSection (PriFile priFile)
|
||||
: base (Identifier, priFile)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool ParseSectionContent (BinaryReader binaryReader)
|
||||
{
|
||||
PriFlags = (PriDescriptorFlags)binaryReader.ReadUInt16 ();
|
||||
ushort includedFileListSection = binaryReader.ReadUInt16 ();
|
||||
binaryReader.ExpectUInt16 (0);
|
||||
|
||||
ushort numHierarchicalSchemaSections = binaryReader.ReadUInt16 ();
|
||||
ushort numDecisionInfoSections = binaryReader.ReadUInt16 ();
|
||||
ushort numResourceMapSections = binaryReader.ReadUInt16 ();
|
||||
|
||||
ushort primaryResourceMapSection = binaryReader.ReadUInt16 ();
|
||||
if (primaryResourceMapSection != 0xFFFF)
|
||||
{
|
||||
PrimaryResourceMapSection =
|
||||
new SectionRef<ResourceMapSection> (primaryResourceMapSection);
|
||||
HasPrimaryResourceMapSection = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
HasPrimaryResourceMapSection = false;
|
||||
}
|
||||
|
||||
ushort numReferencedFileSections = binaryReader.ReadUInt16 ();
|
||||
ushort numDataItemSections = binaryReader.ReadUInt16 ();
|
||||
|
||||
binaryReader.ExpectUInt16 (0);
|
||||
|
||||
// Hierarchical schema sections
|
||||
List<SectionRef<HierarchicalSchemaSection>> hierarchicalSchemaSections =
|
||||
new List<SectionRef<HierarchicalSchemaSection>> (numHierarchicalSchemaSections);
|
||||
|
||||
for (int i = 0; i < numHierarchicalSchemaSections; i++)
|
||||
{
|
||||
hierarchicalSchemaSections.Add (
|
||||
new SectionRef<HierarchicalSchemaSection> (binaryReader.ReadUInt16 ()));
|
||||
}
|
||||
|
||||
HierarchicalSchemaSections = hierarchicalSchemaSections;
|
||||
|
||||
// Decision info sections
|
||||
List<SectionRef<DecisionInfoSection>> decisionInfoSections =
|
||||
new List<SectionRef<DecisionInfoSection>> (numDecisionInfoSections);
|
||||
|
||||
for (int i = 0; i < numDecisionInfoSections; i++)
|
||||
{
|
||||
decisionInfoSections.Add (
|
||||
new SectionRef<DecisionInfoSection> (binaryReader.ReadUInt16 ()));
|
||||
}
|
||||
|
||||
DecisionInfoSections = decisionInfoSections;
|
||||
|
||||
// Resource map sections
|
||||
List<SectionRef<ResourceMapSection>> resourceMapSections =
|
||||
new List<SectionRef<ResourceMapSection>> (numResourceMapSections);
|
||||
|
||||
for (int i = 0; i < numResourceMapSections; i++)
|
||||
{
|
||||
resourceMapSections.Add (
|
||||
new SectionRef<ResourceMapSection> (binaryReader.ReadUInt16 ()));
|
||||
}
|
||||
|
||||
ResourceMapSections = resourceMapSections;
|
||||
|
||||
// Referenced file sections
|
||||
List<SectionRef<ReferencedFileSection>> referencedFileSections =
|
||||
new List<SectionRef<ReferencedFileSection>> (numReferencedFileSections);
|
||||
|
||||
for (int i = 0; i < numReferencedFileSections; i++)
|
||||
{
|
||||
referencedFileSections.Add (
|
||||
new SectionRef<ReferencedFileSection> (binaryReader.ReadUInt16 ()));
|
||||
}
|
||||
|
||||
ReferencedFileSections = referencedFileSections;
|
||||
|
||||
// Data item sections
|
||||
List<SectionRef<DataItemSection>> dataItemSections =
|
||||
new List<SectionRef<DataItemSection>> (numDataItemSections);
|
||||
|
||||
for (int i = 0; i < numDataItemSections; i++)
|
||||
{
|
||||
dataItemSections.Add (
|
||||
new SectionRef<DataItemSection> (binaryReader.ReadUInt16 ()));
|
||||
}
|
||||
|
||||
DataItemSections = dataItemSections;
|
||||
|
||||
return true;
|
||||
}
|
||||
public override void Dispose ()
|
||||
{
|
||||
this.HierarchicalSchemaSections?.Clear ();
|
||||
this.DecisionInfoSections?.Clear ();
|
||||
this.ResourceMapSections?.Clear ();
|
||||
this.ReferencedFileSections?.Clear ();
|
||||
this.DataItemSections?.Clear ();
|
||||
HierarchicalSchemaSections = null;
|
||||
DecisionInfoSections = null;
|
||||
ResourceMapSections = null;
|
||||
ReferencedFileSections = null;
|
||||
DataItemSections = null;
|
||||
base.Dispose ();
|
||||
}
|
||||
}
|
||||
[Flags]
|
||||
public enum PriDescriptorFlags: ushort
|
||||
{
|
||||
AutoMerge = 1,
|
||||
IsDeploymentMergeable = 2,
|
||||
IsDeploymentMergeResult = 4,
|
||||
IsAutomergeMergeResult = 8
|
||||
}
|
||||
}
|
||||
144
PriFormat/PriFile.cs
Normal file
144
PriFormat/PriFile.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
public class PriFile: IDisposable
|
||||
{
|
||||
public string Version { get; private set; }
|
||||
public uint TotalFileSize { get; private set; }
|
||||
public IList<TocEntry> TableOfContents { get; private set; }
|
||||
public IList<Section> Sections { get; private set; }
|
||||
private PriFile ()
|
||||
{
|
||||
}
|
||||
public static PriFile Parse (Stream stream)
|
||||
{
|
||||
PriFile priFile = new PriFile ();
|
||||
priFile.ParseInternal (stream);
|
||||
return priFile;
|
||||
}
|
||||
|
||||
private void ParseInternal (Stream stream)
|
||||
{
|
||||
BinaryReader binaryReader = new BinaryReader (stream, Encoding.ASCII);
|
||||
long fileStartOffset = binaryReader.BaseStream.Position;
|
||||
string magic = new string (binaryReader.ReadChars (8));
|
||||
switch (magic)
|
||||
{
|
||||
case "mrm_pri0":
|
||||
case "mrm_pri1":
|
||||
case "mrm_pri2":
|
||||
case "mrm_pri3":
|
||||
case "mrm_prif":
|
||||
Version = magic;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidDataException ("Data does not start with a PRI file header.");
|
||||
}
|
||||
binaryReader.ExpectUInt16 (0);
|
||||
binaryReader.ExpectUInt16 (1);
|
||||
TotalFileSize = binaryReader.ReadUInt32 ();
|
||||
uint tocOffset = binaryReader.ReadUInt32 ();
|
||||
uint sectionStartOffset = binaryReader.ReadUInt32 ();
|
||||
ushort numSections = binaryReader.ReadUInt16 ();
|
||||
binaryReader.ExpectUInt16 (0xFFFF);
|
||||
binaryReader.ExpectUInt32 (0);
|
||||
binaryReader.BaseStream.Seek (fileStartOffset + TotalFileSize - 16, SeekOrigin.Begin);
|
||||
binaryReader.ExpectUInt32 (0xDEFFFADE);
|
||||
binaryReader.ExpectUInt32 (TotalFileSize);
|
||||
binaryReader.ExpectString (magic);
|
||||
binaryReader.BaseStream.Seek (tocOffset, SeekOrigin.Begin);
|
||||
List<TocEntry> toc = new List<TocEntry> (numSections);
|
||||
for (int i = 0; i < numSections; i++)
|
||||
{
|
||||
toc.Add (TocEntry.Parse (binaryReader));
|
||||
}
|
||||
TableOfContents = toc;
|
||||
Section [] sections = new Section [numSections];
|
||||
Sections = sections;
|
||||
bool parseSuccess;
|
||||
bool parseFailure;
|
||||
do
|
||||
{
|
||||
parseSuccess = false;
|
||||
parseFailure = false;
|
||||
for (int i = 0; i < sections.Length; i++)
|
||||
{
|
||||
if (sections [i] != null) continue;
|
||||
binaryReader.BaseStream.Seek (
|
||||
sectionStartOffset + toc [i].SectionOffset,
|
||||
SeekOrigin.Begin);
|
||||
Section section = Section.CreateForIdentifier (
|
||||
toc [i].SectionIdentifier,
|
||||
this);
|
||||
if (section.Parse (binaryReader))
|
||||
{
|
||||
sections [i] = section;
|
||||
parseSuccess = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
parseFailure = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (parseFailure && parseSuccess);
|
||||
if (parseFailure) throw new InvalidDataException ("Failed to parse all sections.");
|
||||
}
|
||||
|
||||
private PriDescriptorSection _priDescriptorSection;
|
||||
public PriDescriptorSection PriDescriptorSection
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_priDescriptorSection == null)
|
||||
{
|
||||
_priDescriptorSection =
|
||||
Sections.OfType<PriDescriptorSection> ().Single ();
|
||||
}
|
||||
return _priDescriptorSection;
|
||||
}
|
||||
}
|
||||
|
||||
public T GetSectionByRef<T> (SectionRef<T> sectionRef)
|
||||
where T : Section
|
||||
{
|
||||
return (T)Sections [sectionRef.SectionIndex];
|
||||
}
|
||||
public ResourceMapItem GetResourceMapItemByRef (
|
||||
ResourceMapItemRef resourceMapItemRef)
|
||||
{
|
||||
HierarchicalSchemaSection schema =
|
||||
GetSectionByRef (resourceMapItemRef.SchemaSection);
|
||||
|
||||
return schema.Items [resourceMapItemRef.ItemIndex];
|
||||
}
|
||||
public ByteSpan GetDataItemByRef (DataItemRef dataItemRef)
|
||||
{
|
||||
DataItemSection section =
|
||||
GetSectionByRef (dataItemRef.DataItemSection);
|
||||
|
||||
return section.DataItems [dataItemRef.ItemIndex];
|
||||
}
|
||||
public ReferencedFile GetReferencedFileByRef (
|
||||
ReferencedFileRef referencedFileRef)
|
||||
{
|
||||
SectionRef<ReferencedFileSection> refSection =
|
||||
PriDescriptorSection.ReferencedFileSections.First ();
|
||||
ReferencedFileSection section = GetSectionByRef (refSection);
|
||||
return section.ReferencedFiles [referencedFileRef.FileIndex];
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
TableOfContents?.Clear ();
|
||||
TableOfContents = null;
|
||||
//Sections?.Clear ();
|
||||
Sections = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
69
PriFormat/PriFormat.csproj
Normal file
69
PriFormat/PriFormat.csproj
Normal file
@@ -0,0 +1,69 @@
|
||||
<?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>{676E9BD2-A704-4539-9A88-E46654FC94B6}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>PriFormat</RootNamespace>
|
||||
<AssemblyName>PriFormat</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="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="ByteSpan.cs" />
|
||||
<Compile Include="DataItemSection.cs" />
|
||||
<Compile Include="Datas.cs" />
|
||||
<Compile Include="DecisionInfoSection.cs" />
|
||||
<Compile Include="HierarchicalSchemaSection.cs" />
|
||||
<Compile Include="Polyfill.cs" />
|
||||
<Compile Include="PriDescriptorSection.cs" />
|
||||
<Compile Include="PriFile.cs" />
|
||||
<Compile Include="PriReader.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ReferencedFileSection.cs" />
|
||||
<Compile Include="ResourceMapSection.cs" />
|
||||
<Compile Include="ReverseMapSection.cs" />
|
||||
<Compile Include="Section.cs" />
|
||||
<Compile Include="StreamHelper.cs" />
|
||||
<Compile Include="SubStream.cs" />
|
||||
<Compile Include="TocEntry.cs" />
|
||||
<Compile Include="UnknownSection.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>
|
||||
817
PriFormat/PriReader.cs
Normal file
817
PriFormat/PriReader.cs
Normal file
@@ -0,0 +1,817 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
namespace PriFormat
|
||||
{
|
||||
internal enum SearchState
|
||||
{
|
||||
Pending,
|
||||
Searching,
|
||||
Found,
|
||||
NotFound
|
||||
}
|
||||
internal sealed class SearchTask
|
||||
{
|
||||
public PriPath Path { get; }
|
||||
public BaseResources Result { get; set; }
|
||||
public SearchState State { get; set; }
|
||||
public SearchTask (PriPath path)
|
||||
{
|
||||
Path = path;
|
||||
State = SearchState.Pending;
|
||||
}
|
||||
}
|
||||
public sealed class PriReader: IDisposable
|
||||
{
|
||||
private PriFile _pri;
|
||||
private Stream _stream;
|
||||
private readonly bool _fromFile;
|
||||
private readonly object _lock = new object ();
|
||||
private readonly Dictionary<PriPath, SearchTask> _tasks =
|
||||
new Dictionary<PriPath, SearchTask> ();
|
||||
private Thread _searchThread;
|
||||
private bool _searchRunning;
|
||||
private bool _disposed;
|
||||
private readonly AutoResetEvent _searchWakeup = new AutoResetEvent (false);
|
||||
private PriReader (string filePath)
|
||||
{
|
||||
_fromFile = true;
|
||||
_stream = new FileStream (filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
_pri = PriFile.Parse (_stream);
|
||||
}
|
||||
private PriReader (Stream stream)
|
||||
{
|
||||
_fromFile = false;
|
||||
_stream = stream;
|
||||
_pri = PriFile.Parse (stream);
|
||||
}
|
||||
public static PriReader Open (string filePath) => new PriReader (filePath);
|
||||
public static PriReader Open (Stream stream) => new PriReader (stream);
|
||||
public void AddSearch (IEnumerable<string> resourceNames)
|
||||
{
|
||||
if (resourceNames == null) return;
|
||||
|
||||
bool added = false;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var name in resourceNames)
|
||||
{
|
||||
if (string.IsNullOrEmpty (name)) continue;
|
||||
|
||||
var path = new PriResourceIdentifier (name).Path;
|
||||
if (!_tasks.ContainsKey (path))
|
||||
{
|
||||
_tasks [path] = new SearchTask (path);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (added)
|
||||
EnsureSearchThread ();
|
||||
}
|
||||
public void AddSearch (string resname) { AddSearch (new string [] { resname }); }
|
||||
private void EnsureSearchThread ()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_disposed) return;
|
||||
if (_searchRunning) return;
|
||||
|
||||
_searchRunning = true;
|
||||
_searchThread = new Thread (SearchThreadProc);
|
||||
_searchThread.IsBackground = true;
|
||||
_searchThread.Start ();
|
||||
}
|
||||
}
|
||||
private void SearchThreadProc ()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (_disposed) return;
|
||||
|
||||
bool hasPending = false;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var task in _tasks.Values)
|
||||
{
|
||||
if (task.State == SearchState.Pending)
|
||||
{
|
||||
hasPending = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasPending)
|
||||
{
|
||||
// 没任务了,休眠等待唤醒
|
||||
_searchWakeup.WaitOne (200);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 真正跑一次搜索
|
||||
RunSearch (TimeSpan.FromSeconds (10));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_searchRunning = false;
|
||||
_searchThread = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
public BaseResources GetValue (string resourceName)
|
||||
{
|
||||
if (string.IsNullOrEmpty (resourceName)) return null;
|
||||
|
||||
var path = new PriResourceIdentifier (resourceName).Path;
|
||||
SearchTask task;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_tasks.TryGetValue (path, out task))
|
||||
{
|
||||
task = new SearchTask (path);
|
||||
_tasks [path] = task;
|
||||
EnsureSearchThread ();
|
||||
}
|
||||
}
|
||||
|
||||
// 已有结果
|
||||
if (task.State == SearchState.Found)
|
||||
return task.Result;
|
||||
|
||||
// 等待搜索完成
|
||||
while (true)
|
||||
{
|
||||
if (_disposed) return null;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (task.State == SearchState.Found)
|
||||
return task.Result;
|
||||
|
||||
if (task.State == SearchState.NotFound)
|
||||
return null;
|
||||
}
|
||||
|
||||
Thread.Sleep (50);
|
||||
}
|
||||
}
|
||||
public void RunSearch (TimeSpan timeout)
|
||||
{
|
||||
var begin = DateTime.Now;
|
||||
foreach (var rmsRef in _pri.PriDescriptorSection.ResourceMapSections)
|
||||
{
|
||||
var rms = _pri.GetSectionByRef (rmsRef);
|
||||
if (rms == null || rms.HierarchicalSchemaReference != null) continue;
|
||||
var decision = _pri.GetSectionByRef (rms.DecisionInfoSection);
|
||||
foreach (var candidateSet in rms.CandidateSets.Values)
|
||||
{
|
||||
if (DateTime.Now - begin > timeout) return;
|
||||
var item = _pri.GetResourceMapItemByRef (candidateSet.ResourceMapItem);
|
||||
var fullName = item.FullName.Trim ('\\');
|
||||
var parts = fullName.Split (new [] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var itemPath = new PriPath (fullName, true);
|
||||
SearchTask task;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_tasks.TryGetValue (itemPath, out task))
|
||||
continue;
|
||||
|
||||
if (task.State != SearchState.Pending)
|
||||
continue;
|
||||
|
||||
task.State = SearchState.Searching;
|
||||
}
|
||||
var result = ReadCandidate (candidateSet, decision);
|
||||
lock (_lock)
|
||||
{
|
||||
task.Result = result;
|
||||
task.State = result != null
|
||||
? SearchState.Found
|
||||
: SearchState.NotFound;
|
||||
}
|
||||
}
|
||||
}
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var kv in _tasks)
|
||||
{
|
||||
if (kv.Value.State == SearchState.Pending)
|
||||
{
|
||||
kv.Value.State = SearchState.NotFound;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DateTime.Now - begin > timeout) return;
|
||||
}
|
||||
private BaseResources ReadCandidate (
|
||||
CandidateSet candidateSet,
|
||||
DecisionInfoSection decisionInfo)
|
||||
{
|
||||
string value = System.String.Empty;
|
||||
int restype = 0; // 0 string, 1 file
|
||||
Dictionary<StringQualifier, string> strdict = new Dictionary<StringQualifier, string> ();
|
||||
Dictionary<FileQualifier, string> filedict = new Dictionary<FileQualifier, string> ();
|
||||
foreach (var candidate in candidateSet.Candidates)
|
||||
{
|
||||
if (candidate.SourceFile != null)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
var byteSpan = new ByteSpan ();
|
||||
if (candidate.DataItem != null) byteSpan = _pri.GetDataItemByRef (candidate.DataItem);
|
||||
else byteSpan = candidate.Data;
|
||||
_stream.Seek (byteSpan.Offset, SeekOrigin.Begin);
|
||||
var binaryReader = new BinaryReader (_stream, Encoding.Default);
|
||||
{
|
||||
var data = binaryReader.ReadBytes ((int)byteSpan.Length);
|
||||
switch (candidate.Type)
|
||||
{
|
||||
case ResourceValueType.AsciiPath:
|
||||
case ResourceValueType.AsciiString:
|
||||
value = Encoding.ASCII.GetString (data).TrimEnd ('\0'); break;
|
||||
case ResourceValueType.Utf8Path:
|
||||
case ResourceValueType.Utf8String:
|
||||
value = Encoding.UTF8.GetString (data).TrimEnd ('\0'); break;
|
||||
case ResourceValueType.Path:
|
||||
case ResourceValueType.String:
|
||||
value = Encoding.Unicode.GetString (data).TrimEnd ('\0'); break;
|
||||
case ResourceValueType.EmbeddedData:
|
||||
value = Convert.ToBase64String (data); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
var qualifierSet = decisionInfo.QualifierSets [candidate.QualifierSet];
|
||||
var qualis = new Dictionary <QualifierType, object> ();
|
||||
foreach (var quali in qualifierSet.Qualifiers)
|
||||
{
|
||||
var qtype = quali.Type;
|
||||
var qvalue = quali.Value;
|
||||
qualis.Add (qtype, qvalue);
|
||||
}
|
||||
if (qualis.ContainsKey (QualifierType.Language))
|
||||
{
|
||||
restype = 0;
|
||||
strdict.Add (new StringQualifier (qualis [QualifierType.Language].ToString ()), value);
|
||||
}
|
||||
else
|
||||
{
|
||||
restype = 1;
|
||||
if (qualis.ContainsKey (QualifierType.Scale))
|
||||
{
|
||||
var cons = qualis.ContainsKey (QualifierType.Contrast) ? qualis [QualifierType.Contrast].ToString () : "None";
|
||||
Contrast cs = Contrast.None;
|
||||
switch (cons?.Trim ()?.ToLower ())
|
||||
{
|
||||
case "white": cs = Contrast.White; break;
|
||||
case "black": cs = Contrast.Black; break;
|
||||
case "high": cs = Contrast.High; break;
|
||||
case "low": cs = Contrast.Low; break;
|
||||
case "none": cs = Contrast.None; break;
|
||||
}
|
||||
filedict.Add (new FileQualifier (Convert.ToInt32 (qualis [QualifierType.Scale]), cs), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (strdict.Count > 0 && filedict.Count > 0)
|
||||
{
|
||||
if (strdict.Count >= filedict.Count) return new StringResources (strdict, true);
|
||||
else return new FileResources (filedict, true);
|
||||
}
|
||||
else if (strdict.Count > 0) return new StringResources (strdict, true);
|
||||
else if (filedict.Count > 0) return new FileResources (filedict, true);
|
||||
return new StringResources ();
|
||||
}
|
||||
public void Dispose ()
|
||||
{
|
||||
_disposed = true;
|
||||
_searchWakeup.Set ();
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_tasks.Clear ();
|
||||
}
|
||||
|
||||
_pri?.Dispose ();
|
||||
_pri = null;
|
||||
|
||||
if (_fromFile)
|
||||
_stream?.Dispose ();
|
||||
|
||||
_stream = null;
|
||||
}
|
||||
public string Resource (string resname) { return GetValue (resname)?.SuitableValue ?? ""; }
|
||||
public Dictionary<string, string> Resources (IEnumerable<string> list)
|
||||
{
|
||||
var ret = new Dictionary<string, string> ();
|
||||
AddSearch (list);
|
||||
foreach (var item in list) ret [item] = Resource (item);
|
||||
return ret;
|
||||
}
|
||||
public string Path (string resname) => Resource (resname);
|
||||
public Dictionary<string, string> Paths (IEnumerable<string> resnames) => Resources (resnames);
|
||||
public string String (string resname) => Resource (resname);
|
||||
public Dictionary<string, string> Strings (IEnumerable<string> resnames) => Resources (resnames);
|
||||
}
|
||||
public sealed class PriReaderBundle: IDisposable
|
||||
{
|
||||
private sealed class PriInst
|
||||
{
|
||||
// 0b01 = lang, 0b10 = scale, 0b11 = both
|
||||
public readonly byte Type;
|
||||
public PriReader Reader;
|
||||
|
||||
public PriInst (byte type, Stream stream)
|
||||
{
|
||||
Type = (byte)(type & 0x03);
|
||||
Reader = PriReader.Open (stream);
|
||||
}
|
||||
|
||||
public bool IsValid
|
||||
{
|
||||
get { return (Type & 0x03) != 0 && Reader != null; }
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<PriInst> _priFiles = new List<PriInst> (3);
|
||||
private readonly Dictionary<byte, PriInst> _mapPri = new Dictionary<byte, PriInst> ();
|
||||
|
||||
// -----------------------------
|
||||
// Set
|
||||
// -----------------------------
|
||||
// type: 1 = language, 2 = scale, 3 = both
|
||||
public bool Set (byte type, Stream priStream)
|
||||
{
|
||||
byte realType = (byte)(type & 0x03);
|
||||
if (realType == 0 || priStream == null)
|
||||
return false;
|
||||
|
||||
PriInst inst;
|
||||
if (_mapPri.TryGetValue (realType, out inst))
|
||||
{
|
||||
inst.Reader.Dispose ();
|
||||
inst.Reader = PriReader.Open (priStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
inst = new PriInst (realType, priStream);
|
||||
_priFiles.Add (inst);
|
||||
_mapPri [realType] = inst;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果你外部仍然是 IStream / IntPtr,这里假定你已有封装成 Stream 的工具
|
||||
public bool Set (byte type, IntPtr priStream)
|
||||
{
|
||||
if (priStream == IntPtr.Zero)
|
||||
return false;
|
||||
|
||||
Stream stream = StreamHelper.FromIStream (priStream);
|
||||
return Set (type, stream);
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// 内部路由
|
||||
// -----------------------------
|
||||
private PriReader Get (byte type, bool mustReturn)
|
||||
{
|
||||
type = (byte)(type & 0x03);
|
||||
|
||||
PriInst inst;
|
||||
if (_mapPri.TryGetValue (type, out inst))
|
||||
return inst.Reader;
|
||||
|
||||
// fallback: both
|
||||
if (type != 0x03 && _mapPri.TryGetValue (0x03, out inst))
|
||||
return inst.Reader;
|
||||
|
||||
if (mustReturn && _priFiles.Count > 0)
|
||||
return _priFiles [0].Reader;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool IsMsResourcePrefix (string s)
|
||||
{
|
||||
try
|
||||
{
|
||||
return MSRUriHelper.IsMsResourceUri (s) || MSRUriHelper.IsFullMsResourceUri (s) || MSRUriHelper.IsRelativeMsResourceUri (s);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return MSRUriHelper.IsMsResourceUri (s);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// AddSearch
|
||||
// -----------------------------
|
||||
public void AddSearch (IEnumerable<string> arr)
|
||||
{
|
||||
if (arr == null)
|
||||
return;
|
||||
|
||||
List<string> langRes = new List<string> ();
|
||||
List<string> scaleRes = new List<string> ();
|
||||
|
||||
foreach (string it in arr)
|
||||
{
|
||||
if (string.IsNullOrEmpty (it))
|
||||
continue;
|
||||
|
||||
if (IsMsResourcePrefix (it))
|
||||
langRes.Add (it);
|
||||
else
|
||||
scaleRes.Add (it);
|
||||
}
|
||||
|
||||
PriReader langPri = Get (1, true);
|
||||
PriReader scalePri = Get (2, true);
|
||||
|
||||
if (langPri != null && langRes.Count > 0)
|
||||
langPri.AddSearch (langRes);
|
||||
|
||||
if (scalePri != null && scaleRes.Count > 0)
|
||||
scalePri.AddSearch (scaleRes);
|
||||
}
|
||||
|
||||
public void AddSearch (string resName)
|
||||
{
|
||||
if (string.IsNullOrEmpty (resName))
|
||||
return;
|
||||
|
||||
if (IsMsResourcePrefix (resName))
|
||||
{
|
||||
PriReader langPri = Get (1, true);
|
||||
if (langPri != null)
|
||||
langPri.AddSearch (resName);
|
||||
}
|
||||
else
|
||||
{
|
||||
PriReader scalePri = Get (2, true);
|
||||
if (scalePri != null)
|
||||
scalePri.AddSearch (resName);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// Resource / Path / String
|
||||
// -----------------------------
|
||||
public string Resource (string resName)
|
||||
{
|
||||
if (string.IsNullOrEmpty (resName))
|
||||
return string.Empty;
|
||||
|
||||
PriReader reader;
|
||||
|
||||
if (IsMsResourcePrefix (resName))
|
||||
reader = Get (1, true);
|
||||
else
|
||||
reader = Get (2, true);
|
||||
|
||||
if (reader == null)
|
||||
return string.Empty;
|
||||
|
||||
var res = reader.GetValue (resName);
|
||||
return res != null ? res.ToString () : string.Empty;
|
||||
}
|
||||
|
||||
public Dictionary<string, string> Resources (IEnumerable<string> resNames)
|
||||
{
|
||||
if (resNames == null)
|
||||
throw new ArgumentNullException ("resNames");
|
||||
|
||||
AddSearch (resNames);
|
||||
|
||||
Dictionary<string, string> result = new Dictionary<string, string> ();
|
||||
foreach (string name in resNames)
|
||||
result [name] = Resource (name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string Path (string resName)
|
||||
{
|
||||
return Resource (resName);
|
||||
}
|
||||
public Dictionary<string, string> Paths (IEnumerable<string> resNames)
|
||||
{
|
||||
return Resources (resNames);
|
||||
}
|
||||
public string String (string resName)
|
||||
{
|
||||
return Resource (resName);
|
||||
}
|
||||
public Dictionary<string, string> Strings (IEnumerable<string> resNames)
|
||||
{
|
||||
return Resources (resNames);
|
||||
}
|
||||
public void Dispose ()
|
||||
{
|
||||
foreach (var inst in _priFiles)
|
||||
{
|
||||
inst.Reader.Dispose ();
|
||||
}
|
||||
|
||||
_mapPri.Clear ();
|
||||
_priFiles.Clear ();
|
||||
}
|
||||
}
|
||||
public abstract class BaseQualifier { }
|
||||
public class StringQualifier: BaseQualifier, IEquatable<StringQualifier>, IEquatable<string>
|
||||
{
|
||||
public string LocaleName { get; private set; }
|
||||
public int LCID => CultureInfo.GetCultureInfo (LocaleName).LCID;
|
||||
public StringQualifier (string localeName) { LocaleName = localeName; }
|
||||
public StringQualifier (int lcid) { LocaleName = CultureInfo.GetCultureInfo (lcid).Name; }
|
||||
public override string ToString () { return $"String Qualifier: {LocaleName} ({LCID})"; }
|
||||
public bool Equals (StringQualifier other)
|
||||
{
|
||||
var ca = new CultureInfo (this.LocaleName);
|
||||
var cb = new CultureInfo (other.LocaleName);
|
||||
return string.Equals (ca.Name, cb.Name, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
public bool Equals (string other) { return this.Equals (new StringQualifier (other)); }
|
||||
public override int GetHashCode () => CultureInfo.GetCultureInfo (LocaleName).Name.GetHashCode ();
|
||||
}
|
||||
public enum Contrast
|
||||
{
|
||||
None,
|
||||
Black,
|
||||
White,
|
||||
High,
|
||||
Low
|
||||
};
|
||||
public class FileQualifier: BaseQualifier, IEquatable<FileQualifier>, IEquatable<int>, IEquatable<Tuple<int, Contrast>>
|
||||
{
|
||||
public Contrast Contrast { get; private set; } = Contrast.None;
|
||||
public int Scale { get; private set; } = 0;
|
||||
public FileQualifier (int scale, Contrast contrast = Contrast.None)
|
||||
{
|
||||
Scale = scale;
|
||||
this.Contrast = contrast;
|
||||
}
|
||||
public override string ToString () { return $"File Qualifier: Scale {Scale}, Contrast {this.Contrast}"; }
|
||||
public bool Equals (FileQualifier other)
|
||||
{
|
||||
return this.Contrast == other.Contrast && this.Scale == other.Scale;
|
||||
}
|
||||
public bool Equals (int other)
|
||||
{
|
||||
return this.Scale == other && this.Contrast == Contrast.None;
|
||||
}
|
||||
public bool Equals (Tuple<int, Contrast> other)
|
||||
{
|
||||
return this.Contrast == other.Item2 && this.Scale == other.Item1;
|
||||
}
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hash = 17;
|
||||
hash = hash * 31 + Scale.GetHashCode ();
|
||||
hash = hash * 31 + Contrast.GetHashCode ();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
public abstract class BaseResources: IDisposable
|
||||
{
|
||||
public virtual void Dispose () { }
|
||||
public virtual string SuitableValue { get; } = String.Empty;
|
||||
public virtual Dictionary<BaseQualifier, string> AllValue { get; } = new Dictionary<BaseQualifier, string> ();
|
||||
/// <summary>
|
||||
/// 表示是否寻找过,如果真则不用再次寻找。
|
||||
/// </summary>
|
||||
public bool IsFind { get; set; }
|
||||
}
|
||||
public class StringResources: BaseResources, IDictionary<StringQualifier, string>, IDictionary<string, string>
|
||||
{
|
||||
private Dictionary<StringQualifier, string> dict = new Dictionary<StringQualifier, string> ();
|
||||
public string this [string key]
|
||||
{
|
||||
get { return dict [new StringQualifier (key)]; }
|
||||
set { }
|
||||
}
|
||||
public string this [StringQualifier key]
|
||||
{
|
||||
get { return dict [key]; }
|
||||
set { }
|
||||
}
|
||||
public int Count => dict.Count;
|
||||
public bool IsReadOnly => true;
|
||||
public ICollection<StringQualifier> Keys => dict.Keys;
|
||||
public ICollection<string> Values => dict.Values;
|
||||
ICollection<string> IDictionary<string, string>.Keys => dict.Keys.Select (k => k.LocaleName).ToList ();
|
||||
public void Add (KeyValuePair<string, string> item) { }
|
||||
public void Add (KeyValuePair<StringQualifier, string> item) { }
|
||||
public void Add (string key, string value) { }
|
||||
public void Add (StringQualifier key, string value) { }
|
||||
public void Clear () { }
|
||||
public bool Contains (KeyValuePair<string, string> item)
|
||||
{
|
||||
string value;
|
||||
if (TryGetValue (item.Key, out value)) return value == item.Value;
|
||||
return false;
|
||||
}
|
||||
public bool Contains (KeyValuePair<StringQualifier, string> item) => dict.Contains (item);
|
||||
public bool ContainsKey (string key)
|
||||
{
|
||||
foreach (var kv in dict)
|
||||
{
|
||||
if (string.Equals (kv.Key.LocaleName, key, StringComparison.OrdinalIgnoreCase)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public bool ContainsKey (StringQualifier key) => dict.ContainsKey (key);
|
||||
public void CopyTo (KeyValuePair<string, string> [] array, int arrayIndex)
|
||||
{
|
||||
if (array == null) throw new ArgumentNullException ("array");
|
||||
if (arrayIndex < 0 || arrayIndex > array.Length) throw new ArgumentOutOfRangeException ("arrayIndex");
|
||||
if (array.Length - arrayIndex < dict.Count) throw new ArgumentException ("The destination array is not large enough.");
|
||||
foreach (var kv in dict)
|
||||
{
|
||||
array [arrayIndex++] = new KeyValuePair<string, string> (
|
||||
kv.Key.LocaleName, kv.Value);
|
||||
}
|
||||
}
|
||||
public void CopyTo (KeyValuePair<StringQualifier, string> [] array, int arrayIndex)
|
||||
{
|
||||
if (array == null) throw new ArgumentNullException ("array");
|
||||
if (arrayIndex < 0 || arrayIndex > array.Length) throw new ArgumentOutOfRangeException ("arrayIndex");
|
||||
if (array.Length - arrayIndex < dict.Count) throw new ArgumentException ("The destination array is not large enough.");
|
||||
foreach (var kv in dict)
|
||||
{
|
||||
array [arrayIndex++] = new KeyValuePair<StringQualifier, string> (
|
||||
kv.Key, kv.Value);
|
||||
}
|
||||
}
|
||||
public IEnumerator<KeyValuePair<StringQualifier, string>> GetEnumerator () => dict.GetEnumerator ();
|
||||
public bool Remove (KeyValuePair<StringQualifier, string> item) { return false; }
|
||||
public bool Remove (string key) => false;
|
||||
public bool Remove (KeyValuePair<string, string> item) => false;
|
||||
public bool Remove (StringQualifier key) { return false; }
|
||||
public bool TryGetValue (string key, out string value)
|
||||
{
|
||||
foreach (var kv in dict)
|
||||
{
|
||||
if (string.Equals (kv.Key.LocaleName, key, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
value = kv.Value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
public bool TryGetValue (StringQualifier key, out string value) => dict.TryGetValue (key, out value);
|
||||
IEnumerator<KeyValuePair<string, string>> IEnumerable<KeyValuePair<string, string>>.GetEnumerator ()
|
||||
{
|
||||
foreach (var kv in dict)
|
||||
{
|
||||
yield return new KeyValuePair<string, string> (kv.Key.LocaleName, kv.Value);
|
||||
}
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator () => dict.GetEnumerator ();
|
||||
internal static bool LocaleNameEqualsIgnoreRegion (string a, string b)
|
||||
{
|
||||
var ca = new CultureInfo (a);
|
||||
var cb = new CultureInfo (b);
|
||||
return string.Equals (ca.TwoLetterISOLanguageName, cb.TwoLetterISOLanguageName, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
public static string GetCoincidentValue (Dictionary<StringQualifier, string> d, string localeName)
|
||||
{
|
||||
if (d == null) return null;
|
||||
foreach (var kv in d)
|
||||
{
|
||||
if (kv.Key.LocaleName?.Trim ()?.ToLower () == localeName?.Trim ()?.ToLower ()) return kv.Value;
|
||||
}
|
||||
var targetLang = new StringQualifier (localeName);
|
||||
foreach (var kv in d)
|
||||
{
|
||||
if (kv.Key.LCID == targetLang.LCID) return kv.Value;
|
||||
}
|
||||
foreach (var kv in d)
|
||||
{
|
||||
if (LocaleNameEqualsIgnoreRegion (kv.Key.LocaleName, localeName)) return kv.Value;
|
||||
}
|
||||
return String.Empty;
|
||||
}
|
||||
public static string GetSuitableValue (Dictionary<StringQualifier, string> d)
|
||||
{
|
||||
var ret = GetCoincidentValue (d, LocaleExt.GetComputerLocaleCode ());
|
||||
if (String.IsNullOrEmpty (ret)) ret = GetCoincidentValue (d, "en-us");
|
||||
if (String.IsNullOrEmpty (ret) && d.Count > 0) ret = d.ElementAt (0).Value;
|
||||
return ret;
|
||||
}
|
||||
public override string SuitableValue => GetSuitableValue (dict);
|
||||
public override Dictionary<BaseQualifier, string> AllValue => dict.ToDictionary (kv => (BaseQualifier)kv.Key, kv => kv.Value);
|
||||
public override void Dispose ()
|
||||
{
|
||||
dict.Clear ();
|
||||
dict = null;
|
||||
base.Dispose ();
|
||||
}
|
||||
~StringResources () { Dispose (); }
|
||||
public StringResources (Dictionary<StringQualifier, string> _dict, bool isfind = true)
|
||||
{
|
||||
dict = _dict;
|
||||
IsFind = isfind;
|
||||
}
|
||||
public StringResources (Dictionary<string, string> _dict, bool isfind = true)
|
||||
{
|
||||
dict = _dict.ToDictionary (kv => new StringQualifier (kv.Key), kv => kv.Value);
|
||||
IsFind = isfind;
|
||||
}
|
||||
public StringResources () { IsFind = false; }
|
||||
}
|
||||
public class FileResources: BaseResources, IDictionary<FileQualifier, string>
|
||||
{
|
||||
private Dictionary<FileQualifier, string> dict = new Dictionary<FileQualifier, string> ();
|
||||
public string this [FileQualifier key]
|
||||
{
|
||||
get { return dict [key]; }
|
||||
set { }
|
||||
}
|
||||
public int Count => dict.Count;
|
||||
public bool IsReadOnly => false;
|
||||
public ICollection<FileQualifier> Keys => dict.Keys;
|
||||
public ICollection<string> Values => dict.Values;
|
||||
public void Add (KeyValuePair<FileQualifier, string> item) { }
|
||||
public void Add (FileQualifier key, string value) { }
|
||||
public void Clear () { }
|
||||
public bool Contains (KeyValuePair<FileQualifier, string> item) => dict.Contains (item);
|
||||
public bool ContainsKey (FileQualifier key) => dict.ContainsKey (key);
|
||||
public void CopyTo (KeyValuePair<FileQualifier, string> [] array, int arrayIndex) { }
|
||||
public IEnumerator<KeyValuePair<FileQualifier, string>> GetEnumerator () => dict.GetEnumerator ();
|
||||
public bool Remove (KeyValuePair<FileQualifier, string> item) => false;
|
||||
public bool Remove (FileQualifier key) => false;
|
||||
public bool TryGetValue (FileQualifier key, out string value) => dict.TryGetValue (key, out value);
|
||||
IEnumerator IEnumerable.GetEnumerator () => dict.GetEnumerator ();
|
||||
public static string GetCoincidentValue (Dictionary<FileQualifier, string> d, int scale, Contrast contrast = Contrast.None)
|
||||
{
|
||||
var td = d.OrderBy (k => k.Key.Contrast).ThenBy (k => k.Key.Scale);
|
||||
foreach (var kv in td)
|
||||
{
|
||||
if (kv.Key.Contrast == contrast)
|
||||
{
|
||||
if (kv.Key.Scale >= scale) return kv.Value;
|
||||
}
|
||||
}
|
||||
foreach (var kv in td)
|
||||
{
|
||||
if (kv.Key.Contrast == Contrast.None)
|
||||
if (kv.Key.Scale >= scale) return kv.Value;
|
||||
}
|
||||
foreach (var kv in td)
|
||||
{
|
||||
if (kv.Key.Contrast == Contrast.Black)
|
||||
if (kv.Key.Scale >= scale) return kv.Value;
|
||||
}
|
||||
foreach (var kv in td)
|
||||
{
|
||||
if (kv.Key.Scale >= scale) return kv.Value;
|
||||
}
|
||||
if (d.Count > 0) return d.ElementAt (0).Value;
|
||||
return String.Empty;
|
||||
}
|
||||
public static string GetSuitableValue (Dictionary<FileQualifier, string> d, Contrast contrast = Contrast.None) => GetCoincidentValue (d, UIExt.DPI, contrast);
|
||||
public override string SuitableValue => GetSuitableValue (dict);
|
||||
public override Dictionary<BaseQualifier, string> AllValue => dict.ToDictionary (kv => (BaseQualifier)kv.Key, kv => kv.Value);
|
||||
public override void Dispose ()
|
||||
{
|
||||
dict.Clear ();
|
||||
dict = null;
|
||||
base.Dispose ();
|
||||
}
|
||||
~FileResources () { Dispose (); }
|
||||
public FileResources (Dictionary<FileQualifier, string> _dict, bool isfind = true)
|
||||
{
|
||||
dict = _dict;
|
||||
IsFind = isfind;
|
||||
}
|
||||
public FileResources (Dictionary<Tuple<int, Contrast>, string> _dict, bool isfind = true)
|
||||
{
|
||||
dict = _dict.ToDictionary (kv => new FileQualifier (kv.Key.Item1, kv.Key.Item2), kv => kv.Value);
|
||||
IsFind = isfind;
|
||||
}
|
||||
public FileResources () { IsFind = false; }
|
||||
}
|
||||
}
|
||||
36
PriFormat/Properties/AssemblyInfo.cs
Normal file
36
PriFormat/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("PriFormat")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("PriFormat")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2026")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
//将 ComVisible 设置为 false 将使此程序集中的类型
|
||||
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible (true)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("676e9bd2-a704-4539-9a88-e46654fc94b6")]
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
|
||||
// 方法是按如下所示使用“*”: :
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
248
PriFormat/ReferencedFileSection.cs
Normal file
248
PriFormat/ReferencedFileSection.cs
Normal file
@@ -0,0 +1,248 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
public class ReferencedFileSection: Section
|
||||
{
|
||||
public IList<ReferencedFile> ReferencedFiles { get; private set; }
|
||||
|
||||
internal const string Identifier = "[def_file_list]\0";
|
||||
|
||||
internal ReferencedFileSection (PriFile priFile)
|
||||
: base (Identifier, priFile)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool ParseSectionContent (BinaryReader binaryReader)
|
||||
{
|
||||
ushort numRoots = binaryReader.ReadUInt16 ();
|
||||
ushort numFolders = binaryReader.ReadUInt16 ();
|
||||
ushort numFiles = binaryReader.ReadUInt16 ();
|
||||
binaryReader.ExpectUInt16 (0);
|
||||
uint totalDataLength = binaryReader.ReadUInt32 ();
|
||||
|
||||
List<FolderInfo> folderInfos = new List<FolderInfo> (numFolders);
|
||||
|
||||
for (int i = 0; i < numFolders; i++)
|
||||
{
|
||||
binaryReader.ExpectUInt16 (0);
|
||||
ushort parentFolder = binaryReader.ReadUInt16 ();
|
||||
ushort numFoldersInFolder = binaryReader.ReadUInt16 ();
|
||||
ushort firstFolderInFolder = binaryReader.ReadUInt16 ();
|
||||
ushort numFilesInFolder = binaryReader.ReadUInt16 ();
|
||||
ushort firstFileInFolder = binaryReader.ReadUInt16 ();
|
||||
ushort folderNameLength = binaryReader.ReadUInt16 ();
|
||||
ushort fullPathLength = binaryReader.ReadUInt16 ();
|
||||
uint folderNameOffset = binaryReader.ReadUInt32 ();
|
||||
|
||||
folderInfos.Add (new FolderInfo (
|
||||
parentFolder,
|
||||
numFoldersInFolder,
|
||||
firstFolderInFolder,
|
||||
numFilesInFolder,
|
||||
firstFileInFolder,
|
||||
folderNameLength,
|
||||
fullPathLength,
|
||||
folderNameOffset));
|
||||
}
|
||||
|
||||
List<FileInfo> fileInfos = new List<FileInfo> (numFiles);
|
||||
|
||||
for (int i = 0; i < numFiles; i++)
|
||||
{
|
||||
binaryReader.ReadUInt16 ();
|
||||
ushort parentFolder = binaryReader.ReadUInt16 ();
|
||||
ushort fullPathLength = binaryReader.ReadUInt16 ();
|
||||
ushort fileNameLength = binaryReader.ReadUInt16 ();
|
||||
uint fileNameOffset = binaryReader.ReadUInt32 ();
|
||||
|
||||
fileInfos.Add (new FileInfo (parentFolder, fullPathLength, fileNameLength, fileNameOffset));
|
||||
}
|
||||
|
||||
long dataStartPosition = binaryReader.BaseStream.Position;
|
||||
|
||||
List<ReferencedFolder> referencedFolders = new List<ReferencedFolder> (numFolders);
|
||||
|
||||
for (int i = 0; i < numFolders; i++)
|
||||
{
|
||||
binaryReader.BaseStream.Seek (dataStartPosition + folderInfos [i].FolderNameOffset * 2, SeekOrigin.Begin);
|
||||
|
||||
string name = binaryReader.ReadString (Encoding.Unicode, folderInfos [i].FolderNameLength);
|
||||
|
||||
referencedFolders.Add (new ReferencedFolder (null, name));
|
||||
}
|
||||
|
||||
for (int i = 0; i < numFolders; i++)
|
||||
{
|
||||
if (folderInfos [i].ParentFolder != 0xFFFF)
|
||||
referencedFolders [i].Parent = referencedFolders [folderInfos [i].ParentFolder];
|
||||
}
|
||||
|
||||
List<ReferencedFile> referencedFiles = new List<ReferencedFile> (numFiles);
|
||||
|
||||
for (int i = 0; i < numFiles; i++)
|
||||
{
|
||||
binaryReader.BaseStream.Seek (dataStartPosition + fileInfos [i].FileNameOffset * 2, SeekOrigin.Begin);
|
||||
|
||||
string name = binaryReader.ReadString (Encoding.Unicode, fileInfos [i].FileNameLength);
|
||||
|
||||
ReferencedFolder parentFolder;
|
||||
|
||||
if (fileInfos [i].ParentFolder != 0xFFFF)
|
||||
parentFolder = referencedFolders [fileInfos [i].ParentFolder];
|
||||
else
|
||||
parentFolder = null;
|
||||
|
||||
referencedFiles.Add (new ReferencedFile (parentFolder, name));
|
||||
}
|
||||
|
||||
for (int i = 0; i < numFolders; i++)
|
||||
{
|
||||
List<ReferencedEntry> children = new List<ReferencedEntry> (
|
||||
folderInfos [i].NumFoldersInFolder + folderInfos [i].NumFilesInFolder);
|
||||
|
||||
for (int j = 0; j < folderInfos [i].NumFoldersInFolder; j++)
|
||||
children.Add (referencedFolders [folderInfos [i].FirstFolderInFolder + j]);
|
||||
|
||||
for (int j = 0; j < folderInfos [i].NumFilesInFolder; j++)
|
||||
children.Add (referencedFiles [folderInfos [i].FirstFileInFolder + j]);
|
||||
|
||||
referencedFolders [i].Children = children;
|
||||
}
|
||||
|
||||
ReferencedFiles = new ReadOnlyCollection<ReferencedFile> (referencedFiles);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private struct FolderInfo
|
||||
{
|
||||
public ushort ParentFolder;
|
||||
public ushort NumFoldersInFolder;
|
||||
public ushort FirstFolderInFolder;
|
||||
public ushort NumFilesInFolder;
|
||||
public ushort FirstFileInFolder;
|
||||
public ushort FolderNameLength;
|
||||
public ushort FullPathLength;
|
||||
public uint FolderNameOffset;
|
||||
|
||||
public FolderInfo (
|
||||
ushort parentFolder,
|
||||
ushort numFoldersInFolder,
|
||||
ushort firstFolderInFolder,
|
||||
ushort numFilesInFolder,
|
||||
ushort firstFileInFolder,
|
||||
ushort folderNameLength,
|
||||
ushort fullPathLength,
|
||||
uint folderNameOffset)
|
||||
{
|
||||
ParentFolder = parentFolder;
|
||||
NumFoldersInFolder = numFoldersInFolder;
|
||||
FirstFolderInFolder = firstFolderInFolder;
|
||||
NumFilesInFolder = numFilesInFolder;
|
||||
FirstFileInFolder = firstFileInFolder;
|
||||
FolderNameLength = folderNameLength;
|
||||
FullPathLength = fullPathLength;
|
||||
FolderNameOffset = folderNameOffset;
|
||||
}
|
||||
}
|
||||
|
||||
private struct FileInfo
|
||||
{
|
||||
public ushort ParentFolder;
|
||||
public ushort FullPathLength;
|
||||
public ushort FileNameLength;
|
||||
public uint FileNameOffset;
|
||||
|
||||
public FileInfo (ushort parentFolder, ushort fullPathLength, ushort fileNameLength, uint fileNameOffset)
|
||||
{
|
||||
ParentFolder = parentFolder;
|
||||
FullPathLength = fullPathLength;
|
||||
FileNameLength = fileNameLength;
|
||||
FileNameOffset = fileNameOffset;
|
||||
}
|
||||
}
|
||||
public override void Dispose ()
|
||||
{
|
||||
ReferencedFiles?.Clear ();
|
||||
ReferencedFiles = null;
|
||||
base.Dispose ();
|
||||
}
|
||||
~ReferencedFileSection () { Dispose (); }
|
||||
}
|
||||
|
||||
public abstract class ReferencedEntry: IDisposable
|
||||
{
|
||||
public ReferencedFolder Parent { get; internal set; }
|
||||
public string Name { get; private set; }
|
||||
|
||||
internal ReferencedEntry (ReferencedFolder parent, string name)
|
||||
{
|
||||
Parent = parent;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
private string fullName;
|
||||
|
||||
public string FullName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (fullName == null)
|
||||
{
|
||||
if (Parent == null)
|
||||
fullName = Name;
|
||||
else
|
||||
fullName = Parent.FullName + "\\" + Name;
|
||||
}
|
||||
|
||||
return fullName;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Dispose ()
|
||||
{
|
||||
Parent = null;
|
||||
}
|
||||
~ReferencedEntry () { Dispose (); }
|
||||
}
|
||||
|
||||
public sealed class ReferencedFolder: ReferencedEntry
|
||||
{
|
||||
internal ReferencedFolder (ReferencedFolder parent, string name)
|
||||
: base (parent, name)
|
||||
{
|
||||
}
|
||||
|
||||
public IList<ReferencedEntry> Children { get; internal set; }
|
||||
public override void Dispose ()
|
||||
{
|
||||
Children?.Clear ();
|
||||
Children = null;
|
||||
base.Dispose ();
|
||||
}
|
||||
~ReferencedFolder () { Dispose (); }
|
||||
}
|
||||
|
||||
public sealed class ReferencedFile: ReferencedEntry
|
||||
{
|
||||
internal ReferencedFile (ReferencedFolder parent, string name)
|
||||
: base (parent, name)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class ReferencedFileRef
|
||||
{
|
||||
internal int fileIndex;
|
||||
public int FileIndex => fileIndex;
|
||||
internal ReferencedFileRef (int fileIndex)
|
||||
{
|
||||
this.fileIndex = fileIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
414
PriFormat/ResourceMapSection.cs
Normal file
414
PriFormat/ResourceMapSection.cs
Normal file
@@ -0,0 +1,414 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
public class ResourceMapSection: Section
|
||||
{
|
||||
public HierarchicalSchemaReference HierarchicalSchemaReference { get; private set; }
|
||||
public SectionRef<HierarchicalSchemaSection> SchemaSection { get; private set; }
|
||||
public SectionRef<DecisionInfoSection> DecisionInfoSection { get; private set; }
|
||||
public IDictionary<ushort, CandidateSet> CandidateSets { get; private set; }
|
||||
|
||||
readonly bool version2;
|
||||
|
||||
internal const string Identifier1 = "[mrm_res_map__]\0";
|
||||
internal const string Identifier2 = "[mrm_res_map2_]\0";
|
||||
|
||||
internal ResourceMapSection (PriFile priFile, bool version2)
|
||||
: base (version2 ? Identifier2 : Identifier1, priFile)
|
||||
{
|
||||
this.version2 = version2;
|
||||
}
|
||||
|
||||
protected override bool ParseSectionContent (BinaryReader binaryReader)
|
||||
{
|
||||
long sectionPosition = (binaryReader.BaseStream as SubStream) != null ?
|
||||
((SubStream)binaryReader.BaseStream).Position : 0;
|
||||
|
||||
ushort environmentReferencesLength = binaryReader.ReadUInt16 ();
|
||||
ushort numEnvironmentReferences = binaryReader.ReadUInt16 ();
|
||||
|
||||
if (!version2)
|
||||
{
|
||||
if (environmentReferencesLength == 0 || numEnvironmentReferences == 0)
|
||||
throw new InvalidDataException ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (environmentReferencesLength != 0 || numEnvironmentReferences != 0)
|
||||
throw new InvalidDataException ();
|
||||
}
|
||||
|
||||
SchemaSection = new SectionRef<HierarchicalSchemaSection> (binaryReader.ReadUInt16 ());
|
||||
ushort hierarchicalSchemaReferenceLength = binaryReader.ReadUInt16 ();
|
||||
DecisionInfoSection = new SectionRef<DecisionInfoSection> (binaryReader.ReadUInt16 ());
|
||||
ushort resourceValueTypeTableSize = binaryReader.ReadUInt16 ();
|
||||
ushort ItemToItemInfoGroupCount = binaryReader.ReadUInt16 ();
|
||||
ushort itemInfoGroupCount = binaryReader.ReadUInt16 ();
|
||||
uint itemInfoCount = binaryReader.ReadUInt32 ();
|
||||
uint numCandidates = binaryReader.ReadUInt32 ();
|
||||
uint dataLength = binaryReader.ReadUInt32 ();
|
||||
uint largeTableLength = binaryReader.ReadUInt32 ();
|
||||
|
||||
if (PriFile.GetSectionByRef (DecisionInfoSection) == null)
|
||||
return false;
|
||||
|
||||
byte [] environmentReferencesData = binaryReader.ReadBytes (environmentReferencesLength);
|
||||
byte [] schemaReferenceData = binaryReader.ReadBytes (hierarchicalSchemaReferenceLength);
|
||||
|
||||
if (schemaReferenceData.Length != 0)
|
||||
{
|
||||
using (BinaryReader r = new BinaryReader (new MemoryStream (schemaReferenceData, false)))
|
||||
{
|
||||
ushort majorVersion = r.ReadUInt16 ();
|
||||
ushort minorVersion = r.ReadUInt16 ();
|
||||
r.ExpectUInt32 (0);
|
||||
uint checksum = r.ReadUInt32 ();
|
||||
uint numScopes = r.ReadUInt32 ();
|
||||
uint numItems = r.ReadUInt32 ();
|
||||
|
||||
HierarchicalSchemaVersionInfo versionInfo = new HierarchicalSchemaVersionInfo (
|
||||
majorVersion, minorVersion, checksum, numScopes, numItems);
|
||||
|
||||
ushort stringDataLength = r.ReadUInt16 ();
|
||||
r.ExpectUInt16 (0);
|
||||
uint unknown1 = r.ReadUInt32 ();
|
||||
uint unknown2 = r.ReadUInt32 ();
|
||||
string uniqueName = r.ReadNullTerminatedString (Encoding.Unicode);
|
||||
|
||||
if (uniqueName.Length != stringDataLength - 1)
|
||||
throw new InvalidDataException ();
|
||||
|
||||
HierarchicalSchemaReference = new HierarchicalSchemaReference (versionInfo, unknown1, unknown2, uniqueName);
|
||||
}
|
||||
}
|
||||
|
||||
List<ResourceValueType> resourceValueTypeTable = new List<ResourceValueType> (resourceValueTypeTableSize);
|
||||
for (int i = 0; i < resourceValueTypeTableSize; i++)
|
||||
{
|
||||
binaryReader.ExpectUInt32 (4);
|
||||
ResourceValueType resourceValueType = (ResourceValueType)binaryReader.ReadUInt32 ();
|
||||
resourceValueTypeTable.Add (resourceValueType);
|
||||
}
|
||||
|
||||
List<ItemToItemInfoGroup> itemToItemInfoGroups = new List<ItemToItemInfoGroup> (ItemToItemInfoGroupCount);
|
||||
for (int i = 0; i < ItemToItemInfoGroupCount; i++)
|
||||
{
|
||||
ushort firstItem = binaryReader.ReadUInt16 ();
|
||||
ushort itemInfoGroup = binaryReader.ReadUInt16 ();
|
||||
itemToItemInfoGroups.Add (new ItemToItemInfoGroup (firstItem, itemInfoGroup));
|
||||
}
|
||||
|
||||
List<ItemInfoGroup> itemInfoGroups = new List<ItemInfoGroup> (itemInfoGroupCount);
|
||||
for (int i = 0; i < itemInfoGroupCount; i++)
|
||||
{
|
||||
ushort groupSize = binaryReader.ReadUInt16 ();
|
||||
ushort firstItemInfo = binaryReader.ReadUInt16 ();
|
||||
itemInfoGroups.Add (new ItemInfoGroup (groupSize, firstItemInfo));
|
||||
}
|
||||
|
||||
List<ItemInfo> itemInfos = new List<ItemInfo> ((int)itemInfoCount);
|
||||
for (int i = 0; i < itemInfoCount; i++)
|
||||
{
|
||||
ushort decision = binaryReader.ReadUInt16 ();
|
||||
ushort firstCandidate = binaryReader.ReadUInt16 ();
|
||||
itemInfos.Add (new ItemInfo (decision, firstCandidate));
|
||||
}
|
||||
|
||||
byte [] largeTable = binaryReader.ReadBytes ((int)largeTableLength);
|
||||
|
||||
if (largeTable.Length != 0)
|
||||
{
|
||||
using (BinaryReader r = new BinaryReader (new MemoryStream (largeTable, false)))
|
||||
{
|
||||
uint ItemToItemInfoGroupCountLarge = r.ReadUInt32 ();
|
||||
uint itemInfoGroupCountLarge = r.ReadUInt32 ();
|
||||
uint itemInfoCountLarge = r.ReadUInt32 ();
|
||||
|
||||
for (int i = 0; i < ItemToItemInfoGroupCountLarge; i++)
|
||||
{
|
||||
uint firstItem = r.ReadUInt32 ();
|
||||
uint itemInfoGroup = r.ReadUInt32 ();
|
||||
itemToItemInfoGroups.Add (new ItemToItemInfoGroup (firstItem, itemInfoGroup));
|
||||
}
|
||||
|
||||
for (int i = 0; i < itemInfoGroupCountLarge; i++)
|
||||
{
|
||||
uint groupSize = r.ReadUInt32 ();
|
||||
uint firstItemInfo = r.ReadUInt32 ();
|
||||
itemInfoGroups.Add (new ItemInfoGroup (groupSize, firstItemInfo));
|
||||
}
|
||||
|
||||
for (int i = 0; i < itemInfoCountLarge; i++)
|
||||
{
|
||||
uint decision = r.ReadUInt32 ();
|
||||
uint firstCandidate = r.ReadUInt32 ();
|
||||
itemInfos.Add (new ItemInfo (decision, firstCandidate));
|
||||
}
|
||||
|
||||
if (r.BaseStream.Position != r.BaseStream.Length)
|
||||
throw new InvalidDataException ();
|
||||
}
|
||||
}
|
||||
|
||||
List<CandidateInfo> candidateInfos = new List<CandidateInfo> ((int)numCandidates);
|
||||
for (int i = 0; i < numCandidates; i++)
|
||||
{
|
||||
byte type = binaryReader.ReadByte ();
|
||||
|
||||
if (type == 0x01)
|
||||
{
|
||||
ResourceValueType resourceValueType = resourceValueTypeTable [binaryReader.ReadByte ()];
|
||||
ushort sourceFileIndex = binaryReader.ReadUInt16 ();
|
||||
ushort valueLocation = binaryReader.ReadUInt16 ();
|
||||
ushort dataItemSection = binaryReader.ReadUInt16 ();
|
||||
candidateInfos.Add (new CandidateInfo (resourceValueType, sourceFileIndex, valueLocation, dataItemSection));
|
||||
}
|
||||
else if (type == 0x00)
|
||||
{
|
||||
ResourceValueType resourceValueType = resourceValueTypeTable [binaryReader.ReadByte ()];
|
||||
ushort length = binaryReader.ReadUInt16 ();
|
||||
uint stringOffset = binaryReader.ReadUInt32 ();
|
||||
candidateInfos.Add (new CandidateInfo (resourceValueType, length, stringOffset));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException ();
|
||||
}
|
||||
}
|
||||
|
||||
long stringDataStartOffset = binaryReader.BaseStream.Position;
|
||||
|
||||
Dictionary<ushort, CandidateSet> candidateSets = new Dictionary<ushort, CandidateSet> ();
|
||||
|
||||
for (int itemToItemInfoGroupIndex = 0; itemToItemInfoGroupIndex < itemToItemInfoGroups.Count; itemToItemInfoGroupIndex++)
|
||||
{
|
||||
ItemToItemInfoGroup itemToItemInfoGroup = itemToItemInfoGroups [itemToItemInfoGroupIndex];
|
||||
|
||||
ItemInfoGroup itemInfoGroup;
|
||||
|
||||
if (itemToItemInfoGroup.ItemInfoGroup < itemInfoGroups.Count)
|
||||
itemInfoGroup = itemInfoGroups [(int)itemToItemInfoGroup.ItemInfoGroup];
|
||||
else
|
||||
itemInfoGroup = new ItemInfoGroup (1, (uint)(itemToItemInfoGroup.ItemInfoGroup - itemInfoGroups.Count));
|
||||
|
||||
for (uint itemInfoIndex = itemInfoGroup.FirstItemInfo; itemInfoIndex < itemInfoGroup.FirstItemInfo + itemInfoGroup.GroupSize; itemInfoIndex++)
|
||||
{
|
||||
ItemInfo itemInfo = itemInfos [(int)itemInfoIndex];
|
||||
|
||||
ushort decisionIndex = (ushort)itemInfo.Decision;
|
||||
|
||||
Decision decision = PriFile.GetSectionByRef (DecisionInfoSection).Decisions [decisionIndex];
|
||||
|
||||
List<Candidate> candidates = new List<Candidate> (decision.QualifierSets.Count);
|
||||
|
||||
for (int i = 0; i < decision.QualifierSets.Count; i++)
|
||||
{
|
||||
CandidateInfo candidateInfo = candidateInfos [(int)itemInfo.FirstCandidate + i];
|
||||
|
||||
if (candidateInfo.Type == 0x01)
|
||||
{
|
||||
ReferencedFileRef sourceFile = null;
|
||||
|
||||
if (candidateInfo.SourceFileIndex != 0)
|
||||
sourceFile = new ReferencedFileRef (candidateInfo.SourceFileIndex - 1);
|
||||
|
||||
candidates.Add (new Candidate (decision.QualifierSets [i].Index, candidateInfo.ResourceValueType, sourceFile,
|
||||
new DataItemRef (new SectionRef<DataItemSection> (candidateInfo.DataItemSection), candidateInfo.DataItemIndex)));
|
||||
}
|
||||
else if (candidateInfo.Type == 0x00)
|
||||
{
|
||||
ByteSpan data = new ByteSpan (sectionPosition + stringDataStartOffset + candidateInfo.DataOffset, candidateInfo.DataLength);
|
||||
|
||||
candidates.Add (new Candidate (decision.QualifierSets [i].Index, candidateInfo.ResourceValueType, data));
|
||||
}
|
||||
}
|
||||
|
||||
ushort resourceMapItemIndex = (ushort)(itemToItemInfoGroup.FirstItem + (itemInfoIndex - itemInfoGroup.FirstItemInfo));
|
||||
|
||||
CandidateSet candidateSet = new CandidateSet (
|
||||
new ResourceMapItemRef (SchemaSection, resourceMapItemIndex),
|
||||
decisionIndex,
|
||||
candidates);
|
||||
|
||||
candidateSets.Add (resourceMapItemIndex, candidateSet);
|
||||
}
|
||||
}
|
||||
|
||||
CandidateSets = candidateSets;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private struct ItemToItemInfoGroup
|
||||
{
|
||||
public uint FirstItem;
|
||||
public uint ItemInfoGroup;
|
||||
|
||||
public ItemToItemInfoGroup (uint firstItem, uint itemInfoGroup)
|
||||
{
|
||||
FirstItem = firstItem;
|
||||
ItemInfoGroup = itemInfoGroup;
|
||||
}
|
||||
}
|
||||
|
||||
private struct ItemInfoGroup
|
||||
{
|
||||
public uint GroupSize;
|
||||
public uint FirstItemInfo;
|
||||
|
||||
public ItemInfoGroup (uint groupSize, uint firstItemInfo)
|
||||
{
|
||||
GroupSize = groupSize;
|
||||
FirstItemInfo = firstItemInfo;
|
||||
}
|
||||
}
|
||||
|
||||
private struct ItemInfo
|
||||
{
|
||||
public uint Decision;
|
||||
public uint FirstCandidate;
|
||||
|
||||
public ItemInfo (uint decision, uint firstCandidate)
|
||||
{
|
||||
Decision = decision;
|
||||
FirstCandidate = firstCandidate;
|
||||
}
|
||||
}
|
||||
|
||||
private struct CandidateInfo
|
||||
{
|
||||
public byte Type;
|
||||
public ResourceValueType ResourceValueType;
|
||||
|
||||
// Type 1
|
||||
public ushort SourceFileIndex;
|
||||
public ushort DataItemIndex;
|
||||
public ushort DataItemSection;
|
||||
|
||||
// Type 0
|
||||
public ushort DataLength;
|
||||
public uint DataOffset;
|
||||
|
||||
public CandidateInfo (ResourceValueType resourceValueType, ushort sourceFileIndex, ushort dataItemIndex, ushort dataItemSection)
|
||||
{
|
||||
Type = 0x01;
|
||||
ResourceValueType = resourceValueType;
|
||||
SourceFileIndex = sourceFileIndex;
|
||||
DataItemIndex = dataItemIndex;
|
||||
DataItemSection = dataItemSection;
|
||||
DataLength = 0;
|
||||
DataOffset = 0;
|
||||
}
|
||||
|
||||
public CandidateInfo (ResourceValueType resourceValueType, ushort dataLength, uint dataOffset)
|
||||
{
|
||||
Type = 0x00;
|
||||
ResourceValueType = resourceValueType;
|
||||
SourceFileIndex = 0;
|
||||
DataItemIndex = 0;
|
||||
DataItemSection = 0;
|
||||
DataLength = dataLength;
|
||||
DataOffset = dataOffset;
|
||||
}
|
||||
}
|
||||
public override void Dispose ()
|
||||
{
|
||||
HierarchicalSchemaReference = null;
|
||||
CandidateSets?.Clear ();
|
||||
CandidateSets = null;
|
||||
base.Dispose ();
|
||||
}
|
||||
~ResourceMapSection () { Dispose (); }
|
||||
}
|
||||
|
||||
public enum ResourceValueType
|
||||
{
|
||||
String,
|
||||
Path,
|
||||
EmbeddedData,
|
||||
AsciiString,
|
||||
Utf8String,
|
||||
AsciiPath,
|
||||
Utf8Path
|
||||
}
|
||||
|
||||
public class CandidateSet: IDisposable
|
||||
{
|
||||
public ResourceMapItemRef ResourceMapItem { get; private set; }
|
||||
public ushort DecisionIndex { get; private set; }
|
||||
public IList<Candidate> Candidates { get; private set; }
|
||||
|
||||
internal CandidateSet (ResourceMapItemRef resourceMapItem, ushort decisionIndex, IList<Candidate> candidates)
|
||||
{
|
||||
ResourceMapItem = resourceMapItem;
|
||||
DecisionIndex = decisionIndex;
|
||||
Candidates = candidates;
|
||||
}
|
||||
|
||||
public virtual void Dispose ()
|
||||
{
|
||||
Candidates?.Clear ();
|
||||
Candidates = null;
|
||||
}
|
||||
~CandidateSet () { Dispose (); }
|
||||
}
|
||||
|
||||
public class Candidate
|
||||
{
|
||||
public ushort QualifierSet { get; private set; }
|
||||
public ResourceValueType Type { get; private set; }
|
||||
public ReferencedFileRef SourceFile { get; private set; }
|
||||
public DataItemRef DataItem { get; private set; }
|
||||
public ByteSpan Data { get; private set; }
|
||||
|
||||
internal Candidate (ushort qualifierSet, ResourceValueType type, ReferencedFileRef sourceFile, DataItemRef dataItem)
|
||||
{
|
||||
QualifierSet = qualifierSet;
|
||||
Type = type;
|
||||
SourceFile = sourceFile;
|
||||
DataItem = dataItem;
|
||||
}
|
||||
|
||||
internal Candidate (ushort qualifierSet, ResourceValueType type, ByteSpan data)
|
||||
{
|
||||
QualifierSet = qualifierSet;
|
||||
Type = type;
|
||||
SourceFile = null;
|
||||
DataItem = null;
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
|
||||
public class HierarchicalSchemaReference
|
||||
{
|
||||
public HierarchicalSchemaVersionInfo VersionInfo { get; private set; }
|
||||
public uint Unknown1 { get; private set; }
|
||||
public uint Unknown2 { get; private set; }
|
||||
public string UniqueName { get; private set; }
|
||||
|
||||
internal HierarchicalSchemaReference (HierarchicalSchemaVersionInfo versionInfo, uint unknown1, uint unknown2, string uniqueName)
|
||||
{
|
||||
VersionInfo = versionInfo;
|
||||
Unknown1 = unknown1;
|
||||
Unknown2 = unknown2;
|
||||
UniqueName = uniqueName;
|
||||
}
|
||||
}
|
||||
|
||||
public struct ResourceMapItemRef
|
||||
{
|
||||
internal SectionRef<HierarchicalSchemaSection> schemaSection;
|
||||
internal int itemIndex;
|
||||
public SectionRef<HierarchicalSchemaSection> SchemaSection => schemaSection;
|
||||
public int ItemIndex => itemIndex;
|
||||
internal ResourceMapItemRef (SectionRef<HierarchicalSchemaSection> schemaSection, int itemIndex)
|
||||
{
|
||||
this.schemaSection = schemaSection;
|
||||
this.itemIndex = itemIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
210
PriFormat/ReverseMapSection.cs
Normal file
210
PriFormat/ReverseMapSection.cs
Normal file
@@ -0,0 +1,210 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
public class ReverseMapSection: Section
|
||||
{
|
||||
public uint [] Mapping { get; private set; }
|
||||
public IList<ResourceMapScope> Scopes { get; private set; }
|
||||
public IList<ResourceMapItem> Items { get; private set; }
|
||||
|
||||
internal const string Identifier = "[mrm_rev_map] \0";
|
||||
|
||||
internal ReverseMapSection (PriFile priFile)
|
||||
: base (Identifier, priFile)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool ParseSectionContent (BinaryReader binaryReader)
|
||||
{
|
||||
uint numItems = binaryReader.ReadUInt32 ();
|
||||
binaryReader.ExpectUInt32 ((uint)(binaryReader.BaseStream.Length - 8));
|
||||
|
||||
uint [] mapping = new uint [numItems];
|
||||
for (int i = 0; i < numItems; i++)
|
||||
mapping [i] = binaryReader.ReadUInt32 ();
|
||||
Mapping = mapping;
|
||||
|
||||
ushort maxFullPathLength = binaryReader.ReadUInt16 ();
|
||||
binaryReader.ExpectUInt16 (0);
|
||||
uint numEntries = binaryReader.ReadUInt32 ();
|
||||
uint numScopes = binaryReader.ReadUInt32 ();
|
||||
|
||||
if (numEntries != numScopes + numItems)
|
||||
throw new InvalidDataException ();
|
||||
|
||||
binaryReader.ExpectUInt32 (numItems);
|
||||
uint unicodeDataLength = binaryReader.ReadUInt32 ();
|
||||
binaryReader.ReadUInt32 (); // meaning unknown
|
||||
|
||||
List<ScopeAndItemInfo> scopeAndItemInfos = new List<ScopeAndItemInfo> ((int)(numScopes + numItems));
|
||||
|
||||
for (int i = 0; i < numScopes + numItems; i++)
|
||||
{
|
||||
ushort parent = binaryReader.ReadUInt16 ();
|
||||
ushort fullPathLength = binaryReader.ReadUInt16 ();
|
||||
char uppercaseFirstChar = (char)binaryReader.ReadUInt16 ();
|
||||
byte nameLength2 = binaryReader.ReadByte ();
|
||||
byte flags = binaryReader.ReadByte ();
|
||||
uint nameOffset = binaryReader.ReadUInt16 () | (uint)((flags & 0xF) << 16);
|
||||
ushort index = binaryReader.ReadUInt16 ();
|
||||
|
||||
scopeAndItemInfos.Add (new ScopeAndItemInfo (parent, fullPathLength, flags, nameOffset, index));
|
||||
}
|
||||
|
||||
List<ScopeExInfo> scopeExInfos = new List<ScopeExInfo> ((int)numScopes);
|
||||
|
||||
for (int i = 0; i < numScopes; i++)
|
||||
{
|
||||
ushort scopeIndex = binaryReader.ReadUInt16 ();
|
||||
ushort childCount = binaryReader.ReadUInt16 ();
|
||||
ushort firstChildIndex = binaryReader.ReadUInt16 ();
|
||||
binaryReader.ExpectUInt16 (0);
|
||||
|
||||
scopeExInfos.Add (new ScopeExInfo (scopeIndex, childCount, firstChildIndex));
|
||||
}
|
||||
|
||||
ushort [] itemIndexPropertyToIndex = new ushort [numItems];
|
||||
for (int i = 0; i < numItems; i++)
|
||||
itemIndexPropertyToIndex [i] = binaryReader.ReadUInt16 ();
|
||||
|
||||
long unicodeDataOffset = binaryReader.BaseStream.Position;
|
||||
long asciiDataOffset = binaryReader.BaseStream.Position + unicodeDataLength * 2;
|
||||
|
||||
ResourceMapScope [] scopes = new ResourceMapScope [numScopes];
|
||||
ResourceMapItem [] items = new ResourceMapItem [numItems];
|
||||
|
||||
for (int i = 0; i < numScopes + numItems; i++)
|
||||
{
|
||||
long pos;
|
||||
|
||||
if (scopeAndItemInfos [i].NameInAscii)
|
||||
pos = asciiDataOffset + scopeAndItemInfos [i].NameOffset;
|
||||
else
|
||||
pos = unicodeDataOffset + scopeAndItemInfos [i].NameOffset * 2;
|
||||
|
||||
binaryReader.BaseStream.Seek (pos, SeekOrigin.Begin);
|
||||
|
||||
string name;
|
||||
|
||||
if (scopeAndItemInfos [i].FullPathLength != 0)
|
||||
name = binaryReader.ReadNullTerminatedString (
|
||||
scopeAndItemInfos [i].NameInAscii ? Encoding.ASCII : Encoding.Unicode);
|
||||
else
|
||||
name = string.Empty;
|
||||
|
||||
ushort index = scopeAndItemInfos [i].Index;
|
||||
|
||||
if (scopeAndItemInfos [i].IsScope)
|
||||
{
|
||||
if (scopes [index] != null)
|
||||
throw new InvalidDataException ();
|
||||
|
||||
scopes [index] = new ResourceMapScope (index, null, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (items [index] != null)
|
||||
throw new InvalidDataException ();
|
||||
|
||||
items [index] = new ResourceMapItem (index, null, name);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numScopes + numItems; i++)
|
||||
{
|
||||
ushort index = scopeAndItemInfos [i].Index;
|
||||
ushort parent = scopeAndItemInfos [scopeAndItemInfos [i].Parent].Index;
|
||||
|
||||
if (parent != 0xFFFF)
|
||||
{
|
||||
if (scopeAndItemInfos [i].IsScope)
|
||||
{
|
||||
if (parent != index)
|
||||
scopes [index].Parent = scopes [parent];
|
||||
}
|
||||
else
|
||||
items [index].Parent = scopes [parent];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numScopes; i++)
|
||||
{
|
||||
List<ResourceMapEntry> children = new List<ResourceMapEntry> (scopeExInfos [i].ChildCount);
|
||||
|
||||
for (int j = 0; j < scopeExInfos [i].ChildCount; j++)
|
||||
{
|
||||
ScopeAndItemInfo saiInfo = scopeAndItemInfos [scopeExInfos [i].FirstChildIndex + j];
|
||||
|
||||
if (saiInfo.IsScope)
|
||||
children.Add (scopes [saiInfo.Index]);
|
||||
else
|
||||
children.Add (items [saiInfo.Index]);
|
||||
}
|
||||
|
||||
scopes [i].Children = children;
|
||||
}
|
||||
|
||||
Scopes = new ReadOnlyCollection<ResourceMapScope> (scopes);
|
||||
Items = new ReadOnlyCollection<ResourceMapItem> (items);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private struct ScopeAndItemInfo
|
||||
{
|
||||
public ushort Parent;
|
||||
public ushort FullPathLength;
|
||||
public byte Flags;
|
||||
public uint NameOffset;
|
||||
public ushort Index;
|
||||
|
||||
public ScopeAndItemInfo (ushort parent, ushort fullPathLength, byte flags, uint nameOffset, ushort index)
|
||||
{
|
||||
Parent = parent;
|
||||
FullPathLength = fullPathLength;
|
||||
Flags = flags;
|
||||
NameOffset = nameOffset;
|
||||
Index = index;
|
||||
}
|
||||
|
||||
public bool IsScope
|
||||
{
|
||||
get { return (Flags & 0x10) != 0; }
|
||||
}
|
||||
|
||||
public bool NameInAscii
|
||||
{
|
||||
get { return (Flags & 0x20) != 0; }
|
||||
}
|
||||
}
|
||||
|
||||
private struct ScopeExInfo
|
||||
{
|
||||
public ushort ScopeIndex;
|
||||
public ushort ChildCount;
|
||||
public ushort FirstChildIndex;
|
||||
|
||||
public ScopeExInfo (ushort scopeIndex, ushort childCount, ushort firstChildIndex)
|
||||
{
|
||||
ScopeIndex = scopeIndex;
|
||||
ChildCount = childCount;
|
||||
FirstChildIndex = firstChildIndex;
|
||||
}
|
||||
}
|
||||
public override void Dispose ()
|
||||
{
|
||||
Mapping = null;
|
||||
Scopes?.Clear ();
|
||||
Scopes = null;
|
||||
Items?.Clear ();
|
||||
Items = null;
|
||||
base.Dispose ();
|
||||
}
|
||||
~ReverseMapSection () { Dispose (); }
|
||||
}
|
||||
}
|
||||
126
PriFormat/Section.cs
Normal file
126
PriFormat/Section.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
public abstract class Section: IDisposable
|
||||
{
|
||||
protected PriFile PriFile { get; private set; }
|
||||
|
||||
public string SectionIdentifier { get; private set; }
|
||||
public uint SectionQualifier { get; private set; }
|
||||
public uint Flags { get; private set; }
|
||||
public uint SectionFlags { get; private set; }
|
||||
public uint SectionLength { get; private set; }
|
||||
|
||||
protected Section (string sectionIdentifier, PriFile priFile)
|
||||
{
|
||||
if (sectionIdentifier == null)
|
||||
throw new ArgumentNullException ("sectionIdentifier");
|
||||
|
||||
if (sectionIdentifier.Length != 16)
|
||||
throw new ArgumentException (
|
||||
"Section identifiers must be exactly 16 characters long.",
|
||||
"sectionIdentifier");
|
||||
|
||||
SectionIdentifier = sectionIdentifier;
|
||||
PriFile = priFile;
|
||||
}
|
||||
|
||||
internal bool Parse (BinaryReader binaryReader)
|
||||
{
|
||||
// identifier
|
||||
string identifier = new string (binaryReader.ReadChars (16));
|
||||
if (identifier != SectionIdentifier)
|
||||
throw new InvalidDataException ("Unexpected section identifier.");
|
||||
|
||||
SectionQualifier = binaryReader.ReadUInt32 ();
|
||||
Flags = binaryReader.ReadUInt16 ();
|
||||
SectionFlags = binaryReader.ReadUInt16 ();
|
||||
SectionLength = binaryReader.ReadUInt32 ();
|
||||
|
||||
binaryReader.ExpectUInt32 (0);
|
||||
|
||||
// 跳到 section 尾部校验
|
||||
long contentLength = SectionLength - 16 - 24;
|
||||
|
||||
binaryReader.BaseStream.Seek (contentLength, SeekOrigin.Current);
|
||||
|
||||
binaryReader.ExpectUInt32 (0xDEF5FADE);
|
||||
binaryReader.ExpectUInt32 (SectionLength);
|
||||
|
||||
// 回到 section 内容起始位置
|
||||
binaryReader.BaseStream.Seek (-8 - contentLength, SeekOrigin.Current);
|
||||
|
||||
//关键点:SubStream + BinaryReader 生命周期
|
||||
using (SubStream subStream = new SubStream (
|
||||
binaryReader.BaseStream,
|
||||
binaryReader.BaseStream.Position,
|
||||
contentLength))
|
||||
{
|
||||
using (BinaryReader subReader =
|
||||
new BinaryReader (subStream, Encoding.ASCII))
|
||||
{
|
||||
return ParseSectionContent (subReader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract bool ParseSectionContent (BinaryReader binaryReader);
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return SectionIdentifier.TrimEnd ('\0', ' ') +
|
||||
" length: " + SectionLength;
|
||||
}
|
||||
|
||||
internal static Section CreateForIdentifier (
|
||||
string sectionIdentifier,
|
||||
PriFile priFile)
|
||||
{
|
||||
if (sectionIdentifier == null)
|
||||
throw new ArgumentNullException ("sectionIdentifier");
|
||||
|
||||
switch (sectionIdentifier)
|
||||
{
|
||||
case PriDescriptorSection.Identifier:
|
||||
return new PriDescriptorSection (priFile);
|
||||
|
||||
case HierarchicalSchemaSection.Identifier1:
|
||||
return new HierarchicalSchemaSection (priFile, false);
|
||||
|
||||
case HierarchicalSchemaSection.Identifier2:
|
||||
return new HierarchicalSchemaSection (priFile, true);
|
||||
|
||||
case DecisionInfoSection.Identifier:
|
||||
return new DecisionInfoSection (priFile);
|
||||
|
||||
case ResourceMapSection.Identifier1:
|
||||
return new ResourceMapSection (priFile, false);
|
||||
|
||||
case ResourceMapSection.Identifier2:
|
||||
return new ResourceMapSection (priFile, true);
|
||||
|
||||
case DataItemSection.Identifier:
|
||||
return new DataItemSection (priFile);
|
||||
|
||||
case ReverseMapSection.Identifier:
|
||||
return new ReverseMapSection (priFile);
|
||||
|
||||
case ReferencedFileSection.Identifier:
|
||||
return new ReferencedFileSection (priFile);
|
||||
|
||||
default:
|
||||
return new UnknownSection (sectionIdentifier, priFile);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Dispose ()
|
||||
{
|
||||
this.PriFile = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
171
PriFormat/StreamHelper.cs
Normal file
171
PriFormat/StreamHelper.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
public static class StreamHelper
|
||||
{
|
||||
public static Stream FromIStream (IStream comStream)
|
||||
{
|
||||
if (comStream == null) return null;
|
||||
return new ComIStreamBufferedReader (comStream);
|
||||
}
|
||||
|
||||
public static Stream FromIStream (IntPtr comStreamPtr)
|
||||
{
|
||||
if (comStreamPtr == IntPtr.Zero) return null;
|
||||
|
||||
IStream comStream =
|
||||
(IStream)Marshal.GetObjectForIUnknown (comStreamPtr);
|
||||
|
||||
return new ComIStreamBufferedReader (comStream);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ComIStreamBufferedReader: Stream
|
||||
{
|
||||
private readonly MemoryStream _memory;
|
||||
private bool _disposed;
|
||||
|
||||
public ComIStreamBufferedReader (IStream comStream)
|
||||
{
|
||||
if (comStream == null)
|
||||
throw new ArgumentNullException ("comStream");
|
||||
|
||||
_memory = LoadAll (comStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 一次性把 IStream 全部复制到托管内存
|
||||
/// </summary>
|
||||
private static MemoryStream LoadAll (IStream stream)
|
||||
{
|
||||
// 保存原始位置
|
||||
long originalPos = GetPosition (stream);
|
||||
|
||||
try
|
||||
{
|
||||
// Seek 到头
|
||||
stream.Seek (0, 0 /* STREAM_SEEK_SET */, IntPtr.Zero);
|
||||
|
||||
// 获取长度
|
||||
System.Runtime.InteropServices.ComTypes.STATSTG stat;
|
||||
stream.Stat (out stat, 1); // STATFLAG_NONAME
|
||||
long length = stat.cbSize;
|
||||
|
||||
if (length < 0 || length > int.MaxValue)
|
||||
throw new NotSupportedException ("Stream too large to buffer.");
|
||||
|
||||
MemoryStream ms = new MemoryStream ((int)length);
|
||||
|
||||
byte [] buffer = new byte [64 * 1024]; // 64KB
|
||||
IntPtr pcbRead = Marshal.AllocHGlobal (sizeof (int));
|
||||
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
stream.Read (buffer, buffer.Length, pcbRead);
|
||||
int read = Marshal.ReadInt32 (pcbRead);
|
||||
if (read <= 0)
|
||||
break;
|
||||
|
||||
ms.Write (buffer, 0, read);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal (pcbRead);
|
||||
}
|
||||
|
||||
ms.Position = 0;
|
||||
return ms;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 恢复 COM IStream 的原始位置
|
||||
stream.Seek (originalPos, 0 /* STREAM_SEEK_SET */, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
private static long GetPosition (IStream stream)
|
||||
{
|
||||
IntPtr posPtr = Marshal.AllocHGlobal (sizeof (long));
|
||||
try
|
||||
{
|
||||
stream.Seek (0, 1 /* STREAM_SEEK_CUR */, posPtr);
|
||||
return Marshal.ReadInt64 (posPtr);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal (posPtr);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Stream 重写,全部委托给 MemoryStream =====
|
||||
|
||||
public override bool CanRead { get { return !_disposed; } }
|
||||
public override bool CanSeek { get { return !_disposed; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { EnsureNotDisposed (); return _memory.Length; }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { EnsureNotDisposed (); return _memory.Position; }
|
||||
set { EnsureNotDisposed (); _memory.Position = value; }
|
||||
}
|
||||
|
||||
public override int Read (byte [] buffer, int offset, int count)
|
||||
{
|
||||
EnsureNotDisposed ();
|
||||
return _memory.Read (buffer, offset, count);
|
||||
}
|
||||
|
||||
public override long Seek (long offset, SeekOrigin origin)
|
||||
{
|
||||
EnsureNotDisposed ();
|
||||
return _memory.Seek (offset, origin);
|
||||
}
|
||||
|
||||
public override void Flush ()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
public override void SetLength (long value)
|
||||
{
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
|
||||
public override void Write (byte [] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_memory.Dispose ();
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
base.Dispose (disposing);
|
||||
}
|
||||
|
||||
private void EnsureNotDisposed ()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException ("ComIStreamBufferedReader");
|
||||
}
|
||||
}
|
||||
}
|
||||
110
PriFormat/SubStream.cs
Normal file
110
PriFormat/SubStream.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
internal sealed class SubStream: Stream
|
||||
{
|
||||
private readonly Stream _baseStream;
|
||||
private readonly long _baseOffset;
|
||||
private readonly long _length;
|
||||
private long _position;
|
||||
|
||||
public SubStream (Stream baseStream, long offset, long length)
|
||||
{
|
||||
if (baseStream == null)
|
||||
throw new ArgumentNullException ("baseStream");
|
||||
if (!baseStream.CanSeek)
|
||||
throw new ArgumentException ("Base stream must be seekable.");
|
||||
|
||||
_baseStream = baseStream;
|
||||
_baseOffset = offset;
|
||||
_length = length;
|
||||
_position = 0;
|
||||
}
|
||||
|
||||
public override bool CanRead { get { return true; } }
|
||||
public override bool CanSeek { get { return true; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { return _length; }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { return _position; }
|
||||
set
|
||||
{
|
||||
if (value < 0 || value > _length)
|
||||
throw new ArgumentOutOfRangeException ("value");
|
||||
_position = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read (byte [] buffer, int offset, int count)
|
||||
{
|
||||
if (buffer == null)
|
||||
throw new ArgumentNullException ("buffer");
|
||||
if (offset < 0 || count < 0 || buffer.Length - offset < count)
|
||||
throw new ArgumentOutOfRangeException ();
|
||||
|
||||
long remaining = _length - _position;
|
||||
if (remaining <= 0)
|
||||
return 0;
|
||||
|
||||
if (count > remaining)
|
||||
count = (int)remaining;
|
||||
|
||||
_baseStream.Position = _baseOffset + _position;
|
||||
int read = _baseStream.Read (buffer, offset, count);
|
||||
_position += read;
|
||||
return read;
|
||||
}
|
||||
|
||||
public override long Seek (long offset, SeekOrigin origin)
|
||||
{
|
||||
long target;
|
||||
|
||||
switch (origin)
|
||||
{
|
||||
case SeekOrigin.Begin:
|
||||
target = offset;
|
||||
break;
|
||||
|
||||
case SeekOrigin.Current:
|
||||
target = _position + offset;
|
||||
break;
|
||||
|
||||
case SeekOrigin.End:
|
||||
target = _length + offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentException ("origin");
|
||||
}
|
||||
|
||||
if (target < 0 || target > _length)
|
||||
throw new IOException ("Seek out of range.");
|
||||
|
||||
_position = target;
|
||||
return _position;
|
||||
}
|
||||
|
||||
public override void Flush ()
|
||||
{
|
||||
// no-op (read-only)
|
||||
}
|
||||
|
||||
public override void SetLength (long value)
|
||||
{
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
|
||||
public override void Write (byte [] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
}
|
||||
}
|
||||
35
PriFormat/TocEntry.cs
Normal file
35
PriFormat/TocEntry.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
public sealed class TocEntry
|
||||
{
|
||||
public string SectionIdentifier { get; private set; }
|
||||
public ushort Flags { get; private set; }
|
||||
public ushort SectionFlags { get; private set; }
|
||||
public uint SectionQualifier { get; private set; }
|
||||
public uint SectionOffset { get; private set; }
|
||||
public uint SectionLength { get; private set; }
|
||||
private TocEntry () { }
|
||||
internal static TocEntry Parse (BinaryReader reader)
|
||||
{
|
||||
return new TocEntry
|
||||
{
|
||||
SectionIdentifier = new string (reader.ReadChars (16)),
|
||||
Flags = reader.ReadUInt16 (),
|
||||
SectionFlags = reader.ReadUInt16 (),
|
||||
SectionQualifier = reader.ReadUInt32 (),
|
||||
SectionOffset = reader.ReadUInt32 (),
|
||||
SectionLength = reader.ReadUInt32 ()
|
||||
};
|
||||
}
|
||||
public override string ToString ()
|
||||
{
|
||||
return SectionIdentifier.TrimEnd ('\0', ' ') + "\t length: " + SectionLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
PriFormat/UnknownSection.cs
Normal file
28
PriFormat/UnknownSection.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System.IO;
|
||||
|
||||
namespace PriFormat
|
||||
{
|
||||
public class UnknownSection: Section
|
||||
{
|
||||
public byte [] SectionContent { get; private set; }
|
||||
|
||||
internal UnknownSection (string sectionIdentifier, PriFile priFile)
|
||||
: base (sectionIdentifier, priFile)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool ParseSectionContent (BinaryReader binaryReader)
|
||||
{
|
||||
int contentLength = (int)(binaryReader.BaseStream.Length - binaryReader.BaseStream.Position);
|
||||
|
||||
SectionContent = binaryReader.ReadBytes (contentLength);
|
||||
|
||||
return true;
|
||||
}
|
||||
public override void Dispose ()
|
||||
{
|
||||
SectionContent = null;
|
||||
base.Dispose ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,7 +186,7 @@ namespace Win32
|
||||
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 InitSection this [string key] => GetSection (key);
|
||||
public string [] GetAllSections ()
|
||||
{
|
||||
var sections = new System.Collections.Generic.List<string> ();
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Update
|
||||
{
|
||||
@@ -47,18 +47,36 @@ namespace Update
|
||||
[STAThread]
|
||||
static void Main (string [] args)
|
||||
{
|
||||
Process p = new Process ();
|
||||
p.StartInfo.FileName = Path.Combine (AppDomain.CurrentDomain.BaseDirectory, "settings.exe");
|
||||
var arguments = new List<string>
|
||||
bool createdNew = false;
|
||||
Mutex mutex = new Mutex (true, "WindowsModern.PracticalToolsProject!Settings.Update", out createdNew);
|
||||
if (!createdNew)
|
||||
{
|
||||
"appinstaller",
|
||||
"update"
|
||||
};
|
||||
arguments.AddRange (args);
|
||||
p.StartInfo.Arguments = string.Join (" ", arguments.Select (EscapeArgument));
|
||||
p.Start ();
|
||||
p.WaitForExit ();
|
||||
int exitCode = p.ExitCode;
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
Process p = new Process ();
|
||||
p.StartInfo.FileName = Path.Combine (AppDomain.CurrentDomain.BaseDirectory, "settings.exe");
|
||||
List<string> arguments = new List<string> ();
|
||||
arguments.Add ("appinstaller");
|
||||
arguments.Add ("update");
|
||||
arguments.AddRange (args);
|
||||
StringBuilder argBuilder = new StringBuilder ();
|
||||
foreach (string a in arguments)
|
||||
{
|
||||
if (argBuilder.Length > 0)
|
||||
argBuilder.Append (" ");
|
||||
argBuilder.Append (EscapeArgument (a));
|
||||
}
|
||||
p.StartInfo.Arguments = argBuilder.ToString ();
|
||||
p.Start ();
|
||||
p.WaitForExit ();
|
||||
int exitCode = p.ExitCode;
|
||||
}
|
||||
finally
|
||||
{
|
||||
mutex.ReleaseMutex ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,12 +73,6 @@
|
||||
<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.
|
||||
|
||||
63
WAShell/Properties/Resources.Designer.cs
generated
Normal file
63
WAShell/Properties/Resources.Designer.cs
generated
Normal file
@@ -0,0 +1,63 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本:4.0.30319.42000
|
||||
//
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||
// 重新生成代码,这些更改将会丢失。
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace WAShell.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 一个强类型的资源类,用于查找本地化的字符串等。
|
||||
/// </summary>
|
||||
// 此类是由 StronglyTypedResourceBuilder
|
||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回此类使用的缓存的 ResourceManager 实例。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WAShell.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用此强类型资源类,为所有资源查找
|
||||
/// 重写当前线程的 CurrentUICulture 属性。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user