/* * Copyright (c) 2007-2009 SlimDX Group * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (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: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * 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 THE * AUTHORS OR COPYRIGHT HOLDERS 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. */ using System; using System.ComponentModel; using System.Drawing; using System.IO; using System.Reflection; using System.Security.Permissions; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Diagnostics; using SampleFramework.Properties; namespace SampleFramework { /// /// Implements a specialized window for games and rendering. /// public class GameWindow : Form { const int DefaultWidth = 800; const int DefaultHeight = 600; const string DefaultTitle = "Game"; Size cachedSize; bool minimized; bool maximized; bool inSizeMove; /// /// Occurs when the application is suspended. /// public event EventHandler Suspend; /// /// Occurs when the application is resumed. /// public event EventHandler Resume; /// /// Occurs when the user resizes the window. /// public event EventHandler UserResized; /// /// Occurs when the screen on which the window resides is changed. /// public event EventHandler ScreenChanged; /// /// Occurs when the application is activated. /// public event EventHandler ApplicationActivated; /// /// Occurs when the application is deactivated. /// public event EventHandler ApplicationDeactivated; /// /// Occurs when the system is suspended. /// public event EventHandler SystemSuspend; /// /// Occurs when the system is resumed. /// public event EventHandler SystemResume; /// /// Occurs when a screen saver is about to be activated. /// public event CancelEventHandler Screensaver; /// /// Gets a value indicating whether this instance is minimized. /// /// /// true if this instance is minimized; otherwise, false. /// public bool IsMinimized { get { return minimized; } } /// /// Gets a value indicating whether this instance is maximized. /// /// /// true if this instance is maximized; otherwise, false. /// public bool IsMaximized { get { return maximized; } } /// /// Gets or sets a value indicating whether System Menu is enabled. /// /// true if System Menu is enabled; otherwise, false. public bool EnableSystemMenu // #28200 2012.5.1 yyagi { get; set; } public string strMessage // #28821 2014.1.23 yyagi { get; private set; } public bool IsReceivedMessage { get; set; } private Screen m_Screen; /// /// Gets the screen on which the window resides. /// /// The screen. public Screen Screen { get { return m_Screen; } private set { m_Screen = value; } } /// /// Initializes a new instance of the class. /// public GameWindow() { MinimumSize = new Size(200, 200); Screen = ScreenFromHandle(Handle); //Icon = GetDefaultIcon(); Text = GetDefaultTitle(); strMessage = ""; } /// /// Raises the event. /// /// The instance containing the event data. protected virtual void OnSuspend(EventArgs e) { if (Suspend != null) Suspend(this, e); } /// /// Raises the event. /// /// The instance containing the event data. protected virtual void OnResume(EventArgs e) { if (Resume != null) Resume(this, e); } /// /// Raises the event. /// /// The instance containing the event data. protected virtual void OnUserResized(EventArgs e) { if (UserResized != null) UserResized(this, e); } /// /// Raises the event. /// /// The instance containing the event data. protected virtual void OnScreenChanged(EventArgs e) { if (ScreenChanged != null) ScreenChanged(this, e); } /// /// Raises the event. /// /// The instance containing the event data. protected virtual void OnApplicationActivated(EventArgs e) { if (ApplicationActivated != null) ApplicationActivated(this, e); } /// /// Raises the event. /// /// The instance containing the event data. protected virtual void OnApplicationDeactivated(EventArgs e) { if (ApplicationDeactivated != null) ApplicationDeactivated(this, e); } /// /// Raises the event. /// /// The instance containing the event data. protected virtual void OnSystemSuspend(EventArgs e) { if (SystemSuspend != null) SystemSuspend(this, e); } /// /// Raises the event. /// /// The instance containing the event data. protected virtual void OnSystemResume(EventArgs e) { if (SystemResume != null) SystemResume(this, e); } /// /// Raises the event. /// /// The instance containing the event data. protected virtual void OnScreensaver(CancelEventArgs e) { if (Screensaver != null) Screensaver(this, e); } /// /// Raises the event. /// /// An that contains the event data. protected override void OnLoad(EventArgs e) { base.OnLoad(e); cachedSize = Size; } /// /// Raises the event. /// /// A that contains the event data. protected override void OnResizeBegin(EventArgs e) { base.OnResizeBegin(e); // suspend any processing until we are done being minimized inSizeMove = true; cachedSize = Size; OnSuspend(EventArgs.Empty); } /// /// Raises the event. /// /// A that contains the event data. protected override void OnResizeEnd(EventArgs e) { base.OnResizeEnd(e); // check for screen and size changes OnUserResized(EventArgs.Empty); UpdateScreen(); inSizeMove = false; // resume application processing OnResume(EventArgs.Empty); } #region #23510 2010.11.14 yyagi add: 縦横比固定でのウインドウサイズ変更 定数定義 from http://www.vcskicks.com/maintain-aspect-ratio.php //double so division keeps decimal points const double widthRatio = SampleFramework.GameWindowSize.Width; const double heightRatio = SampleFramework.GameWindowSize.Height; const int WM_SIZING = 0x214; const int WMSZ_LEFT = 1; const int WMSZ_RIGHT = 2; const int WMSZ_TOP = 3; const int WMSZ_TOPLEFT = 4; const int WMSZ_TOPRIGHT = 5; const int WMSZ_BOTTOM = 6; const int WMSZ_BOTTOMLEFT = 7; const int WMSZ_BOTTOMRIGHT = 8; public struct RECT { public int Left; public int Top; public int Right; public int Bottom; } #endregion /// /// Handles raw window messages. /// /// The raw message. [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] protected override void WndProc(ref Message m) { if (m.Msg == WindowConstants.WM_SIZE) { if (m.WParam == WindowConstants.SIZE_MINIMIZED) { minimized = true; maximized = false; OnSuspend(EventArgs.Empty); } else { Rectangle client = NativeMethods.GetClientRectangle(m.HWnd); if (client.Height == 0) { // rapidly clicking the task bar to minimize and restore a window // can cause a WM_SIZE message with SIZE_RESTORED when // the window has actually become minimized due to rapid change // so just ignore this message } else if (m.WParam == WindowConstants.SIZE_MAXIMIZED) { if (minimized) OnResume(EventArgs.Empty); minimized = false; maximized = true; OnUserResized(EventArgs.Empty); UpdateScreen(); } else if (m.WParam == WindowConstants.SIZE_RESTORED) { if (minimized) OnResume(EventArgs.Empty); minimized = false; maximized = false; if (!inSizeMove && Size != cachedSize) { OnUserResized(EventArgs.Empty); UpdateScreen(); cachedSize = Size; } } } } else if (m.Msg == WindowConstants.WM_ACTIVATEAPP) { if (m.WParam != IntPtr.Zero) OnApplicationActivated(EventArgs.Empty); else OnApplicationDeactivated(EventArgs.Empty); } else if (m.Msg == WindowConstants.WM_POWERBROADCAST) { if (m.WParam == WindowConstants.PBT_APMQUERYSUSPEND) { OnSystemSuspend(EventArgs.Empty); m.Result = (IntPtr)1; return; } else if (m.WParam == WindowConstants.PBT_APMRESUMESUSPEND) { OnSystemResume(EventArgs.Empty); m.Result = (IntPtr)1; return; } } else if (m.Msg == WindowConstants.WM_SYSCOMMAND) { long wparam = m.WParam.ToInt64() & 0xFFF0; if (wparam == WindowConstants.SC_MONITORPOWER || wparam == WindowConstants.SC_SCREENSAVE) { CancelEventArgs e = new CancelEventArgs(); OnScreensaver(e); if (e.Cancel) { m.Result = IntPtr.Zero; return; } } #region #28200 2012.5.1 yyagi: Disable system menu if ((m.WParam.ToInt32() & 0xFFFF) == 0xF100 && !EnableSystemMenu) // SC_KEYMENU { m.Result = IntPtr.Zero; return; } #endregion #region #23510 2010.11.13 yyagi: reset to 640x480 if ((m.WParam.ToInt32() & 0xFFFF) == MENU_VIEW) { base.ClientSize = new Size(SampleFramework.GameWindowSize.Width, SampleFramework.GameWindowSize.Height); this.OnResizeEnd(new EventArgs()); // #23510 2010.11.20 yyagi: to set window size to Config.ini } else if ((m.WParam.ToInt32() & 0xFFFF) == MENU_VIEW - 1) { base.ClientSize = new Size(1280, 720); this.OnResizeEnd(new EventArgs()); // #23510 2010.11.20 yyagi: to set window size to Config.ini } else if ((m.WParam.ToInt32() & 0xFFFF) == MENU_VIEW - 2) { base.ClientSize = new Size(896, 504); this.OnResizeEnd(new EventArgs()); // #23510 2010.11.20 yyagi: to set window size to Config.ini } else if ((m.WParam.ToInt32() & 0xFFFF) == MENU_VIEW - 3) { base.ClientSize = new Size(640, 480); this.OnResizeEnd(new EventArgs()); // #23510 2010.11.20 yyagi: to set window size to Config.ini } #endregion } #region #28821 2014.1.23 yyagi (WM_COPYDATA) else if (m.Msg == WindowConstants.WM_COPYDATA) { //Trace.WriteLine( "FDK;msg received" ); COPYDATASTRUCT cds = (COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT)); strMessage = Marshal.PtrToStringUni(cds.lpData); IsReceivedMessage = true; //Trace.WriteLine( "FDK;msg=" + strMessage + ", len=" + strMessage.Length + ", truelen=" + cds.cbData ); } #endregion #region #23510 2010.11.16 yyagi add: 縦横比固定でのウインドウサイズ変更 from http://d.hatena.ne.jp/iselix/20080917/1221666614 http://hp.vector.co.jp/authors/VA016117/sizing.html else if (m.Msg == WM_SIZING) { RECT rc = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT)); int w = rc.Right - rc.Left - (Size.Width - ClientSize.Width); int h = rc.Bottom - rc.Top - (Size.Height - ClientSize.Height); int dw = (int)(h * widthRatio / heightRatio + 0.5) - w; int dh = (int)(w / (widthRatio / heightRatio) + 0.5) - h; switch (m.WParam.ToInt32()) { case WMSZ_LEFT: case WMSZ_RIGHT: rc.Bottom += dh; break; case WMSZ_TOP: case WMSZ_BOTTOM: rc.Right += dw; break; case WMSZ_BOTTOMRIGHT: if (dw > 0) { rc.Right += dw; } else { rc.Bottom += dh; } break; case WMSZ_TOPLEFT: if (dw > 0) { rc.Left -= dw; } else { rc.Top -= dh; } break; case WMSZ_TOPRIGHT: if (dw > 0) { rc.Right += dw; } else { rc.Top -= dh; } break; case WMSZ_BOTTOMLEFT: if (dw > 0) { rc.Left -= dw; } else { rc.Bottom += dh; } break; case 9: // #32383 2013.11.2 yyagi; exitting maximized window by using Aero snap break; default: throw new ArgumentOutOfRangeException("value", "Illegal WM_SIZING value."); } Marshal.StructureToPtr(rc, m.LParam, true); } #endregion base.WndProc(ref m); } void UpdateScreen() { Screen current = Screen.FromHandle(Handle); if (Screen == null || Screen.DeviceName != current.DeviceName) { Screen = current; if (Screen != null) OnScreenChanged(EventArgs.Empty); } } static Screen ScreenFromHandle(IntPtr windowHandle) { Rectangle rectangle = NativeMethods.GetWindowRectangle(windowHandle); Screen bestScreen = null; int mostArea = 0; foreach (Screen screen in Screen.AllScreens) { Rectangle r = Rectangle.Intersect(rectangle, screen.Bounds); int area = r.Width * r.Height; if (area > mostArea) { mostArea = area; bestScreen = screen; } } if (bestScreen == null) bestScreen = Screen.PrimaryScreen; return bestScreen; } static string GetAssemblyTitle(Assembly assembly) { if (assembly == null) return null; AssemblyTitleAttribute[] customAttributes = (AssemblyTitleAttribute[])assembly.GetCustomAttributes(typeof(AssemblyTitleAttribute), true); if (customAttributes != null && customAttributes.Length > 0) return customAttributes[0].Title; return null; } static string GetDefaultTitle() { string assemblyTitle = GetAssemblyTitle(Assembly.GetEntryAssembly()); if (!string.IsNullOrEmpty(assemblyTitle)) return assemblyTitle; try { Uri uri = new Uri(Application.ExecutablePath); return Path.GetFileNameWithoutExtension(uri.LocalPath); } catch (ArgumentNullException) { // swallow the exception } catch (UriFormatException) { // swallow the exception } return DefaultTitle; } static Icon GetDefaultIcon() { return (Icon)Resources.sdx_icon_black.Clone(); } #region システムメニューに"1920x1080", "1280x720", "640x480" を追加 #23510 2010.11.13 yyagi add: to set "1920x1020","1280x720","640x480" menu in systemmenu. See also http://cs2ch.blog123.fc2.com/blog-entry-80.html [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct MENUITEMINFO { public uint cbSize; public uint fMask; public uint fType; public uint fState; public uint wID; public IntPtr hSubMenu; public IntPtr hbmpChecked; public IntPtr hbmpUnchecked; public IntPtr dwItemData; public string dwTypeData; public uint cch; public IntPtr hbmpItem; } [DllImport("user32", ExactSpelling = true)] private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); [DllImport("user32", CharSet = CharSet.Auto)] private static extern bool InsertMenuItem(IntPtr hMenu, uint uItem, bool fByPosition, ref MENUITEMINFO lpmii); private const uint MENU_VIEW = 0x9999; private const uint MFT_SEPARATOR = 0x00000800; private const uint MIIM_FTYPE = 0x00000100; private const uint MIIM_STRING = 0x00000040; private const uint MIIM_ID = 0x00000002; protected override void OnCreateControl() { base.OnCreateControl(); //システムメニューのハンドル取得 IntPtr hSysMenu = GetSystemMenu(this.Handle, false); //セパレーターの挿入 MENUITEMINFO item1 = new MENUITEMINFO(); item1.cbSize = (uint)Marshal.SizeOf(item1); item1.fMask = MIIM_FTYPE; item1.fType = MFT_SEPARATOR; InsertMenuItem(hSysMenu, 5, true, ref item1); //メニュー項目(1920x1080)の挿入 MENUITEMINFO item2 = new MENUITEMINFO(); item2.cbSize = (uint)Marshal.SizeOf(item2); item2.fMask = MIIM_STRING | MIIM_ID; item2.wID = MENU_VIEW; item2.dwTypeData = "&" + SampleFramework.GameWindowSize.Width.ToString() + "x" + SampleFramework.GameWindowSize.Height.ToString(); InsertMenuItem(hSysMenu, 6, true, ref item2); //メニュー項目(1280x720)の挿入 MENUITEMINFO item3 = new MENUITEMINFO(); item3.cbSize = (uint)Marshal.SizeOf(item3); item3.fMask = MIIM_STRING | MIIM_ID; item3.wID = MENU_VIEW - 1; item3.dwTypeData = "&1280x720"; InsertMenuItem(hSysMenu, 6, true, ref item3); //メニュー項目(896x504)の挿入 MENUITEMINFO item4 = new MENUITEMINFO(); item4.cbSize = (uint)Marshal.SizeOf(item4); item4.fMask = MIIM_STRING | MIIM_ID; item4.wID = MENU_VIEW - 2; item4.dwTypeData = "&896x504"; InsertMenuItem(hSysMenu, 6, true, ref item4); //メニュー項目(640x480)の挿入 MENUITEMINFO item5 = new MENUITEMINFO(); item5.cbSize = (uint)Marshal.SizeOf(item4); item5.fMask = MIIM_STRING | MIIM_ID; item5.wID = MENU_VIEW - 3; item5.dwTypeData = "&640x480"; InsertMenuItem(hSysMenu, 6, true, ref item5); } #endregion private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GameWindow)); this.SuspendLayout(); // // GameWindow // resources.ApplyResources(this, "$this"); this.Name = "GameWindow"; this.ResumeLayout(false); } } }