Aegisub/devel/SSATool/SaveFileDialogWithEncoding.cs

347 lines
10 KiB
C#

using System;
using System.Collections;
using System.Windows.Forms;
using System.Data;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
public enum EncodingType {
//UTF8=0,
//UTF8WithPreamble,
//Unicode,
//Ansi
ANSI,
BigEndianUnicode,
Unicode,
UTF8,
Shift_JIS
};
public class SaveFileDialogWithEncoding {
private delegate int OFNHookProcDelegate(int hdlg, int msg, int wParam, int lParam);
private int m_LabelHandle=0;
private int m_ComboHandle=0;
private string m_Filter="";
private string m_DefaultExt="";
private string m_FileName="";
private EncodingType m_EncodingType;
private Screen m_ActiveScreen;
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
private struct OPENFILENAME {
public int lStructSize;
public IntPtr hwndOwner;
public int hInstance;
[MarshalAs(UnmanagedType.LPTStr)] public string lpstrFilter;
[MarshalAs(UnmanagedType.LPTStr)] public string lpstrCustomFilter;
public int nMaxCustFilter;
public int nFilterIndex;
[MarshalAs(UnmanagedType.LPTStr)] public string lpstrFile;
public int nMaxFile;
[MarshalAs(UnmanagedType.LPTStr)] public string lpstrFileTitle;
public int nMaxFileTitle;
[MarshalAs(UnmanagedType.LPTStr)] public string lpstrInitialDir;
[MarshalAs(UnmanagedType.LPTStr)] public string lpstrTitle;
public int Flags;
public short nFileOffset;
public short nFileExtension;
[MarshalAs(UnmanagedType.LPTStr)] public string lpstrDefExt;
public int lCustData;
public OFNHookProcDelegate lpfnHook;
[MarshalAs(UnmanagedType.LPTStr)] public string lpTemplateName;
//only if on nt 5.0 or higher
public int pvReserved;
public int dwReserved;
public int FlagsEx;
}
[DllImport("Comdlg32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern bool GetSaveFileName(ref OPENFILENAME lpofn);
[DllImport("Comdlg32.dll")]
private static extern int CommDlgExtendedError();
[DllImport("user32.dll")]
private static extern bool SetWindowPos(int hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
private struct RECT {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
private struct POINT {
public int X;
public int Y;
}
private struct NMHDR {
public int HwndFrom;
public int IdFrom;
public int Code;
}
[DllImport("user32.dll")]
private static extern bool GetWindowRect(int hWnd, ref RECT lpRect);
[DllImport("user32.dll")]
private static extern int GetParent(int hWnd);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern bool SetWindowText(int hWnd, string lpString);
[DllImport("user32.dll")]
private static extern int SendMessage(int hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern int SendMessage(int hWnd, int Msg, int wParam, string lParam);
[DllImport("user32.dll")]
private static extern bool DestroyWindow(int hwnd);
private const int OFN_ENABLEHOOK=0x00000020;
private const int OFN_EXPLORER=0x00080000;
private const int OFN_FILEMUSTEXIST=0x00001000;
private const int OFN_HIDEREADONLY=0x00000004;
private const int OFN_CREATEPROMPT=0x00002000;
private const int OFN_NOTESTFILECREATE=0x00010000;
private const int OFN_OVERWRITEPROMPT=0x00000002;
private const int OFN_PATHMUSTEXIST=0x00000800;
private const int SWP_NOSIZE=0x0001;
private const int SWP_NOMOVE=0x0002;
private const int SWP_NOZORDER=0x0004;
private const int WM_INITDIALOG=0x110;
private const int WM_DESTROY=0x2;
private const int WM_SETFONT=0x0030;
private const int WM_GETFONT=0x0031;
private const int CBS_DROPDOWNLIST=0x0003;
private const int CBS_HASSTRINGS=0x0200;
private const int CB_ADDSTRING=0x0143;
private const int CB_SETCURSEL=0x014E;
private const int CB_GETCURSEL=0x0147;
private const uint WS_VISIBLE=0x10000000;
private const uint WS_CHILD=0x40000000;
private const uint WS_TABSTOP=0x00010000;
private const int CDN_FILEOK=-606;
private const int WM_NOTIFY=0x004E;
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern int GetDlgItem(int hDlg, int nIDDlgItem);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern int CreateWindowEx(int dwExStyle, string lpClassName, string lpWindowName, uint dwStyle, int x, int y, int nWidth, int nHeight, int hWndParent, int hMenu, int hInstance, int lpParam);
[DllImport("user32.dll")]
private static extern bool ScreenToClient(int hWnd, ref POINT lpPoint);
private int HookProc(int hdlg, int msg, int wParam, int lParam) {
switch (msg) {
case WM_INITDIALOG:
//we need to centre the dialog
Rectangle sr=m_ActiveScreen.Bounds;
RECT cr=new RECT();
int parent=GetParent(hdlg);
GetWindowRect(parent, ref cr);
int x=(sr.Right + sr.Left - (cr.Right-cr.Left))/2;
int y=(sr.Bottom + sr.Top - (cr.Bottom-cr.Top))/2;
SetWindowPos(parent, 0, x, y, cr.Right-cr.Left, cr.Bottom - cr.Top + 32, SWP_NOZORDER);
//we need to find the label to position our new label under
int fileTypeWindow=GetDlgItem(parent, 0x441);
RECT aboveRect=new RECT();
GetWindowRect(fileTypeWindow, ref aboveRect);
//now convert the label's screen co-ordinates to client co-ordinates
POINT point=new POINT();
point.X=aboveRect.Left;
point.Y=aboveRect.Bottom;
ScreenToClient(parent, ref point);
//create the label
int labelHandle=CreateWindowEx(0, "STATIC", "mylabel", WS_VISIBLE | WS_CHILD | WS_TABSTOP, point.X, point.Y + 12, 200, 100, parent, 0, 0, 0);
SetWindowText(labelHandle, "&Encoding:");
int fontHandle=SendMessage(fileTypeWindow, WM_GETFONT, 0, 0);
SendMessage(labelHandle, WM_SETFONT, fontHandle, 0);
//we now need to find the combo-box to position the new combo-box under
int fileComboWindow=GetDlgItem(parent, 0x470);
aboveRect=new RECT();
GetWindowRect(fileComboWindow, ref aboveRect);
point=new POINT();
point.X=aboveRect.Left;
point.Y=aboveRect.Bottom;
ScreenToClient(parent, ref point);
POINT rightPoint=new POINT();
rightPoint.X=aboveRect.Right;
rightPoint.Y=aboveRect.Top;
ScreenToClient(parent, ref rightPoint);
//we create the new combobox
int comboHandle=CreateWindowEx(0, "ComboBox", "mycombobox", WS_VISIBLE | WS_CHILD | CBS_HASSTRINGS | CBS_DROPDOWNLIST | WS_TABSTOP, point.X, point.Y + 8, rightPoint.X-point.X, 100, parent, 0, 0, 0);
SendMessage(comboHandle, WM_SETFONT, fontHandle, 0);
//and add the encodings we want to offer
SendMessage(comboHandle, CB_ADDSTRING, 0, "ANSI");
SendMessage(comboHandle, CB_ADDSTRING, 0, "BigEndianUnicode");
SendMessage(comboHandle, CB_ADDSTRING, 0, "Unicode");
SendMessage(comboHandle, CB_ADDSTRING, 0, "UTF-8");
SendMessage(comboHandle, CB_ADDSTRING, 0, "SJIS");
SendMessage(comboHandle, CB_SETCURSEL, (int)m_EncodingType, 0);
//remember the handles of the controls we have created so we can destroy them after
m_LabelHandle=labelHandle;
m_ComboHandle=comboHandle;
break;
case WM_DESTROY:
//destroy the handles we have created
if (m_ComboHandle!=0) {
DestroyWindow(m_ComboHandle);
}
if (m_LabelHandle!=0) {
DestroyWindow(m_LabelHandle);
}
break;
case WM_NOTIFY:
//we need to intercept the CDN_FILEOK message
//which is sent when the user selects a filename
NMHDR nmhdr=(NMHDR)Marshal.PtrToStructure(new IntPtr(lParam), typeof(NMHDR));
if (nmhdr.Code==CDN_FILEOK) {
//a file has been selected
//we need to get the encoding
m_EncodingType=(EncodingType)SendMessage(m_ComboHandle, CB_GETCURSEL, 0, 0);
}
break;
}
return 0;
}
public string DefaultExt {
get { return m_DefaultExt; }
set { m_DefaultExt=value; }
}
public string Filter {
get { return m_Filter; }
set { m_Filter=value; }
}
public string FileName {
get { return m_FileName; }
set { m_FileName=value; }
}
public EncodingType EncodingType {
get { return m_EncodingType; }
set { m_EncodingType=value; }
}
public DialogResult ShowDialog(IntPtr ownerhwnd, Screen ownerscreen) {
return ShowDialog(ownerhwnd,ownerscreen,"Unicode");
}
public DialogResult ShowDialog(IntPtr ownerhwnd, Screen ownerscreen, string encoding) {
//m_EncodingType = stringToEncodingType(encoding);
//set up the struct and populate it
OPENFILENAME ofn=new OPENFILENAME();
ofn.lStructSize= Marshal.SizeOf( ofn );
ofn.lpstrFilter= m_Filter.Replace('|', '\0') + '\0';
ofn.lpstrFile = m_FileName + new string(' ', 512);
ofn.nMaxFile= ofn.lpstrFile.Length;
ofn.lpstrFileTitle= System.IO.Path.GetFileName(m_FileName) + new string(' ', 512);
ofn.nMaxFileTitle = ofn.lpstrFileTitle.Length;
ofn.lpstrTitle= "Save file as";
ofn.lpstrDefExt=m_DefaultExt;
//position the dialog above the active window
ofn.hwndOwner=ownerhwnd;
//we need to find out the active screen so the dialog box is
//centred on the correct display
m_ActiveScreen=ownerscreen;
//set up some sensible flags
ofn.Flags=OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_NOTESTFILECREATE | OFN_ENABLEHOOK | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
//this is where the hook is set. Note that we can use a C# delegate in place of a C function pointer
ofn.lpfnHook=new OFNHookProcDelegate(HookProc);
//if we're running on Windows 98/ME then the struct is smaller
if (System.Environment.OSVersion.Platform!=PlatformID.Win32NT) {
ofn.lStructSize-=12;
}
//show the dialog
if (!GetSaveFileName(ref ofn)) {
int ret=CommDlgExtendedError();
if (ret!=0) {
throw new ApplicationException("Couldn't show file open dialog - " + ret.ToString());
}
return DialogResult.Cancel;
}
m_FileName=ofn.lpstrFile;
return DialogResult.OK;
}
public static System.Text.Encoding stringToEncodingType(string input) {
unsafe {
switch (input) {
case "ASCII" : return System.Text.Encoding.ASCII;
case "ANSI" : return System.Text.Encoding.GetEncoding(1252);
case "BigEndianUnicode" : return System.Text.Encoding.BigEndianUnicode;
case "SJIS" :
case "Shift_JIS" : return System.Text.Encoding.GetEncoding("shift_jis");
case "UTF8" :
case "UTF-8" : return System.Text.Encoding.UTF8;
case "Unicode" :
default : return System.Text.Encoding.Unicode;
}
}
}
}