OSDN Git Service

Shift+クリックでのツイート複数選択時の起点がおかしくなる問題の修正
[opentween/open-tween.git] / OpenTween / Win32Api.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 // All rights reserved.
9 // 
10 // This file is part of OpenTween.
11 // 
12 // This program is free software; you can redistribute it and/or modify it
13 // under the terms of the GNU General public License as published by the Free
14 // Software Foundation; either version 3 of the License, or (at your option)
15 // any later version.
16 // 
17 // This program is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General public License
20 // for more details. 
21 // 
22 // You should have received a copy of the GNU General public License along
23 // with this program. if not, see <http://www.gnu.org/licenses/>, or write to
24 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
25 // Boston, MA 02110-1301, USA.
26
27 using System;
28 using System.Diagnostics;
29 using System.Linq;
30 using System.Net;
31 using System.Runtime.InteropServices;
32 using System.Threading;
33 using System.Windows.Forms;
34
35 namespace OpenTween
36 {
37     public static class Win32Api
38     {
39         #region "先行起動プロセスをアクティブにする"
40         // 外部プロセスのウィンドウを起動する
41         public static void WakeupWindow(IntPtr hWnd)
42         {
43             // メイン・ウィンドウが最小化されていれば元に戻す
44             if (IsIconic(hWnd))
45             {
46                 ShowWindowAsync(hWnd, SW_RESTORE);
47             }
48
49             // メイン・ウィンドウを最前面に表示する
50             SetForegroundWindow(hWnd);
51         }
52
53         // 外部プロセスのメイン・ウィンドウを起動するためのWin32 API
54         [DllImport("user32.dll")]
55         private extern static bool SetForegroundWindow(
56             IntPtr hWnd);
57
58         // ウィンドウの表示状態を設定
59         [DllImport("user32.dll")]
60         private extern static bool ShowWindowAsync(
61             IntPtr hWnd,
62             int nCmdShow);
63
64         // 指定されたウィンドウが最小化( アイコン化)されているかどうかを調べる
65         [DllImport("user32.dll")]
66         private extern static bool IsIconic(
67             IntPtr hWnd);
68
69         // ShowWindowAsync関数のパラメータに渡す定義値
70         private const int SW_RESTORE = 9; // 画面を元の大きさに戻す
71
72         // 実行中の同じアプリケーションのプロセスを取得する
73         public static Process GetPreviousProcess()
74         {
75             var curProcess = Process.GetCurrentProcess();
76             try
77             {
78                 return Process.GetProcessesByName(curProcess.ProcessName)
79                     .Where(p => p.Id != curProcess.Id)
80                     .FirstOrDefault(p => string.Compare(p.MainModule.FileName, curProcess.MainModule.FileName, StringComparison.OrdinalIgnoreCase) == 0);
81             }
82             catch
83             {
84                 return null;
85             }
86         }
87         #endregion
88
89         #region "タスクトレイアイコンのクリック"
90         // 指定されたクラス名およびウィンドウ名と一致するトップレベルウィンドウのハンドルを取得します
91         [DllImport("user32.dll", CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
92         private extern static IntPtr FindWindow(
93             [MarshalAs(UnmanagedType.LPTStr)] string lpClassName,
94             [MarshalAs(UnmanagedType.LPTStr)] string lpWindowName);
95
96         // 指定された文字列と一致するクラス名とウィンドウ名文字列を持つウィンドウのハンドルを返します
97         [DllImport("user32.dll", CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
98         private extern static IntPtr FindWindowEx(
99             IntPtr hWnd1,
100             IntPtr hWnd2,
101             [MarshalAs(UnmanagedType.LPTStr)] string lpsz1,
102             [MarshalAs(UnmanagedType.LPTStr)] string lpsz2);
103
104         // 指定されたウィンドウへ、指定されたメッセージを送信します
105         [DllImport("user32.dll")]
106         private extern static IntPtr SendMessage(
107             IntPtr hwnd,
108             SendMessageType wMsg,
109             IntPtr wParam,
110             IntPtr lParam);
111
112         // SendMessageで送信するメッセージ
113         private enum SendMessageType : int
114         {
115             WM_USER = 0x400,                     //ユーザー定義メッセージ
116             TB_GETBUTTON = WM_USER + 23,         //ツールバーのボタン取得
117             TB_BUTTONCOUNT = WM_USER + 24,       //ツールバーのボタン(アイコン)数取得
118             TB_GETBUTTONINFO = WM_USER + 65,     //ツールバーのボタン詳細情報取得
119
120             TCM_FIRST = 0x1300,                  //タブコントロールメッセージ
121             TCM_SETMINTABWIDTH = TCM_FIRST + 49, //タブアイテムの最小幅を設定
122
123             LVM_FIRST = 0x1000,                    //リストビューメッセージ
124             LVM_GETSELECTIONMARK = LVM_FIRST + 66, //複数選択時の起点になるアイテムの位置を取得
125             LVM_SETSELECTIONMARK = LVM_FIRST + 67, //複数選択時の起点になるアイテムを設定
126         }
127         // ツールバーボタン構造体
128         [StructLayout(LayoutKind.Sequential, Pack = 1)]
129         private struct TBBUTTON
130         {
131             public int iBitmap;
132             public IntPtr idCommand;
133             public byte fsState;
134             public byte fsStyle;
135             public byte bReserved0;
136             public byte bReserved1;
137             public int dwData;
138             public int iString;
139         }
140         // ツールバーボタン詳細情報構造体
141         [StructLayout(LayoutKind.Sequential)]
142         private struct TBBUTTONINFO
143         {
144             public Int32 cbSize;
145             public Int32 dwMask;
146             public Int32 idCommand;
147             public Int32 iImage;
148             public Byte fsState;
149             public Byte fsStyle;
150             public short cx;
151             public IntPtr lParam;
152             public IntPtr pszText;
153             public Int32 cchText;
154         }
155         // TBBUTTONINFOのlParamでポイントされるアイコン情報(PostMessageで使用)
156         [StructLayout(LayoutKind.Sequential)]
157         private struct TRAYNOTIFY
158         {
159             public IntPtr hWnd;
160             public UInt32 uID;
161             public UInt32 uCallbackMessage;
162             public UInt32 dwDummy1;
163             public UInt32 dwDummy2;
164             public IntPtr hIcon;
165         }
166         // TBBUTTONINFOに指定するマスク情報
167         [Flags()]
168         private enum ToolbarButtonMask : int
169         {
170             TBIF_COMMAND = 0x20,
171             TBIF_LPARAM = 0x10,
172             TBIF_TEXT = 0x2,
173         }
174         // 指定されたウィンドウを作成したスレッドの ID を取得します
175         [DllImport("user32.dll", SetLastError = true)]
176         private static extern int GetWindowThreadProcessId(
177             IntPtr hwnd,
178             out int lpdwProcessId);
179
180         // 指定したプロセスIDに対するプロセスハンドルを取得します
181         [DllImport("kernel32.dll")]
182         private static extern IntPtr OpenProcess(
183             ProcessAccess dwDesiredAccess,
184             [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
185             int dwProcessId);
186
187         // OpenProcessで指定するアクセス権
188         [Flags()]
189         private enum ProcessAccess : int
190         {
191             /// <summary>Specifies all possible access flags for the process object.</summary>
192             AllAccess = CreateThread | DuplicateHandle | QueryInformation | SetInformation | Terminate | VMOperation | VMRead | VMWrite | Synchronize,
193             /// <summary>Enables usage of the process handle in the CreateRemoteThread function to create a thread in the process.</summary>
194             CreateThread = 0x2,
195             /// <summary>Enables usage of the process handle as either the source or target process in the DuplicateHandle function to duplicate a handle.</summary>
196             DuplicateHandle = 0x40,
197             /// <summary>Enables usage of the process handle in the GetExitCodeProcess and GetPriorityClass functions to read information from the process object.</summary>
198             QueryInformation = 0x400,
199             /// <summary>Enables usage of the process handle in the SetPriorityClass function to set the priority class of the process.</summary>
200             SetInformation = 0x200,
201             /// <summary>Enables usage of the process handle in the TerminateProcess function to terminate the process.</summary>
202             Terminate = 0x1,
203             /// <summary>Enables usage of the process handle in the VirtualProtectEx and WriteProcessMemory functions to modify the virtual memory of the process.</summary>
204             VMOperation = 0x8,
205             /// <summary>Enables usage of the process handle in the ReadProcessMemory function to read from the virtual memory of the process.</summary>
206             VMRead = 0x10,
207             /// <summary>Enables usage of the process handle in the WriteProcessMemory function to write to the virtual memory of the process.</summary>
208             VMWrite = 0x20,
209             /// <summary>Enables usage of the process handle in any of the wait functions to wait for the process to terminate.</summary>
210             Synchronize = 0x100000,
211         }
212         // 指定したプロセスの仮想アドレス空間にメモリ領域を確保
213         [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
214         private static extern IntPtr VirtualAllocEx(
215             IntPtr hProcess,
216             IntPtr lpAddress,
217             IntPtr dwSize,
218             AllocationTypes flAllocationType,
219             MemoryProtectionTypes flProtect);
220
221         // アロケート種類
222         [Flags()]
223         private enum AllocationTypes : uint
224         {
225             Commit = 0x1000,
226             Reserve = 0x2000,
227             Decommit = 0x4000,
228             Release = 0x8000,
229             Reset = 0x80000,
230             Physical = 0x400000,
231             TopDown = 0x100000,
232             WriteWatch = 0x200000,
233             LargePages = 0x20000000,
234         }
235         // アロケートしたメモリに対する保護レベル
236         [Flags()]
237         private enum MemoryProtectionTypes : uint
238         {
239             Execute = 0x10,
240             ExecuteRead = 0x20,
241             ExecuteReadWrite = 0x40,
242             ExecuteWriteCopy = 0x80,
243             NoAccess = 0x1,
244             ReadOnly = 0x2,
245             ReadWrite = 0x4,
246             WriteCopy = 0x8,
247             GuardModifierflag = 0x100,
248             NoCacheModifierflag = 0x200,
249             WriteCombineModifierflag = 0x400,
250         }
251         // オープンしているカーネルオブジェクトのハンドルをクローズします
252         [DllImport("kernel32.dll", SetLastError = true)]
253         private static extern bool CloseHandle(IntPtr hHandle);
254
255         // 指定されたプロセスの仮想アドレス空間内のメモリ領域を解放またはコミット解除します
256         [DllImport("kernel32.dll")]
257         private static extern bool VirtualFreeEx(
258             IntPtr hProcess,
259             IntPtr lpAddress,
260             IntPtr dwSize,
261             MemoryFreeTypes dwFreeType);
262
263         // メモリ解放種別
264         [Flags()]
265         private enum MemoryFreeTypes
266         {
267             Release = 0x8000,
268         }
269         //指定したプロセスのメモリ領域にデータをコピーする
270         [DllImport("kernel32.dll", SetLastError = true)]
271         private static extern bool WriteProcessMemory(
272             IntPtr hProcess,
273             IntPtr lpBaseAddress,
274             ref TBBUTTONINFO lpBuffer,
275             IntPtr nSize,
276             out int lpNumberOfBytesWritten);
277
278         //指定したプロセスのメモリ領域のデータを呼び出し側プロセスのバッファにコピーする
279         [DllImport("kernel32.dll", SetLastError = true)]
280         private static extern bool ReadProcessMemory(
281             IntPtr hProcess,
282             IntPtr lpBaseAddress,
283             IntPtr lpBuffer,
284             IntPtr nSize,
285             out int lpNumberOfBytesRead);
286
287         //メッセージをウィンドウのメッセージ キューに置き、対応するウィンドウがメッセージを処理するのを待たずに戻ります
288         [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
289         private static extern bool PostMessage(
290             IntPtr hWnd,
291             uint Msg,
292             IntPtr wParam,
293             IntPtr lParam);
294
295         //PostMessageで送信するメッセージ
296         private enum PM_Message : uint
297         {
298             WM_LBUTTONDOWN = 0x201,      //左マウスボタン押し下げ
299             WM_LBUTTONUP = 0x202,        //左マウスボタン離し
300         }
301
302         /// <summary>
303         /// タブコントロールのアイテムの最小幅を設定します
304         /// </summary>
305         /// <param name="tabControl">対象となるタブコントロール</param>
306         /// <param name="width">アイテムの最小幅。-1 を指定するとデフォルトの幅が使用されます</param>
307         /// <returns>設定前の最小幅</returns>
308         public static int SetMinTabWidth(TabControl tabControl, int width)
309         {
310             return (int)SendMessage(tabControl.Handle, SendMessageType.TCM_SETMINTABWIDTH, IntPtr.Zero, (IntPtr)width);
311         }
312
313         //タスクトレイアイコンのクリック処理
314         public static bool ClickTasktrayIcon(string tooltip)
315         {
316             const string TRAY_WINDOW = "Shell_TrayWnd";
317             const string TRAY_NOTIFYWINDOW = "TrayNotifyWnd";
318             const string TRAY_PAGER = "SysPager";
319             const string TOOLBAR_CONTROL = "ToolbarWindow32";
320             //タスクバーのハンドル取得
321             var taskbarWin = FindWindow(TRAY_WINDOW, null);
322             if (taskbarWin.Equals(IntPtr.Zero)) return false;
323             //通知領域のハンドル取得
324             var trayWin = FindWindowEx(taskbarWin, IntPtr.Zero, TRAY_NOTIFYWINDOW, null);
325             if (trayWin.Equals(IntPtr.Zero)) return false;
326             //SysPagerの有無確認。(XP/2000はSysPagerあり)
327             var tempWin = FindWindowEx(trayWin, IntPtr.Zero, TRAY_PAGER, null);
328             if (tempWin.Equals(IntPtr.Zero)) tempWin = trayWin;
329             //タスクトレイがツールバーで出来ているか確認
330             // → ツールバーでなければ終了
331             var toolWin = FindWindowEx(tempWin, IntPtr.Zero, TOOLBAR_CONTROL, null);
332             if (toolWin.Equals(IntPtr.Zero)) return false;
333             //タスクトレイのプロセス(Explorer)を取得し、外部から参照するために開く
334             int expPid = 0;
335             GetWindowThreadProcessId(toolWin, out expPid);
336             var hProc = OpenProcess(ProcessAccess.VMOperation | ProcessAccess.VMRead | ProcessAccess.VMWrite, false, expPid);
337             if (hProc.Equals(IntPtr.Zero)) return false;
338
339             //プロセスを閉じるためにtry-finally
340             try
341             {
342                 var tbButtonLocal = new TBBUTTON();   //本プロセス内のタスクバーボタン情報作成(サイズ特定でのみ使用)
343                 //Explorer内のタスクバーボタン格納メモリ確保
344                 var ptbSysButton = VirtualAllocEx(hProc, IntPtr.Zero, (IntPtr)Marshal.SizeOf(tbButtonLocal), AllocationTypes.Reserve | AllocationTypes.Commit, MemoryProtectionTypes.ReadWrite);
345                 if (ptbSysButton.Equals(IntPtr.Zero)) return false; //メモリ確保失敗
346                 try
347                 {
348                     var tbButtonInfoLocal = new TBBUTTONINFO();   //本プロセス内ツールバーボタン詳細情報作成
349                     //Explorer内のタスクバーボタン詳細情報格納メモリ確保
350                     var ptbSysInfo = VirtualAllocEx(hProc, IntPtr.Zero, (IntPtr)Marshal.SizeOf(tbButtonInfoLocal), AllocationTypes.Reserve | AllocationTypes.Commit, MemoryProtectionTypes.ReadWrite);
351                     if (ptbSysInfo.Equals(IntPtr.Zero)) return false; //メモリ確保失敗
352                     try
353                     {
354                         const int titleSize = 256;    //Tooltip文字列長
355                         var title = "";            //Tooltip文字列
356                         //共有メモリにTooltip読込メモリ確保
357                         var pszTitle = Marshal.AllocCoTaskMem(titleSize);
358                         if (pszTitle.Equals(IntPtr.Zero)) return false; //メモリ確保失敗
359                         try
360                         {
361                             //Explorer内にTooltip読込メモリ確保
362                             var pszSysTitle = VirtualAllocEx(hProc, IntPtr.Zero, (IntPtr)titleSize, AllocationTypes.Reserve | AllocationTypes.Commit, MemoryProtectionTypes.ReadWrite);
363                             if (pszSysTitle.Equals(IntPtr.Zero)) return false; //メモリ確保失敗
364                             try
365                             {
366                                 //通知領域ボタン数取得
367                                 var iCount = (int)SendMessage(toolWin, SendMessageType.TB_BUTTONCOUNT, new IntPtr(0), new IntPtr(0));
368                                 //左から順に情報取得
369                                 for (var i = 0; i < iCount; i++)
370                                 {
371                                     var dwBytes = 0;  //読み書きバイト数
372                                     var tbButtonLocal2 = new TBBUTTON();  //ボタン情報
373                                     var tbButtonInfoLocal2 = new TBBUTTONINFO();  //ボタン詳細情報
374                                     //共有メモリにボタン情報読込メモリ確保
375                                     var ptrLocal = Marshal.AllocCoTaskMem(Marshal.SizeOf(tbButtonLocal));
376                                     if (ptrLocal.Equals(IntPtr.Zero)) return false; //メモリ確保失敗
377                                     try
378                                     {
379                                         Marshal.StructureToPtr(tbButtonLocal, ptrLocal, true);   //共有メモリ初期化
380                                         //ボタン情報取得(idCommandを取得するため)
381                                         SendMessage(
382                                             toolWin,
383                                             SendMessageType.TB_GETBUTTON,
384                                             new IntPtr(i),
385                                             ptbSysButton);
386                                         //Explorer内のメモリを共有メモリに読み込み
387                                         ReadProcessMemory(
388                                             hProc,
389                                             ptbSysButton,
390                                             ptrLocal,
391                                             (IntPtr)Marshal.SizeOf(tbButtonLocal),
392                                             out dwBytes);
393                                         //共有メモリの内容を構造体に変換
394                                         tbButtonLocal2 = (TBBUTTON)Marshal.PtrToStructure(
395                                                                 ptrLocal,
396                                                                 typeof(TBBUTTON));
397                                     }
398                                     finally
399                                     {
400                                         Marshal.FreeCoTaskMem(ptrLocal); //共有メモリ解放
401                                     }
402
403                                     //ボタン詳細情報を取得するためのマスク等を設定
404                                     tbButtonInfoLocal.cbSize = Marshal.SizeOf(tbButtonInfoLocal);
405                                     tbButtonInfoLocal.dwMask = (int)(ToolbarButtonMask.TBIF_COMMAND | ToolbarButtonMask.TBIF_LPARAM | ToolbarButtonMask.TBIF_TEXT);
406                                     tbButtonInfoLocal.pszText = pszSysTitle;     //Tooltip書き込み先領域
407                                     tbButtonInfoLocal.cchText = titleSize;
408                                     //マスク設定等をExplorerのメモリへ書き込み
409                                     WriteProcessMemory(
410                                         hProc,
411                                         ptbSysInfo,
412                                         ref tbButtonInfoLocal,
413                                         (IntPtr)Marshal.SizeOf(tbButtonInfoLocal),
414                                         out dwBytes);
415                                     //ボタン詳細情報取得
416                                     SendMessage(
417                                         toolWin,
418                                         SendMessageType.TB_GETBUTTONINFO,
419                                         tbButtonLocal2.idCommand,
420                                         ptbSysInfo);
421                                     //共有メモリにボタン詳細情報を読み込む領域確保
422                                     var ptrInfo = Marshal.AllocCoTaskMem(Marshal.SizeOf(tbButtonInfoLocal));
423                                     if (ptrInfo.Equals(IntPtr.Zero)) return false; //共有メモリ確保失敗
424                                     try
425                                     {
426                                         Marshal.StructureToPtr(tbButtonInfoLocal, ptrInfo, true);    //共有メモリ初期化
427                                         //Explorer内のメモリを共有メモリに読み込み
428                                         ReadProcessMemory(
429                                             hProc,
430                                             ptbSysInfo,
431                                             ptrInfo,
432                                             (IntPtr)Marshal.SizeOf(tbButtonInfoLocal),
433                                             out dwBytes);
434                                         //共有メモリの内容を構造体に変換
435                                         tbButtonInfoLocal2 = (TBBUTTONINFO)Marshal.PtrToStructure(
436                                                                     ptrInfo,
437                                                                     typeof(TBBUTTONINFO));
438                                     }
439                                     finally
440                                     {
441                                         Marshal.FreeCoTaskMem(ptrInfo);  //共有メモリ解放
442                                     }
443                                     //Tooltipの内容をExplorer内のメモリから共有メモリへ読込
444                                     ReadProcessMemory(hProc, pszSysTitle, pszTitle, (IntPtr)titleSize, out dwBytes);
445                                     //ローカル変数へ変換
446                                     title = Marshal.PtrToStringAnsi(pszTitle, titleSize);
447
448                                     //Tooltipが指定文字列を含んでいればクリック
449                                     if (title.Contains(tooltip))
450                                     {
451                                         //PostMessageでクリックを送るために、ボタン詳細情報のlParamでポイントされているTRAYNOTIFY情報が必要
452                                         var tNotify = new TRAYNOTIFY();
453                                         var tNotify2 = new TRAYNOTIFY();
454                                         //共有メモリ確保
455                                         var ptNotify = Marshal.AllocCoTaskMem(Marshal.SizeOf(tNotify));
456                                         if (ptNotify.Equals(IntPtr.Zero)) return false; //メモリ確保失敗
457                                         try
458                                         {
459                                             Marshal.StructureToPtr(tNotify, ptNotify, true); //初期化
460                                             //lParamのメモリを読込
461                                             ReadProcessMemory(
462                                                 hProc,
463                                                 tbButtonInfoLocal2.lParam,
464                                                 ptNotify,
465                                                 (IntPtr)Marshal.SizeOf(tNotify),
466                                                 out dwBytes);
467                                             //構造体へ変換
468                                             tNotify2 = (TRAYNOTIFY)
469                                                             Marshal.PtrToStructure(
470                                                                 ptNotify,
471                                                                 typeof(TRAYNOTIFY));
472                                         }
473                                         finally
474                                         {
475                                             Marshal.FreeCoTaskMem(ptNotify); //共有メモリ解放
476                                         }
477                                         //クリックするためには通知領域がアクティブでなければならない
478                                         SetForegroundWindow(tNotify2.hWnd);
479                                         //左クリック
480                                         PostMessage(tNotify2.hWnd, tNotify2.uCallbackMessage, (IntPtr)tNotify2.uID, (IntPtr)PM_Message.WM_LBUTTONDOWN);
481                                         PostMessage(tNotify2.hWnd, tNotify2.uCallbackMessage, (IntPtr)tNotify2.uID, (IntPtr)PM_Message.WM_LBUTTONUP);
482                                         return true;
483                                     }
484                                 }
485                                 return false;    //該当なし
486                             }
487                             finally
488                             {
489                                 VirtualFreeEx(hProc, pszSysTitle, (IntPtr)titleSize, MemoryFreeTypes.Release);   //メモリ解放
490                             }
491                         }
492                         finally
493                         {
494                             Marshal.FreeCoTaskMem(pszTitle);     //共有メモリ解放
495                         }
496                     }
497                     finally
498                     {
499                         VirtualFreeEx(hProc, ptbSysInfo, (IntPtr)Marshal.SizeOf(tbButtonInfoLocal), MemoryFreeTypes.Release);    //メモリ解放
500                     }
501                 }
502                 finally
503                 {
504                     VirtualFreeEx(hProc, ptbSysButton, (IntPtr)Marshal.SizeOf(tbButtonLocal), MemoryFreeTypes.Release);      //メモリ解放
505                 }
506             }
507             finally
508             {
509                 CloseHandle(hProc);  //Explorerのプロセス閉じる
510             }
511         }
512         #endregion
513
514         #region "画面ブリンク用"
515         public static bool FlashMyWindow(IntPtr hwnd,
516             FlashSpecification flashType,
517             int flashCount)
518         {
519             var fInfo = new FLASHWINFO();
520             fInfo.cbSize = Convert.ToInt32(Marshal.SizeOf(fInfo));
521             fInfo.hwnd = hwnd;
522             fInfo.dwFlags = (int)FlashSpecification.FlashAll;
523             fInfo.uCount = flashCount;
524             fInfo.dwTimeout = 0;
525
526             return FlashWindowEx(ref fInfo);
527         }
528
529         public enum FlashSpecification : uint
530         {
531             FlashStop = FLASHW_STOP,
532             FlashCaption = FLASHW_CAPTION,
533             FlashTray = FLASHW_TRAY,
534             FlashAll = FLASHW_ALL,
535             FlashTimer = FLASHW_TIMER,
536             FlashTimerNoForeground = FLASHW_TIMERNOFG,
537         }
538         /// http://www.atmarkit.co.jp/fdotnet/dotnettips/723flashwindow/flashwindow.html
539         [DllImport("user32.dll")]
540         private static extern bool FlashWindowEx(
541             ref FLASHWINFO FWInfo);
542
543
544         private struct FLASHWINFO
545         {
546             public Int32 cbSize;    // FLASHWINFO構造体のサイズ
547             public IntPtr hwnd;     // 点滅対象のウィンドウ・ハンドル
548             public Int32 dwFlags;   // 以下の「FLASHW_XXX」のいずれか
549             public Int32 uCount;    // 点滅する回数
550             public Int32 dwTimeout; // 点滅する間隔(ミリ秒単位)
551         }
552
553         // 点滅を止める
554         private const Int32 FLASHW_STOP = 0;
555         // タイトルバーを点滅させる
556         private const Int32 FLASHW_CAPTION = 0x1;
557         // タスクバー・ボタンを点滅させる
558         private const Int32 FLASHW_TRAY = 0x2;
559         // タスクバー・ボタンとタイトルバーを点滅させる
560         private const Int32 FLASHW_ALL = 0x3;
561         // FLASHW_STOPが指定されるまでずっと点滅させる
562         private const Int32 FLASHW_TIMER = 0x4;
563         // ウィンドウが最前面に来るまでずっと点滅させる
564         private const Int32 FLASHW_TIMERNOFG = 0xC;
565         #endregion
566
567         [DllImport("user32.dll")]
568         public static extern bool ValidateRect(
569             IntPtr hwnd,
570             IntPtr rect);
571
572         #region "selection mark"
573         // 複数選択時の起点になるアイテム (selection mark) の位置を取得する
574         public static int ListView_GetSelectionMark(IntPtr hwndLV)
575         {
576             return SendMessage(hwndLV, SendMessageType.LVM_GETSELECTIONMARK, IntPtr.Zero, IntPtr.Zero).ToInt32();
577         }
578
579         // 複数選択時の起点になるアイテム (selection mark) を設定する
580         public static void ListView_SetSelectionMark(IntPtr hwndLV, int itemIndex)
581         {
582             SendMessage(hwndLV, SendMessageType.LVM_SETSELECTIONMARK, IntPtr.Zero, (IntPtr)itemIndex);
583         }
584         #endregion
585
586         #region "スクリーンセーバー起動中か判定"
587         [DllImport("user32", CharSet = CharSet.Auto)]
588         private static extern int SystemParametersInfo(
589                     int intAction,
590                     int intParam,
591                     ref bool bParam,
592                     int intWinIniFlag);
593         // returns non-zero value if function succeeds
594
595         //スクリーンセーバーが起動中かを取得する定数
596         private const int SPI_GETSCREENSAVERRUNNING = 0x0072;
597
598         public static bool IsScreenSaverRunning()
599         {
600             var isRunning = false;
601             SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref isRunning, 0);
602             return isRunning;
603         }
604         #endregion
605
606         #region "グローバルフック"
607         [DllImport("user32")]
608         private static extern int RegisterHotKey(IntPtr hwnd, int id,
609             int fsModifiers, int vk);
610         [DllImport("user32")]
611         private static extern int UnregisterHotKey(IntPtr hwnd, int id);
612         [DllImport("kernel32", CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
613         private static extern ushort GlobalAddAtom([MarshalAs(UnmanagedType.LPTStr)] string lpString);
614         [DllImport("kernel32")]
615         private static extern ushort GlobalDeleteAtom(ushort nAtom);
616
617         private static int registerCount = 0;
618         // register a global hot key
619         public static int RegisterGlobalHotKey(int hotkeyValue, int modifiers, Form targetForm)
620         {
621             ushort hotkeyID = 0;
622             try
623             {
624                 // use the GlobalAddAtom API to get a unique ID (as suggested by MSDN docs)
625                 registerCount++;
626                 var atomName = Thread.CurrentThread.ManagedThreadId.ToString("X8") + targetForm.Name + registerCount.ToString();
627                 hotkeyID = GlobalAddAtom(atomName);
628                 if (hotkeyID == 0)
629                 {
630                     throw new Exception("Unable to generate unique hotkey ID. Error code: " +
631                        Marshal.GetLastWin32Error().ToString());
632                 }
633
634                 // register the hotkey, throw if any error
635                 if (RegisterHotKey(targetForm.Handle, hotkeyID, modifiers, hotkeyValue) == 0)
636                 {
637                     throw new Exception("Unable to register hotkey. Error code: " +
638                        Marshal.GetLastWin32Error().ToString());
639                 }
640                 return hotkeyID;
641             }
642             catch (Exception)
643             {
644                 // clean up if hotkey registration failed
645                 UnregisterGlobalHotKey(hotkeyID, targetForm);
646                 return 0;
647             }
648         }
649
650         // unregister a global hotkey
651         public static void UnregisterGlobalHotKey(ushort hotkeyID, Form targetForm)
652         {
653             if (hotkeyID != 0)
654             {
655                 UnregisterHotKey(targetForm.Handle, hotkeyID);
656                 // clean up the atom list
657                 GlobalDeleteAtom(hotkeyID);
658                 hotkeyID = 0;
659             }
660         }
661         #endregion
662
663         #region "プロセスのProxy設定"
664         [DllImport("wininet.dll", SetLastError =true)]
665         private static extern bool InternetSetOption(IntPtr hInternet,
666                                                      int dwOption,
667                                                      IntPtr lpBuffer,
668                                                      int lpdwBufferLength);
669
670         private struct INTERNET_PROXY_INFO : IDisposable
671         {
672             public int dwAccessType;
673             public IntPtr proxy;
674             public IntPtr proxyBypass;
675
676             public void Dispose()
677             {
678                 Dispose(true);
679             }
680
681             private void Dispose(bool disposing)
682             {
683                 if (proxy != IntPtr.Zero) Marshal.FreeHGlobal(proxy);
684                 if (proxyBypass != IntPtr.Zero) Marshal.FreeHGlobal(proxyBypass);
685             }
686         }
687
688         private static void RefreshProxySettings(string strProxy)
689         {
690             const int INTERNET_OPTION_PROXY = 38;
691             //const int INTERNET_OPEN_TYPE_PRECONFIG = 0;   //IE setting
692             const int INTERNET_OPEN_TYPE_DIRECT = 1;      //Direct
693             const int INTERNET_OPEN_TYPE_PROXY = 3;       //Custom
694
695             INTERNET_PROXY_INFO ipi;
696
697             // Filling in structure
698             if (!string.IsNullOrEmpty(strProxy))
699             {
700                 ipi.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
701                 ipi.proxy = Marshal.StringToHGlobalAnsi(strProxy);
702                 ipi.proxyBypass = Marshal.StringToHGlobalAnsi("local");
703             }
704             else if (strProxy == null)
705             {
706                 //IE Default
707                 var p = WebRequest.GetSystemWebProxy();
708                 if (p.IsBypassed(new Uri("http://www.google.com/")))
709                 {
710                     ipi.dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
711                     ipi.proxy = IntPtr.Zero;
712                     ipi.proxyBypass = IntPtr.Zero;
713                 }
714                 else
715                 {
716                     ipi.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
717                     ipi.proxy = Marshal.StringToHGlobalAnsi(p.GetProxy(new Uri("http://www.google.com/")).Authority);
718                     ipi.proxyBypass = Marshal.StringToHGlobalAnsi("local");
719                 }
720             }
721             else
722             {
723                 ipi.dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
724                 ipi.proxy = IntPtr.Zero;
725                 ipi.proxyBypass = IntPtr.Zero;
726             }
727
728             try
729             {
730                 // Allocating memory
731                 var pIpi = Marshal.AllocCoTaskMem(Marshal.SizeOf(ipi));
732                 if (pIpi.Equals(IntPtr.Zero)) return;
733                 try
734                 {
735                     // Converting structure to IntPtr
736                     Marshal.StructureToPtr(ipi, pIpi, true);
737                     var ret = InternetSetOption(IntPtr.Zero,
738                                                            INTERNET_OPTION_PROXY,
739                                                            pIpi,
740                                                            Marshal.SizeOf(ipi));
741                 }
742                 finally
743                 {
744                     Marshal.FreeCoTaskMem(pIpi);
745                 }
746             }
747             finally
748             {
749                 ipi.Dispose();
750             }
751         }
752
753         private static void RefreshProxyAccount(string username, string password)
754         {
755             const int INTERNET_OPTION_PROXY_USERNAME = 43;
756             const int INTERNET_OPTION_PROXY_PASSWORD = 44;
757
758             if (!string.IsNullOrEmpty(username) || !string.IsNullOrEmpty(password))
759             {
760                 var ret = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY_USERNAME, IntPtr.Zero, 0);
761                 ret = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY_PASSWORD, IntPtr.Zero, 0);
762             }
763             else
764             {
765                 var pUser = Marshal.StringToBSTR(username);
766                 var pPass = Marshal.StringToBSTR(password);
767                 try
768                 {
769                     var ret = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY_USERNAME, pUser, username.Length + 1);
770                     ret = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY_PASSWORD, pPass, password.Length + 1);
771                 }
772                 finally
773                 {
774                     Marshal.FreeBSTR(pUser);
775                     Marshal.FreeBSTR(pPass);
776                 }
777             }
778         }
779
780         public static void SetProxy(HttpConnection.ProxyType pType, string host, int port, string username, string password)
781         {
782             string proxy = null;
783             switch (pType)
784             {
785             case HttpConnection.ProxyType.IE:
786                 proxy = null;
787                 break;
788             case HttpConnection.ProxyType.None:
789                 proxy = "";
790                 break;
791             case HttpConnection.ProxyType.Specified:
792                 proxy = host + (port > 0 ? ":" + port.ToString() : "");
793                 break;
794             }
795             RefreshProxySettings(proxy);
796             RefreshProxyAccount(username, password);
797         }
798 #endregion
799     }
800 }