new folder structure and new C# script host
This commit is contained in:
113
src/Native/MediaInfo.cs
Normal file
113
src/Native/MediaInfo.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public class MediaInfo : IDisposable
|
||||
{
|
||||
IntPtr Handle;
|
||||
|
||||
public MediaInfo(string file)
|
||||
{
|
||||
if ((Handle = MediaInfo_New()) == IntPtr.Zero)
|
||||
throw new Exception("Failed to call MediaInfo_New");
|
||||
|
||||
if (MediaInfo_Open(Handle, file) == 0)
|
||||
throw new Exception("Error MediaInfo_Open");
|
||||
}
|
||||
|
||||
public string GetInfo(MediaInfoStreamKind kind, string parameter)
|
||||
{
|
||||
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, kind, 0,
|
||||
parameter, MediaInfoKind.Text, MediaInfoKind.Name));
|
||||
}
|
||||
|
||||
public int GetCount(MediaInfoStreamKind kind) => MediaInfo_Count_Get(Handle, kind, -1);
|
||||
|
||||
public string GetVideo(int stream, string parameter)
|
||||
{
|
||||
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, MediaInfoStreamKind.Video,
|
||||
stream, parameter, MediaInfoKind.Text, MediaInfoKind.Name));
|
||||
}
|
||||
|
||||
public string GetAudio(int stream, string parameter)
|
||||
{
|
||||
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, MediaInfoStreamKind.Audio,
|
||||
stream, parameter, MediaInfoKind.Text, MediaInfoKind.Name));
|
||||
}
|
||||
|
||||
public string GetText(int stream, string parameter)
|
||||
{
|
||||
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, MediaInfoStreamKind.Text,
|
||||
stream, parameter, MediaInfoKind.Text, MediaInfoKind.Name));
|
||||
}
|
||||
|
||||
bool Disposed;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!Disposed)
|
||||
{
|
||||
if (Handle != IntPtr.Zero)
|
||||
{
|
||||
MediaInfo_Close(Handle);
|
||||
MediaInfo_Delete(Handle);
|
||||
}
|
||||
|
||||
Disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
~MediaInfo()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
[DllImport("MediaInfo.dll")]
|
||||
static extern IntPtr MediaInfo_New();
|
||||
|
||||
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
|
||||
static extern int MediaInfo_Open(IntPtr handle, string path);
|
||||
|
||||
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
|
||||
static extern IntPtr MediaInfo_Option(IntPtr handle, string option, string value);
|
||||
|
||||
[DllImport("MediaInfo.dll")]
|
||||
static extern IntPtr MediaInfo_Inform(IntPtr handle, int reserved);
|
||||
|
||||
[DllImport("MediaInfo.dll")]
|
||||
static extern int MediaInfo_Close(IntPtr handle);
|
||||
|
||||
[DllImport("MediaInfo.dll")]
|
||||
static extern void MediaInfo_Delete(IntPtr handle);
|
||||
|
||||
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
|
||||
static extern IntPtr MediaInfo_Get(IntPtr handle, MediaInfoStreamKind kind,
|
||||
int stream, string parameter, MediaInfoKind infoKind, MediaInfoKind searchKind);
|
||||
|
||||
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
|
||||
static extern int MediaInfo_Count_Get(IntPtr handle, MediaInfoStreamKind streamKind, int stream);
|
||||
}
|
||||
|
||||
public enum MediaInfoStreamKind
|
||||
{
|
||||
General,
|
||||
Video,
|
||||
Audio,
|
||||
Text,
|
||||
Other,
|
||||
Image,
|
||||
Menu,
|
||||
Max,
|
||||
}
|
||||
|
||||
public enum MediaInfoKind
|
||||
{
|
||||
Name,
|
||||
Text,
|
||||
Measure,
|
||||
Options,
|
||||
NameText,
|
||||
MeasureText,
|
||||
Info,
|
||||
HowTo
|
||||
}
|
||||
108
src/Native/Native.cs
Normal file
108
src/Native/Native.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public class WinAPI
|
||||
{
|
||||
public const int VK_MEDIA_NEXT_TRACK = 0xB0;
|
||||
public const int VK_MEDIA_PREV_TRACK = 0xB1;
|
||||
public const int VK_MEDIA_STOP = 0xB2;
|
||||
public const int VK_MEDIA_PLAY_PAUSE = 0xB3;
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool AttachConsole(int dwProcessId);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool FreeConsole();
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr LoadLibrary(string path);
|
||||
|
||||
[DllImport("user32")]
|
||||
public static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr FindWindowEx(
|
||||
IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern int RegisterWindowMessage(string id);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool AllowSetForegroundWindow(int dwProcessId);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern void ReleaseCapture();
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool AdjustWindowRect(ref RECT lpRect, uint dwStyle, bool bMenu);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
|
||||
static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
|
||||
static extern IntPtr GetWindowLong64(IntPtr hWnd, int nIndex);
|
||||
|
||||
public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
return GetWindowLong64(hWnd, nIndex);
|
||||
else
|
||||
return GetWindowLong32(hWnd, nIndex);
|
||||
}
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT
|
||||
{
|
||||
public int Left;
|
||||
public int Top;
|
||||
public int Right;
|
||||
public int Bottom;
|
||||
|
||||
public RECT(Rectangle r)
|
||||
{
|
||||
Left = r.Left;
|
||||
Top = r.Top;
|
||||
Right = r.Right;
|
||||
Bottom = r.Bottom;
|
||||
}
|
||||
|
||||
public RECT(int left, int top, int right, int bottom)
|
||||
{
|
||||
Left = left;
|
||||
Top = top;
|
||||
Right = right;
|
||||
Bottom = bottom;
|
||||
}
|
||||
|
||||
public Rectangle ToRectangle() => Rectangle.FromLTRB(Left, Top, Right, Bottom);
|
||||
public Size Size => new Size(Right - Left, Bottom - Top);
|
||||
public int Width => Right - Left;
|
||||
public int Height => Bottom - Top;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct COPYDATASTRUCT
|
||||
{
|
||||
public IntPtr dwData;
|
||||
public int cbData;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string lpData;
|
||||
}
|
||||
}
|
||||
41
src/Native/NativeHelp.cs
Normal file
41
src/Native/NativeHelp.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
using System;
|
||||
|
||||
using static WinAPI;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public static class NativeHelp
|
||||
{
|
||||
public static int GetResizeBorder(int v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
case 1 /* WMSZ_LEFT */ : return 3;
|
||||
case 3 /* WMSZ_TOP */ : return 2;
|
||||
case 2 /* WMSZ_RIGHT */ : return 3;
|
||||
case 6 /* WMSZ_BOTTOM */ : return 2;
|
||||
case 4 /* WMSZ_TOPLEFT */ : return 1;
|
||||
case 5 /* WMSZ_TOPRIGHT */ : return 1;
|
||||
case 7 /* WMSZ_BOTTOMLEFT */ : return 3;
|
||||
case 8 /* WMSZ_BOTTOMRIGHT */ : return 3;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SubtractWindowBorders(IntPtr hwnd, ref RECT rc)
|
||||
{
|
||||
RECT r = new RECT(0, 0, 0, 0);
|
||||
AddWindowBorders(hwnd, ref r);
|
||||
rc.Left -= r.Left;
|
||||
rc.Top -= r.Top;
|
||||
rc.Right -= r.Right;
|
||||
rc.Bottom -= r.Bottom;
|
||||
}
|
||||
|
||||
public static void AddWindowBorders(IntPtr hwnd, ref RECT rc)
|
||||
{
|
||||
AdjustWindowRect(ref rc, (uint)GetWindowLong(hwnd, -16 /* GWL_STYLE */), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
131
src/Native/StockIcon.cs
Normal file
131
src/Native/StockIcon.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public class StockIcon
|
||||
{
|
||||
[DllImport("shell32.dll")]
|
||||
public static extern int SHGetStockIconInfo(SHSTOCKICONID siid, SHSTOCKICONFLAGS uFlags, ref SHSTOCKICONINFO info);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool DestroyIcon(IntPtr handle);
|
||||
|
||||
public static IntPtr GetIcon(SHSTOCKICONID identifier, SHSTOCKICONFLAGS flags)
|
||||
{
|
||||
SHSTOCKICONINFO info = new SHSTOCKICONINFO();
|
||||
info.cbSize = Convert.ToUInt32(Marshal.SizeOf(typeof(SHSTOCKICONINFO)));
|
||||
Marshal.ThrowExceptionForHR(SHGetStockIconInfo(identifier, flags, ref info));
|
||||
return info.hIcon;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct SHSTOCKICONINFO
|
||||
{
|
||||
public uint cbSize;
|
||||
public IntPtr hIcon;
|
||||
int iSysImageIndex;
|
||||
int iIcon;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
|
||||
string szPath;
|
||||
}
|
||||
|
||||
public enum SHSTOCKICONFLAGS : uint
|
||||
{
|
||||
SHGSI_ICONLOCATION = 0,
|
||||
SHGSI_ICON = 0x000000100,
|
||||
SHGSI_SYSICONINDEX = 0x000004000,
|
||||
SHGSI_LINKOVERLAY = 0x000008000,
|
||||
SHGSI_SELECTED = 0x000010000,
|
||||
SHGSI_LARGEICON = 0x000000000,
|
||||
SHGSI_SMALLICON = 0x000000001,
|
||||
SHGSI_SHELLICONSIZE = 0x000000004
|
||||
}
|
||||
|
||||
public enum SHSTOCKICONID : uint
|
||||
{
|
||||
DocumentNotAssociated = 0,
|
||||
DocumentAssociated = 1,
|
||||
Application = 2,
|
||||
Folder = 3,
|
||||
FolderOpen = 4,
|
||||
Drive525 = 5,
|
||||
Drive35 = 6,
|
||||
DriveRemove = 7,
|
||||
DriveFixed = 8,
|
||||
DriveNetwork = 9,
|
||||
DriveNetworkDisabled = 10,
|
||||
DriveCD = 11,
|
||||
DriveRAM = 12,
|
||||
World = 13,
|
||||
Server = 15,
|
||||
Printer = 16,
|
||||
MyNetwork = 17,
|
||||
Find = 22,
|
||||
Help = 23,
|
||||
Share = 28,
|
||||
Link = 29,
|
||||
SlowFile = 30,
|
||||
Recycler = 31,
|
||||
RecyclerFull = 32,
|
||||
MediaCDAudio = 40,
|
||||
Lock = 47,
|
||||
AutoList = 49,
|
||||
PrinterNet = 50,
|
||||
ServerShare = 51,
|
||||
PrinterFax = 52,
|
||||
PrinterFaxNet = 53,
|
||||
PrinterFile = 54,
|
||||
Stack = 55,
|
||||
MediaSVCD = 56,
|
||||
StuffedFolder = 57,
|
||||
DriveUnknown = 58,
|
||||
DriveDVD = 59,
|
||||
MediaDVD = 60,
|
||||
MediaDVDRAM = 61,
|
||||
MediaDVDRW = 62,
|
||||
MediaDVDR = 63,
|
||||
MediaDVDROM = 64,
|
||||
MediaCDAudioPlus = 65,
|
||||
MediaCDRW = 66,
|
||||
MediaCDR = 67,
|
||||
MediaCDBurn = 68,
|
||||
MediaBlankCD = 69,
|
||||
MediaCDROM = 70,
|
||||
AudioFiles = 71,
|
||||
ImageFiles = 72,
|
||||
VideoFiles = 73,
|
||||
MixedFiles = 74,
|
||||
FolderBack = 75,
|
||||
FolderFront = 76,
|
||||
Shield = 77,
|
||||
Warning = 78,
|
||||
Info = 79,
|
||||
Error = 80,
|
||||
Key = 81,
|
||||
Software = 82,
|
||||
Rename = 83,
|
||||
Delete = 84,
|
||||
MediaAudioDVD = 85,
|
||||
MediaMovieDVD = 86,
|
||||
MediaEnhancedCD = 87,
|
||||
MediaEnhancedDVD = 88,
|
||||
MediaHDDVD = 89,
|
||||
MediaBluRay = 90,
|
||||
MediaVCD = 91,
|
||||
MediaDVDPlusR = 92,
|
||||
MediaDVDPlusRW = 93,
|
||||
DesktopPC = 94,
|
||||
MobilePC = 95,
|
||||
Users = 96,
|
||||
MediaSmartMedia = 97,
|
||||
MediaCompactFlash = 98,
|
||||
DeviceCellPhone = 99,
|
||||
DeviceCamera = 100,
|
||||
DeviceVideoCamera = 101,
|
||||
DeviceAudioPlayer = 102,
|
||||
NetworkConnect = 103,
|
||||
Internet = 104,
|
||||
ZipFile = 105,
|
||||
Settings = 106
|
||||
}
|
||||
}
|
||||
670
src/Native/TaskDialog.cs
Normal file
670
src/Native/TaskDialog.cs
Normal file
@@ -0,0 +1,670 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
public class Msg
|
||||
{
|
||||
static string ShownMessages;
|
||||
|
||||
public static string SupportURL { get; set; }
|
||||
|
||||
public static void Show(string mainInstruction, string content = null)
|
||||
{
|
||||
Msg.Show(mainInstruction, content, MsgIcon.Info, MsgButtons.Ok, MsgResult.None);
|
||||
}
|
||||
|
||||
public static void ShowError(string mainInstruction, string content = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (TaskDialog<string> td = new TaskDialog<string>())
|
||||
{
|
||||
td.AllowCancel = false;
|
||||
|
||||
if (string.IsNullOrEmpty(content))
|
||||
{
|
||||
if (mainInstruction.Length < 80)
|
||||
td.MainInstruction = mainInstruction;
|
||||
else
|
||||
td.Content = mainInstruction;
|
||||
}
|
||||
else
|
||||
{
|
||||
td.MainInstruction = mainInstruction;
|
||||
td.Content = content;
|
||||
}
|
||||
|
||||
td.MainIcon = MsgIcon.Error;
|
||||
td.Footer = "[Copy Message](copymsg)";
|
||||
|
||||
if (!string.IsNullOrEmpty(Msg.SupportURL))
|
||||
td.Footer += $" [Contact Support]({SupportURL})";
|
||||
|
||||
td.Show();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBox.Show(e.GetType().Name + "\n\n" + e.Message + "\n\n" + e,
|
||||
Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowException(Exception exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (TaskDialog<string> td = new TaskDialog<string>())
|
||||
{
|
||||
td.MainInstruction = exception.GetType().Name;
|
||||
td.Content = exception.Message;
|
||||
td.MainIcon = MsgIcon.Error;
|
||||
td.ExpandedInformation = exception.StackTrace;
|
||||
td.Footer = "[Copy Message](copymsg)";
|
||||
|
||||
if (!string.IsNullOrEmpty(Msg.SupportURL))
|
||||
td.Footer += $" [Contact Support]({SupportURL})";
|
||||
|
||||
td.Show();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBox.Show(e.ToString(), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowWarning(string mainInstruction,
|
||||
string content = null,
|
||||
bool onlyOnce = false)
|
||||
{
|
||||
if (onlyOnce && Msg.ShownMessages != null &&
|
||||
Msg.ShownMessages.Contains(mainInstruction + content))
|
||||
return;
|
||||
|
||||
Msg.Show(mainInstruction, content, MsgIcon.Warning, MsgButtons.Ok, MsgResult.None);
|
||||
if (!onlyOnce) return;
|
||||
Msg.ShownMessages += mainInstruction + content;
|
||||
}
|
||||
|
||||
public static MsgResult ShowQuestion(
|
||||
string mainInstruction, MsgButtons buttons = MsgButtons.OkCancel)
|
||||
{
|
||||
return Msg.Show(mainInstruction, null, MsgIcon.None, buttons, MsgResult.None);
|
||||
}
|
||||
|
||||
public static MsgResult ShowQuestion(
|
||||
string mainInstruction, string content, MsgButtons buttons = MsgButtons.OkCancel)
|
||||
{
|
||||
return Msg.Show(mainInstruction, content, MsgIcon.None, buttons, MsgResult.None);
|
||||
}
|
||||
|
||||
public static MsgResult Show(
|
||||
string mainInstruction,
|
||||
string content,
|
||||
MsgIcon icon,
|
||||
MsgButtons buttons,
|
||||
MsgResult defaultButton = MsgResult.None)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (TaskDialog<MsgResult> td = new TaskDialog<MsgResult>())
|
||||
{
|
||||
td.AllowCancel = false;
|
||||
td.DefaultButton = defaultButton;
|
||||
td.MainIcon = icon;
|
||||
|
||||
if (content == null)
|
||||
{
|
||||
if (mainInstruction.Length < 80)
|
||||
td.MainInstruction = mainInstruction;
|
||||
else
|
||||
td.Content = mainInstruction;
|
||||
}
|
||||
else
|
||||
{
|
||||
td.MainInstruction = mainInstruction;
|
||||
td.Content = content;
|
||||
}
|
||||
if (buttons == MsgButtons.OkCancel)
|
||||
{
|
||||
td.AddButton("OK", MsgResult.OK);
|
||||
td.AddButton("Cancel", MsgResult.Cancel);
|
||||
}
|
||||
else
|
||||
td.CommonButtons = buttons;
|
||||
return td.Show();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return (MsgResult)MessageBox.Show(e.GetType().Name + "\n\n" + e.Message + "\n\n" + e,
|
||||
Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TaskDialog<T> : TaskDialogNative, IDisposable
|
||||
{
|
||||
Dictionary<int, T> IdValueDic;
|
||||
Dictionary<int, string> IdTextDic;
|
||||
List<int> CommandLinkShieldList;
|
||||
IntPtr ButtonArray;
|
||||
IntPtr RadioButtonArray;
|
||||
T SelectedValueValue;
|
||||
string SelectedTextValue;
|
||||
int TimeoutValue;
|
||||
int ExitTickCount;
|
||||
bool Disposed;
|
||||
List<TaskDialogNative.TASKDIALOG_BUTTON> Buttons;
|
||||
List<TaskDialogNative.TASKDIALOG_BUTTON> RadioButtons;
|
||||
TaskDialogNative.TASKDIALOGCONFIG Config;
|
||||
|
||||
const int TDE_CONTENT = 0;
|
||||
const int TDE_EXPANDED_INFORMATION = 1;
|
||||
const int TDE_FOOTER = 2;
|
||||
const int TDE_MAIN_INSTRUCTION = 3;
|
||||
const int TDN_CREATED = 0;
|
||||
const int TDN_NAVIGATED = 1;
|
||||
const int TDN_BUTTON_CLICKED = 2;
|
||||
const int TDN_HYPERLINK_CLICKED = 3;
|
||||
const int TDN_TIMER = 4;
|
||||
const int TDN_DESTROYED = 5;
|
||||
const int TDN_RADIO_BUTTON_CLICKED = 6;
|
||||
const int TDN_DIALOG_CONSTRUCTED = 7;
|
||||
const int TDN_VERIFICATION_CLICKED = 8;
|
||||
const int TDN_HELP = 9;
|
||||
const int TDN_EXPANDO_BUTTON_CLICKED = 10;
|
||||
const int TDM_NAVIGATE_PAGE = 1125;
|
||||
const int TDM_CLICK_BUTTON = 1126;
|
||||
const int TDM_SET_MARQUEE_PROGRESS_BAR = 1127;
|
||||
const int TDM_SET_PROGRESS_BAR_STATE = 1128;
|
||||
const int TDM_SET_PROGRESS_BAR_RANGE = 1129;
|
||||
const int TDM_SET_PROGRESS_BAR_POS = 1130;
|
||||
const int TDM_SET_PROGRESS_BAR_MARQUEE = 1131;
|
||||
const int TDM_SET_ELEMENT_TEXT = 1132;
|
||||
const int TDM_CLICK_RADIO_BUTTON = 1134;
|
||||
const int TDM_ENABLE_BUTTON = 1135;
|
||||
const int TDM_ENABLE_RADIO_BUTTON = 1136;
|
||||
const int TDM_CLICK_VERIFICATION = 1137;
|
||||
const int TDM_UPDATE_ELEMENT_TEXT = 1138;
|
||||
const int TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE = 1139;
|
||||
const int TDM_UPDATE_ICON = 1140;
|
||||
|
||||
public TaskDialog()
|
||||
{
|
||||
IdValueDic = new Dictionary<int, T>();
|
||||
IdTextDic = new Dictionary<int, string>();
|
||||
CommandLinkShieldList = new List<int>();
|
||||
Buttons = new List<TaskDialogNative.TASKDIALOG_BUTTON>();
|
||||
RadioButtons = new List<TaskDialogNative.TASKDIALOG_BUTTON>();
|
||||
_SelectedID = -1;
|
||||
Config = new TaskDialogNative.TASKDIALOGCONFIG();
|
||||
Config.cbSize = (uint)Marshal.SizeOf(Config);
|
||||
Config.hwndParent = GetHandle();
|
||||
Config.hInstance = IntPtr.Zero;
|
||||
Config.dwFlags = TaskDialogNative.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION;
|
||||
Config.dwCommonButtons = MsgButtons.None;
|
||||
Config.MainIcon = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION(0);
|
||||
Config.FooterIcon = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION(0);
|
||||
Config.cxWidth = 0U;
|
||||
Config.cButtons = 0U;
|
||||
Config.cRadioButtons = 0U;
|
||||
Config.pButtons = IntPtr.Zero;
|
||||
Config.pRadioButtons = IntPtr.Zero;
|
||||
Config.nDefaultButton = 0;
|
||||
Config.nDefaultRadioButton = 0;
|
||||
Config.pszWindowTitle = ((AssemblyProductAttribute)Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), true)[0]).Product;
|
||||
Config.pszMainInstruction = "";
|
||||
Config.pszContent = "";
|
||||
Config.pfCallback = new PFTASKDIALOGCALLBACK(this.DialogProc);
|
||||
}
|
||||
|
||||
public IntPtr GetHandle()
|
||||
{
|
||||
StringBuilder lpszFileName = new StringBuilder(260);
|
||||
IntPtr foregroundWindow = TaskDialogNative.GetForegroundWindow();
|
||||
TaskDialogNative.GetWindowModuleFileName(foregroundWindow, lpszFileName, 260U);
|
||||
|
||||
if (Path.GetFileName(lpszFileName.ToString().Replace(".vshost", "")) ==
|
||||
Path.GetFileName(Assembly.GetEntryAssembly().Location))
|
||||
|
||||
return foregroundWindow;
|
||||
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
public bool AllowCancel {
|
||||
set {
|
||||
if (value)
|
||||
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION;
|
||||
else
|
||||
Config.dwFlags ^= TaskDialogNative.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION;
|
||||
}
|
||||
}
|
||||
|
||||
public string MainInstruction {
|
||||
get => Config.pszMainInstruction;
|
||||
set => Config.pszMainInstruction = value;
|
||||
}
|
||||
|
||||
public string Content {
|
||||
get => Config.pszContent;
|
||||
set => Config.pszContent = ExpandMarkdownMarkup(value);
|
||||
}
|
||||
|
||||
public string ExpandedInformation {
|
||||
get => Config.pszExpandedInformation;
|
||||
set => Config.pszExpandedInformation = ExpandMarkdownMarkup(value);
|
||||
}
|
||||
|
||||
public string VerificationText {
|
||||
get => Config.pszVerificationText;
|
||||
set => Config.pszVerificationText = value;
|
||||
}
|
||||
|
||||
public MsgResult DefaultButton {
|
||||
get => (MsgResult)Config.nDefaultButton;
|
||||
set => Config.nDefaultButton = (int)value;
|
||||
}
|
||||
|
||||
public string Footer {
|
||||
get => Config.pszFooter;
|
||||
set => Config.pszFooter = ExpandMarkdownMarkup(value);
|
||||
}
|
||||
|
||||
public MsgIcon MainIcon {
|
||||
set => Config.MainIcon = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION((int)value);
|
||||
}
|
||||
|
||||
int _SelectedID;
|
||||
|
||||
public int SelectedID {
|
||||
get => _SelectedID;
|
||||
set {
|
||||
foreach (var i in IdValueDic)
|
||||
if (i.Key == value)
|
||||
_SelectedID = value;
|
||||
}
|
||||
}
|
||||
|
||||
public T SelectedValue {
|
||||
get {
|
||||
if (IdValueDic.ContainsKey(SelectedID))
|
||||
return IdValueDic[SelectedID];
|
||||
|
||||
return SelectedValueValue;
|
||||
}
|
||||
set => SelectedValueValue = value;
|
||||
}
|
||||
|
||||
public string SelectedText {
|
||||
get {
|
||||
if (IdTextDic.ContainsKey(SelectedID))
|
||||
return IdTextDic[SelectedID];
|
||||
|
||||
return SelectedTextValue;
|
||||
}
|
||||
set => SelectedTextValue = value;
|
||||
}
|
||||
|
||||
public bool CheckBoxChecked {
|
||||
get => (Config.dwFlags & TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED)
|
||||
== TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED;
|
||||
set {
|
||||
if (value)
|
||||
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED;
|
||||
else
|
||||
Config.dwFlags ^= TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED;
|
||||
}
|
||||
}
|
||||
|
||||
public MsgButtons CommonButtons {
|
||||
get => Config.dwCommonButtons;
|
||||
set => Config.dwCommonButtons = value;
|
||||
}
|
||||
|
||||
public int Timeout {
|
||||
get => Convert.ToInt32(TimeoutValue / 1000.0);
|
||||
set {
|
||||
TimeoutValue = value * 1000;
|
||||
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_CALLBACK_TIMER;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddButton(string text, T value)
|
||||
{
|
||||
int n = 1000 + IdValueDic.Count + 1;
|
||||
IdValueDic[n] = value;
|
||||
Buttons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
|
||||
}
|
||||
|
||||
public string ExpandMarkdownMarkup(string value)
|
||||
{
|
||||
if (value.Contains("["))
|
||||
{
|
||||
Regex regex = new Regex(@"\[(.+)\]\((.+)\)");
|
||||
|
||||
if (regex.Match(value).Success)
|
||||
{
|
||||
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_ENABLE_HYPERLINKS;
|
||||
value = regex.Replace(value, "<a href=\"$2\">$1</a>");
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public void AddCommand(string text)
|
||||
{
|
||||
object obj = text;
|
||||
AddCommand(text, (T)obj);
|
||||
}
|
||||
|
||||
public void AddCommand(string text, T value)
|
||||
{
|
||||
int n = 1000 + IdValueDic.Count + 1;
|
||||
IdValueDic[n] = value;
|
||||
IdTextDic[n] = text;
|
||||
Buttons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
|
||||
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS;
|
||||
}
|
||||
|
||||
public void AddCommand(string text, string description, T value, bool setShield = false)
|
||||
{
|
||||
int n = 1000 + IdValueDic.Count + 1;
|
||||
IdValueDic[n] = value;
|
||||
|
||||
if (setShield)
|
||||
CommandLinkShieldList.Add(n);
|
||||
|
||||
if (!string.IsNullOrEmpty(description))
|
||||
text += "\n" + description;
|
||||
|
||||
Buttons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
|
||||
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS;
|
||||
}
|
||||
|
||||
public void AddRadioButton(string text, T value)
|
||||
{
|
||||
int n = 1000 + IdValueDic.Count + 1;
|
||||
IdValueDic[n] = value;
|
||||
RadioButtons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
|
||||
}
|
||||
|
||||
public T Show()
|
||||
{
|
||||
MarshalDialogControlStructs();
|
||||
TaskDialogNative.TASKDIALOGCONFIG config = Config;
|
||||
int hr = TaskDialogNative.TaskDialogIndirect(
|
||||
config, out int dummy1, out int dummy2, out bool isChecked);
|
||||
|
||||
if (hr < 0)
|
||||
Marshal.ThrowExceptionForHR(hr);
|
||||
|
||||
CheckBoxChecked = isChecked;
|
||||
|
||||
if (SelectedValue is MsgResult)
|
||||
SelectedValue = (T)(object)SelectedID;
|
||||
|
||||
return SelectedValue;
|
||||
}
|
||||
|
||||
public int DialogProc(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam, IntPtr lpRefData)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case 0: //TDN_CREATED
|
||||
foreach (var i in CommandLinkShieldList)
|
||||
SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, new IntPtr(i), new IntPtr(1));
|
||||
break;
|
||||
case 2: //TDN_BUTTON_CLICKED
|
||||
case 6: //TDN_RADIO_BUTTON_CLICKED
|
||||
if (SelectedValue is MsgResult)
|
||||
_SelectedID = wParam.ToInt32();
|
||||
else
|
||||
SelectedID = wParam.ToInt32();
|
||||
break;
|
||||
case 3: //TDN_HYPERLINK_CLICKED
|
||||
string stringUni = Marshal.PtrToStringUni(lParam);
|
||||
|
||||
if (stringUni.StartsWith("mailto") || stringUni.StartsWith("http"))
|
||||
Process.Start(stringUni);
|
||||
|
||||
if (stringUni == "copymsg")
|
||||
{
|
||||
Thread thread = new Thread((ThreadStart)(() => {
|
||||
Clipboard.SetText(MainInstruction + "\r\n\r\n" + Content + "\r\n\r\n" + ExpandedInformation);
|
||||
MessageBox.Show("Message was copied to clipboard.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}));
|
||||
thread.SetApartmentState(ApartmentState.STA);
|
||||
thread.Start();
|
||||
}
|
||||
break;
|
||||
case 4: //TDN_TIMER
|
||||
if (ExitTickCount == 0) ExitTickCount = Environment.TickCount + Timeout * 1000;
|
||||
if (Environment.TickCount > ExitTickCount)
|
||||
TaskDialogNative.SendMessage(hwnd, 1126, new IntPtr(1), IntPtr.Zero);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void MarshalDialogControlStructs()
|
||||
{
|
||||
if (Buttons != null && Buttons.Count > 0)
|
||||
{
|
||||
ButtonArray = AllocateAndMarshalButtons(Buttons);
|
||||
Config.pButtons = ButtonArray;
|
||||
Config.cButtons = (uint)Buttons.Count;
|
||||
}
|
||||
|
||||
if (RadioButtons == null || RadioButtons.Count <= 0)
|
||||
return;
|
||||
|
||||
RadioButtonArray = AllocateAndMarshalButtons(RadioButtons);
|
||||
Config.pRadioButtons = RadioButtonArray;
|
||||
Config.cRadioButtons = (uint)RadioButtons.Count;
|
||||
}
|
||||
|
||||
public static IntPtr AllocateAndMarshalButtons(List<TASKDIALOG_BUTTON> structs)
|
||||
{
|
||||
var initialPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(TASKDIALOG_BUTTON)) * structs.Count);
|
||||
var currentPtr = initialPtr;
|
||||
|
||||
foreach (var button in structs)
|
||||
{
|
||||
Marshal.StructureToPtr(button, currentPtr, false);
|
||||
currentPtr = (IntPtr)(currentPtr.ToInt64() + Marshal.SizeOf(button));
|
||||
}
|
||||
|
||||
return initialPtr;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~TaskDialog()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
protected void Dispose(bool disposing)
|
||||
{
|
||||
if (Disposed)
|
||||
return;
|
||||
|
||||
Disposed = true;
|
||||
|
||||
if (ButtonArray != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(ButtonArray);
|
||||
ButtonArray = IntPtr.Zero;
|
||||
}
|
||||
|
||||
if (RadioButtonArray != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(RadioButtonArray);
|
||||
RadioButtonArray = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public delegate int PFTASKDIALOGCALLBACK(
|
||||
IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam, IntPtr lpRefData);
|
||||
|
||||
public class TaskDialogNative
|
||||
{
|
||||
[DllImport("comctl32", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern int TaskDialogIndirect(
|
||||
TaskDialogNative.TASKDIALOGCONFIG pTaskConfig,
|
||||
out int pnButton,
|
||||
out int pnRadioButton,
|
||||
out bool pVerificationFlagChecked);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern IntPtr GetForegroundWindow();
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern uint GetWindowModuleFileName(
|
||||
IntPtr hwnd, StringBuilder lpszFileName, uint cchFileNameMax);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern IntPtr SendMessage(
|
||||
IntPtr handle, int message, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
|
||||
public class TASKDIALOGCONFIG
|
||||
{
|
||||
public uint cbSize;
|
||||
public IntPtr hwndParent;
|
||||
public IntPtr hInstance;
|
||||
public TaskDialogNative.TASKDIALOG_FLAGS dwFlags;
|
||||
public MsgButtons dwCommonButtons;
|
||||
public string pszWindowTitle;
|
||||
public TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION MainIcon;
|
||||
public string pszMainInstruction;
|
||||
public string pszContent;
|
||||
public uint cButtons;
|
||||
public IntPtr pButtons;
|
||||
public int nDefaultButton;
|
||||
public uint cRadioButtons;
|
||||
public IntPtr pRadioButtons;
|
||||
public int nDefaultRadioButton;
|
||||
public string pszVerificationText;
|
||||
public string pszExpandedInformation;
|
||||
public string pszExpandedControlText;
|
||||
public string pszCollapsedControlText;
|
||||
public TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION FooterIcon;
|
||||
public string pszFooter;
|
||||
public PFTASKDIALOGCALLBACK pfCallback;
|
||||
public IntPtr lpCallbackData;
|
||||
public uint cxWidth;
|
||||
}
|
||||
|
||||
public enum TASKDIALOG_FLAGS
|
||||
{
|
||||
NONE = 0,
|
||||
TDF_ENABLE_HYPERLINKS = 1,
|
||||
TDF_USE_HICON_MAIN = 2,
|
||||
TDF_USE_HICON_FOOTER = 4,
|
||||
TDF_ALLOW_DIALOG_CANCELLATION = 8,
|
||||
TDF_USE_COMMAND_LINKS = 16,
|
||||
TDF_USE_COMMAND_LINKS_NO_ICON = 32,
|
||||
TDF_EXPAND_FOOTER_AREA = 64,
|
||||
TDF_EXPANDED_BY_DEFAULT = 128,
|
||||
TDF_VERIFICATION_FLAG_CHECKED = 256,
|
||||
TDF_SHOW_PROGRESS_BAR = 512,
|
||||
TDF_SHOW_MARQUEE_PROGRESS_BAR = 1024,
|
||||
TDF_CALLBACK_TIMER = 2048,
|
||||
TDF_POSITION_RELATIVE_TO_WINDOW = 4096,
|
||||
TDF_RTL_LAYOUT = 8192,
|
||||
TDF_NO_DEFAULT_RADIO_BUTTON = 16384,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
|
||||
public struct TASKDIALOGCONFIG_ICON_UNION
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public int hMainIcon;
|
||||
[FieldOffset(0)]
|
||||
public int pszIcon;
|
||||
[FieldOffset(0)]
|
||||
public IntPtr spacer;
|
||||
|
||||
public TASKDIALOGCONFIG_ICON_UNION(int i)
|
||||
{
|
||||
this = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION();
|
||||
spacer = IntPtr.Zero;
|
||||
pszIcon = 0;
|
||||
hMainIcon = i;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
|
||||
public struct TASKDIALOG_BUTTON
|
||||
{
|
||||
public int nButtonID;
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string pszButtonText;
|
||||
|
||||
public TASKDIALOG_BUTTON(int n, string txt)
|
||||
{
|
||||
this = new TaskDialogNative.TASKDIALOG_BUTTON();
|
||||
nButtonID = n;
|
||||
pszButtonText = txt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum MsgButtons
|
||||
{
|
||||
None = 0,
|
||||
Ok = 1,
|
||||
Yes = 2,
|
||||
No = 4,
|
||||
YesNo = 6,
|
||||
Cancel = 8,
|
||||
OkCancel = 9,
|
||||
YesNoCancel = 14,
|
||||
Retry = 16,
|
||||
RetryCancel = 24,
|
||||
Close = 32,
|
||||
}
|
||||
|
||||
public enum MsgResult
|
||||
{
|
||||
None,
|
||||
OK,
|
||||
Cancel,
|
||||
Abort,
|
||||
Retry,
|
||||
Ignore,
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
public enum MsgIcon
|
||||
{
|
||||
None = 0,
|
||||
SecurityShieldGray = 65527,
|
||||
SecuritySuccess = 65528,
|
||||
SecurityError = 65529,
|
||||
SecurityWarning = 65530,
|
||||
SecurityShieldBlue = 65531,
|
||||
Shield = 65532,
|
||||
Info = 65533,
|
||||
Error = 65534,
|
||||
Warning = 65535,
|
||||
}
|
||||
55
src/Native/Taskbar.cs
Normal file
55
src/Native/Taskbar.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public class Taskbar
|
||||
{
|
||||
public IntPtr Handle { get; set; }
|
||||
|
||||
public Taskbar(IntPtr handle) => Handle = handle;
|
||||
|
||||
ITaskbarList3 Instance = (ITaskbarList3)new TaskBarCommunication();
|
||||
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid("EA1AFB91-9E28-4B86-90E9-9E9F8A5EEFAF")]
|
||||
interface ITaskbarList3
|
||||
{
|
||||
// ITaskbarList
|
||||
[PreserveSig] void HrInit();
|
||||
[PreserveSig] void AddTab(IntPtr hwnd);
|
||||
[PreserveSig] void DeleteTab(IntPtr hwnd);
|
||||
[PreserveSig] void ActivateTab(IntPtr hwnd);
|
||||
[PreserveSig] void SetActiveAlt(IntPtr hwnd);
|
||||
// ITaskbarList2
|
||||
[PreserveSig] void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen);
|
||||
// ITaskbarList3
|
||||
[PreserveSig] void SetProgressValue(IntPtr hwnd, ulong ullCompleted, ulong ullTotal);
|
||||
[PreserveSig] void SetProgressState(IntPtr hwnd, TaskbarStates state);
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[ClassInterface(ClassInterfaceType.None)]
|
||||
[Guid("56FDF344-FD6D-11d0-958A-006097C9A090")]
|
||||
class TaskBarCommunication
|
||||
{
|
||||
}
|
||||
|
||||
public void SetState(TaskbarStates taskbarState)
|
||||
{
|
||||
Instance.SetProgressState(Handle, taskbarState);
|
||||
}
|
||||
|
||||
public void SetValue(double progressValue, double progressMax)
|
||||
{
|
||||
Instance.SetProgressValue(Handle, (ulong)progressValue, (ulong)progressMax);
|
||||
}
|
||||
}
|
||||
|
||||
public enum TaskbarStates
|
||||
{
|
||||
NoProgress = 0,
|
||||
Indeterminate = 0x1,
|
||||
Normal = 0x2,
|
||||
Error = 0x4,
|
||||
Paused = 0x8
|
||||
}
|
||||
Reference in New Issue
Block a user