OSDN Git Service

使用されていないパラメータを削除 (IDE0060)
[opentween/open-tween.git] / OpenTween / NativeMethods.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2007-2011 kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
3 //           (c) 2008-2011 Moz (@syo68k)
4 //           (c) 2008-2011 takeshik (@takeshik) <http://www.takeshik.org/>
5 //           (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
6 //           (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
7 //           (c) 2011      Egtra (@egtra) <http://dev.activebasic.com/egtra/>
8 //           (c) 2014      kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
9 // All rights reserved.
10 // 
11 // This file is part of OpenTween.
12 // 
13 // This program is free software; you can redistribute it and/or modify it
14 // under the terms of the GNU General public License as published by the Free
15 // Software Foundation; either version 3 of the License, or (at your option)
16 // any later version.
17 // 
18 // This program is distributed in the hope that it will be useful, but
19 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General public License
21 // for more details. 
22 // 
23 // You should have received a copy of the GNU General public License along
24 // with this program. if not, see <http://www.gnu.org/licenses/>, or write to
25 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
26 // Boston, MA 02110-1301, USA.
27
28 using System;
29 using System.ComponentModel;
30 using System.Diagnostics;
31 using System.Linq;
32 using System.Net;
33 using System.Runtime.InteropServices;
34 using System.Threading;
35 using System.Windows.Forms;
36 using System.Text;
37 using OpenTween.Connection;
38
39 namespace OpenTween
40 {
41     internal static class NativeMethods
42     {
43         // 指定されたウィンドウへ、指定されたメッセージを送信します
44         [DllImport("user32.dll")]
45         private extern static IntPtr SendMessage(
46             IntPtr hwnd,
47             SendMessageType wMsg,
48             IntPtr wParam,
49             IntPtr lParam);
50
51         [DllImport("user32.dll")]
52         private extern static IntPtr SendMessage(
53             IntPtr hwnd,
54             SendMessageType wMsg,
55             IntPtr wParam,
56             ref LVITEM lParam);
57
58         // SendMessageで送信するメッセージ
59         private enum SendMessageType : uint
60         {
61             WM_SETREDRAW = 0x000B,               //再描画を許可するかを設定
62             WM_USER = 0x400,                     //ユーザー定義メッセージ
63
64             TCM_FIRST = 0x1300,                  //タブコントロールメッセージ
65             TCM_SETMINTABWIDTH = TCM_FIRST + 49, //タブアイテムの最小幅を設定
66
67             LVM_FIRST = 0x1000,                    //リストビューメッセージ
68             LVM_SETITEMSTATE = LVM_FIRST + 43,     //アイテムの状態を設定
69             LVM_GETSELECTIONMARK = LVM_FIRST + 66, //複数選択時の起点になるアイテムの位置を取得
70             LVM_SETSELECTIONMARK = LVM_FIRST + 67, //複数選択時の起点になるアイテムを設定
71         }
72
73         /// <summary>
74         /// コントロールの再描画を許可するかを設定します
75         /// </summary>
76         /// <param name="control">対象となるコントロール</param>
77         /// <param name="redraw">再描画を許可する場合は true、抑制する場合は false</param>
78         /// <returns>このメッセージを処理する場合、アプリケーションは 0 を返します</returns>
79         public static int SetRedrawState(Control control, bool redraw)
80         {
81             var state = redraw ? new IntPtr(1) : IntPtr.Zero;
82             return (int)SendMessage(control.Handle, SendMessageType.WM_SETREDRAW, state, IntPtr.Zero);
83         }
84
85         /// <summary>
86         /// タブコントロールのアイテムの最小幅を設定します
87         /// </summary>
88         /// <param name="tabControl">対象となるタブコントロール</param>
89         /// <param name="width">アイテムの最小幅。-1 を指定するとデフォルトの幅が使用されます</param>
90         /// <returns>設定前の最小幅</returns>
91         public static int SetMinTabWidth(TabControl tabControl, int width)
92             => (int)SendMessage(tabControl.Handle, SendMessageType.TCM_SETMINTABWIDTH, IntPtr.Zero, (IntPtr)width);
93
94         // 参照: LVITEM structure (Windows)
95         // http://msdn.microsoft.com/en-us/library/windows/desktop/bb774760%28v=vs.85%29.aspx
96         [StructLayout(LayoutKind.Sequential)]
97         [BestFitMapping(false, ThrowOnUnmappableChar = true)]
98         private struct LVITEM
99         {
100             public uint mask;
101             public int iItem;
102             public int iSubItem;
103             public LVIS state;
104             public LVIS stateMask;
105             public string pszText;
106             public int cchTextMax;
107             public int iImage;
108             public IntPtr lParam;
109             public int iIndent;
110             public int iGroupId;
111             public uint cColumns;
112             public uint puColumns;
113             public int piColFmt;
114             public int iGroup;
115         }
116
117         // 参照: List-View Item States (Windows)
118         // http://msdn.microsoft.com/en-us/library/windows/desktop/bb774733%28v=vs.85%29.aspx
119         [Flags]
120         private enum LVIS : uint
121         {
122             SELECTED = 0x02,
123         }
124
125         /// <summary>
126         /// ListView のアイテムを選択された状態にします
127         /// </summary>
128         /// <param name="listView">対象となる ListView</param>
129         /// <param name="index">選択するアイテムのインデックス</param>
130         /// <returns>成功した場合は true、それ以外の場合は false</returns>
131         public static bool SelectItem(ListView listView, int index)
132         {
133             // LVM_SETITEMSTATE では stateMask, state 以外のメンバーは無視される
134             var lvitem = new LVITEM
135             {
136                 stateMask = LVIS.SELECTED,
137                 state = LVIS.SELECTED,
138             };
139
140             var ret = (int)SendMessage(listView.Handle, SendMessageType.LVM_SETITEMSTATE, (IntPtr)index, ref lvitem);
141             return ret != 0;
142         }
143
144         /// <summary>
145         /// ListView の全アイテムを選択された状態にします
146         /// </summary>
147         /// <param name="listView">対象となる ListView</param>
148         /// <returns>成功した場合は true、それ以外の場合は false</returns>
149         public static bool SelectAllItems(ListView listView)
150             => SelectItem(listView, -1 /* all items */);
151
152         #region "画面ブリンク用"
153         public static bool FlashMyWindow(IntPtr hwnd, int flashCount)
154         {
155             var fInfo = new FLASHWINFO();
156             fInfo.cbSize = Convert.ToInt32(Marshal.SizeOf(fInfo));
157             fInfo.hwnd = hwnd;
158             fInfo.dwFlags = (int)FlashSpecification.FlashAll;
159             fInfo.uCount = flashCount;
160             fInfo.dwTimeout = 0;
161
162             return FlashWindowEx(ref fInfo);
163         }
164
165         public enum FlashSpecification : uint
166         {
167             FlashStop = FLASHW_STOP,
168             FlashCaption = FLASHW_CAPTION,
169             FlashTray = FLASHW_TRAY,
170             FlashAll = FLASHW_ALL,
171             FlashTimer = FLASHW_TIMER,
172             FlashTimerNoForeground = FLASHW_TIMERNOFG,
173         }
174         /// http://www.atmarkit.co.jp/fdotnet/dotnettips/723flashwindow/flashwindow.html
175         [DllImport("user32.dll")]
176         [return: MarshalAs(UnmanagedType.Bool)]
177         private static extern bool FlashWindowEx(
178             ref FLASHWINFO FWInfo);
179
180
181         private struct FLASHWINFO
182         {
183             public int cbSize;    // FLASHWINFO構造体のサイズ
184             public IntPtr hwnd;     // 点滅対象のウィンドウ・ハンドル
185             public int dwFlags;   // 以下の「FLASHW_XXX」のいずれか
186             public int uCount;    // 点滅する回数
187             public int dwTimeout; // 点滅する間隔(ミリ秒単位)
188         }
189
190         // 点滅を止める
191         private const int FLASHW_STOP = 0;
192         // タイトルバーを点滅させる
193         private const int FLASHW_CAPTION = 0x1;
194         // タスクバー・ボタンを点滅させる
195         private const int FLASHW_TRAY = 0x2;
196         // タスクバー・ボタンとタイトルバーを点滅させる
197         private const int FLASHW_ALL = 0x3;
198         // FLASHW_STOPが指定されるまでずっと点滅させる
199         private const int FLASHW_TIMER = 0x4;
200         // ウィンドウが最前面に来るまでずっと点滅させる
201         private const int FLASHW_TIMERNOFG = 0xC;
202         #endregion
203
204         [DllImport("user32.dll")]
205         [return: MarshalAs(UnmanagedType.Bool)]
206         public static extern bool ValidateRect(
207             IntPtr hwnd,
208             IntPtr rect);
209
210         #region "selection mark"
211         // 複数選択時の起点になるアイテム (selection mark) の位置を取得する
212         public static int ListView_GetSelectionMark(IntPtr hwndLV)
213             => SendMessage(hwndLV, SendMessageType.LVM_GETSELECTIONMARK, IntPtr.Zero, IntPtr.Zero).ToInt32();
214
215         // 複数選択時の起点になるアイテム (selection mark) を設定する
216         public static void ListView_SetSelectionMark(IntPtr hwndLV, int itemIndex)
217             => SendMessage(hwndLV, SendMessageType.LVM_SETSELECTIONMARK, IntPtr.Zero, (IntPtr)itemIndex);
218         #endregion
219
220         #region "スクリーンセーバー起動中か判定"
221         [DllImport("user32", CharSet = CharSet.Auto)]
222         [return: MarshalAs(UnmanagedType.Bool)]
223         private static extern bool SystemParametersInfo(
224                     int intAction,
225                     int intParam,
226                     [MarshalAs(UnmanagedType.Bool)] ref bool bParam,
227                     int intWinIniFlag);
228         // returns non-zero value if function succeeds
229
230         //スクリーンセーバーが起動中かを取得する定数
231         private const int SPI_GETSCREENSAVERRUNNING = 0x0072;
232
233         public static bool IsScreenSaverRunning()
234         {
235             var isRunning = false;
236             SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref isRunning, 0);
237             return isRunning;
238         }
239         #endregion
240
241         #region "グローバルフック"
242         [DllImport("user32")]
243         private static extern int RegisterHotKey(IntPtr hwnd, int id,
244             int fsModifiers, int vk);
245         [DllImport("user32")]
246         private static extern int UnregisterHotKey(IntPtr hwnd, int id);
247         [DllImport("kernel32", CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
248         private static extern ushort GlobalAddAtom([MarshalAs(UnmanagedType.LPTStr)] string lpString);
249         [DllImport("kernel32")]
250         private static extern ushort GlobalDeleteAtom(ushort nAtom);
251
252         private static int registerCount = 0;
253         // register a global hot key
254         public static int RegisterGlobalHotKey(int hotkeyValue, int modifiers, Form targetForm)
255         {
256             ushort hotkeyID = 0;
257             try
258             {
259                 // use the GlobalAddAtom API to get a unique ID (as suggested by MSDN docs)
260                 registerCount++;
261                 var atomName = Thread.CurrentThread.ManagedThreadId.ToString("X8") + targetForm.Name + registerCount;
262                 hotkeyID = GlobalAddAtom(atomName);
263                 if (hotkeyID == 0)
264                 {
265                     throw new Win32Exception();
266                 }
267
268                 // register the hotkey, throw if any error
269                 if (RegisterHotKey(targetForm.Handle, hotkeyID, modifiers, hotkeyValue) == 0)
270                 {
271                     throw new Win32Exception();
272                 }
273                 return hotkeyID;
274             }
275             catch (Exception)
276             {
277                 // clean up if hotkey registration failed
278                 UnregisterGlobalHotKey(hotkeyID, targetForm);
279                 return 0;
280             }
281         }
282
283         // unregister a global hotkey
284         public static void UnregisterGlobalHotKey(ushort hotkeyID, Form targetForm)
285         {
286             if (hotkeyID != 0)
287             {
288                 UnregisterHotKey(targetForm.Handle, hotkeyID);
289                 // clean up the atom list
290                 GlobalDeleteAtom(hotkeyID);
291             }
292         }
293         #endregion
294
295         #region "プロセスのProxy設定"
296
297         [DllImport("wininet.dll", SetLastError = true)]
298         [return: MarshalAs(UnmanagedType.Bool)]
299         private static extern bool InternetSetOption(IntPtr hInternet,
300             InternetOption dwOption,
301             [In] ref InternetProxyInfo lpBuffer,
302             int lpdwBufferLength);
303
304         private enum InternetOption
305         {
306             PROXY = 38,
307             PROXY_USERNAME = 43,
308             PROXY_PASSWORD = 44,
309         }
310
311         [StructLayout(LayoutKind.Sequential)]
312         [BestFitMapping(false, ThrowOnUnmappableChar = true)]
313         private struct InternetProxyInfo
314         {
315             public InternetOpenType dwAccessType;
316             public string proxy;
317             public string proxyBypass;
318         }
319
320         private enum InternetOpenType
321         {
322             //PRECONFIG = 0, // IE setting
323             DIRECT = 1, // Direct
324             PROXY = 3, // Custom
325         }
326
327         private static void RefreshProxySettings(string strProxy)
328         {
329             InternetProxyInfo ipi;
330
331             // Filling in structure
332             if (!string.IsNullOrEmpty(strProxy))
333             {
334                 ipi = new InternetProxyInfo
335                 {
336                     dwAccessType = InternetOpenType.PROXY,
337                     proxy = strProxy,
338                     proxyBypass = "local",
339                 };
340             }
341             else if (strProxy == null)
342             {
343                 //IE Default
344                 var p = WebRequest.GetSystemWebProxy();
345                 if (p.IsBypassed(new Uri("http://www.google.com/")))
346                 {
347                     ipi = new InternetProxyInfo
348                     {
349                         dwAccessType = InternetOpenType.DIRECT,
350                         proxy = null,
351                         proxyBypass = null,
352                     };
353                 }
354                 else
355                 {
356                     ipi = new InternetProxyInfo
357                     {
358                         dwAccessType = InternetOpenType.PROXY,
359                         proxy = p.GetProxy(new Uri("http://www.google.com/")).Authority,
360                         proxyBypass = "local",
361                     };
362                 }
363             }
364             else
365             {
366                 ipi = new InternetProxyInfo
367                 {
368                     dwAccessType = InternetOpenType.DIRECT,
369                     proxy = null,
370                     proxyBypass = null,
371                 };
372             }
373
374             if (!InternetSetOption(IntPtr.Zero, InternetOption.PROXY, ref ipi, Marshal.SizeOf(ipi)))
375                 throw new Win32Exception();
376         }
377
378         public static void SetProxy(ProxyType pType, string host, int port)
379         {
380             string proxy = null;
381             switch (pType)
382             {
383             case ProxyType.IE:
384                 proxy = null;
385                 break;
386             case ProxyType.None:
387                 proxy = "";
388                 break;
389             case ProxyType.Specified:
390                 proxy = host + (port > 0 ? ":" + port : "");
391                 break;
392             }
393             RefreshProxySettings(proxy);
394         }
395 #endregion
396
397         [StructLayout(LayoutKind.Sequential)]
398         private struct SCROLLINFO
399         {
400             public int cbSize;
401             public ScrollInfoMask fMask;
402             public int nMin;
403             public int nMax;
404             public int nPage;
405             public int nPos;
406             public int nTrackPos;
407         }
408
409         public enum ScrollBarDirection
410         {
411             SB_HORZ = 0,
412             SB_VERT = 1,
413             SB_CTL = 2,
414             SB_BOTH = 3,
415         }
416
417         private enum ScrollInfoMask
418         {
419             SIF_RANGE = 0x1,
420             SIF_PAGE = 0x2,
421             SIF_POS = 0x4,
422             SIF_DISABLENOSCROLL = 0x8,
423             SIF_TRACKPOS = 0x10,
424             SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS),
425         }
426
427         [DllImport("user32.dll")]
428         private static extern int GetScrollInfo(IntPtr hWnd, ScrollBarDirection fnBar, ref SCROLLINFO lpsi);
429
430         public static int GetScrollPosition(Control control, ScrollBarDirection direction)
431         {
432             var si = new SCROLLINFO
433             {
434                 cbSize = Marshal.SizeOf<SCROLLINFO>(),
435                 fMask = ScrollInfoMask.SIF_POS,
436             };
437
438             if (NativeMethods.GetScrollInfo(control.Handle, direction, ref si) == 0)
439                 throw new Win32Exception();
440
441             return si.nPos;
442         }
443
444         #region "ウィンドウの検索"
445
446         [DllImport("user32.dll")]
447         private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint procId);
448         
449         [return: MarshalAs(UnmanagedType.Bool)]
450         private delegate bool EnumWindowCallback(IntPtr hWnd, int lParam);
451
452         [DllImport("user32")]
453         [return: MarshalAs(UnmanagedType.Bool)]
454         private static extern bool EnumWindows(EnumWindowCallback lpEnumFunc, IntPtr lParam);
455
456         [DllImport("user32.dll", CharSet = CharSet.Unicode)]
457         private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
458
459         [DllImport("user32.dll", CharSet = CharSet.Unicode)]
460         private static extern int GetWindowTextLength(IntPtr hWnd);
461
462         /// <summary>
463         /// 指定したPIDとタイトルを持つウィンドウのウィンドウハンドルを取得します
464         /// </summary>
465         /// <param name="pid">対象ウィンドウのPID</param>
466         /// <param name="searchWindowTitle">対象ウィンドウのタイトル</param>
467         /// <returns>ウィンドウハンドル。検索に失敗した場合は<see cref="IntPtr.Zero"/></returns>
468         public static IntPtr GetWindowHandle(uint pid, string searchWindowTitle)
469         {
470             var foundHwnd = IntPtr.Zero;
471
472             EnumWindows((hWnd, lParam) =>
473             {
474                 GetWindowThreadProcessId(hWnd, out var procId);
475
476                 if (procId == pid)
477                 {
478                     var windowTitleLen = GetWindowTextLength(hWnd);
479
480                     if (windowTitleLen > 0)
481                     {
482                         var windowTitle = new StringBuilder(windowTitleLen + 1);
483                         GetWindowText(hWnd, windowTitle, windowTitle.Capacity);
484
485                         if (windowTitle.ToString().Contains(searchWindowTitle))
486                         {
487                             foundHwnd = hWnd;
488                             return false;
489                         }
490                     }
491                 }
492
493                 return true;
494             }, IntPtr.Zero);
495
496             return foundHwnd;
497         }
498
499         #endregion
500
501         #region "ウィンドウのアクティブ化"
502
503         private enum ShowWindowCommands : int
504         {
505             /// <summary>最小化・最大化されたウィンドウを元に戻して表示</summary>
506             SW_RESTORE = 9,
507         }
508
509         [DllImport("user32.dll")]
510         [return: MarshalAs(UnmanagedType.Bool)]
511         private static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow);
512
513         [DllImport("user32.dll")]
514         [return: MarshalAs(UnmanagedType.Bool)]
515         private static extern bool SetForegroundWindow(IntPtr hWnd);
516
517         /// <summary>
518         /// 指定したウィンドウをアクティブにします
519         /// </summary>
520         /// <param name="hWnd">アクティブにするウィンドウのウィンドウハンドル</param>
521         public static void SetActiveWindow(IntPtr hWnd)
522         {
523             ShowWindow(hWnd, ShowWindowCommands.SW_RESTORE);
524             SetForegroundWindow(hWnd);
525         }
526
527         #endregion
528     }
529 }