OSDN Git Service

57f4c9ba3956af117739ede597b61e0cbcf0f287
[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 // 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 using OpenTween.Connection;
35
36 namespace OpenTween
37 {
38     internal static class NativeMethods
39     {
40         // 指定されたウィンドウへ、指定されたメッセージを送信します
41         [DllImport("user32.dll")]
42         private extern static IntPtr SendMessage(
43             IntPtr hwnd,
44             SendMessageType wMsg,
45             IntPtr wParam,
46             IntPtr lParam);
47
48         // SendMessageで送信するメッセージ
49         private enum SendMessageType : uint
50         {
51             WM_SETREDRAW = 0x000B,               //再描画を許可するかを設定
52             WM_USER = 0x400,                     //ユーザー定義メッセージ
53
54             TCM_FIRST = 0x1300,                  //タブコントロールメッセージ
55             TCM_SETMINTABWIDTH = TCM_FIRST + 49, //タブアイテムの最小幅を設定
56
57             LVM_FIRST = 0x1000,                    //リストビューメッセージ
58             LVM_GETSELECTIONMARK = LVM_FIRST + 66, //複数選択時の起点になるアイテムの位置を取得
59             LVM_SETSELECTIONMARK = LVM_FIRST + 67, //複数選択時の起点になるアイテムを設定
60         }
61
62         /// <summary>
63         /// コントロールの再描画を許可するかを設定します
64         /// </summary>
65         /// <param name="control">対象となるコントロール</param>
66         /// <param name="redraw">再描画を許可する場合は true、抑制する場合は false</param>
67         /// <returns>このメッセージを処理する場合、アプリケーションは 0 を返します</returns>
68         public static int SetRedrawState(Control control, bool redraw)
69         {
70             var state = redraw ? new IntPtr(1) : IntPtr.Zero;
71             return (int)SendMessage(control.Handle, SendMessageType.WM_SETREDRAW, state, IntPtr.Zero);
72         }
73
74         /// <summary>
75         /// タブコントロールのアイテムの最小幅を設定します
76         /// </summary>
77         /// <param name="tabControl">対象となるタブコントロール</param>
78         /// <param name="width">アイテムの最小幅。-1 を指定するとデフォルトの幅が使用されます</param>
79         /// <returns>設定前の最小幅</returns>
80         public static int SetMinTabWidth(TabControl tabControl, int width)
81         {
82             return (int)SendMessage(tabControl.Handle, SendMessageType.TCM_SETMINTABWIDTH, IntPtr.Zero, (IntPtr)width);
83         }
84
85         [DllImport("user32")]
86         private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
87
88         /// <summary>
89         /// 最小化状態のウィンドウを最小化する前の状態に復元します。
90         /// </summary>
91         /// <param name="window">復元するウィンドウ。</param>
92         /// <exception cref="System.ArgumentNullException"><paramref name="window"/> が null です。</exception>
93         public static void RestoreWindow(IWin32Window window)
94         {
95             if (window == null)
96             {
97                 throw new ArgumentNullException("window");
98             }
99
100             ShowWindow(window.Handle, /* SW_RESTORE */ 9);
101         }
102
103         #region "画面ブリンク用"
104         public static bool FlashMyWindow(IntPtr hwnd,
105             FlashSpecification flashType,
106             int flashCount)
107         {
108             var fInfo = new FLASHWINFO();
109             fInfo.cbSize = Convert.ToInt32(Marshal.SizeOf(fInfo));
110             fInfo.hwnd = hwnd;
111             fInfo.dwFlags = (int)FlashSpecification.FlashAll;
112             fInfo.uCount = flashCount;
113             fInfo.dwTimeout = 0;
114
115             return FlashWindowEx(ref fInfo);
116         }
117
118         public enum FlashSpecification : uint
119         {
120             FlashStop = FLASHW_STOP,
121             FlashCaption = FLASHW_CAPTION,
122             FlashTray = FLASHW_TRAY,
123             FlashAll = FLASHW_ALL,
124             FlashTimer = FLASHW_TIMER,
125             FlashTimerNoForeground = FLASHW_TIMERNOFG,
126         }
127         /// http://www.atmarkit.co.jp/fdotnet/dotnettips/723flashwindow/flashwindow.html
128         [DllImport("user32.dll")]
129         private static extern bool FlashWindowEx(
130             ref FLASHWINFO FWInfo);
131
132
133         private struct FLASHWINFO
134         {
135             public Int32 cbSize;    // FLASHWINFO構造体のサイズ
136             public IntPtr hwnd;     // 点滅対象のウィンドウ・ハンドル
137             public Int32 dwFlags;   // 以下の「FLASHW_XXX」のいずれか
138             public Int32 uCount;    // 点滅する回数
139             public Int32 dwTimeout; // 点滅する間隔(ミリ秒単位)
140         }
141
142         // 点滅を止める
143         private const Int32 FLASHW_STOP = 0;
144         // タイトルバーを点滅させる
145         private const Int32 FLASHW_CAPTION = 0x1;
146         // タスクバー・ボタンを点滅させる
147         private const Int32 FLASHW_TRAY = 0x2;
148         // タスクバー・ボタンとタイトルバーを点滅させる
149         private const Int32 FLASHW_ALL = 0x3;
150         // FLASHW_STOPが指定されるまでずっと点滅させる
151         private const Int32 FLASHW_TIMER = 0x4;
152         // ウィンドウが最前面に来るまでずっと点滅させる
153         private const Int32 FLASHW_TIMERNOFG = 0xC;
154         #endregion
155
156         [DllImport("user32.dll")]
157         public static extern bool ValidateRect(
158             IntPtr hwnd,
159             IntPtr rect);
160
161         #region "selection mark"
162         // 複数選択時の起点になるアイテム (selection mark) の位置を取得する
163         public static int ListView_GetSelectionMark(IntPtr hwndLV)
164         {
165             return SendMessage(hwndLV, SendMessageType.LVM_GETSELECTIONMARK, IntPtr.Zero, IntPtr.Zero).ToInt32();
166         }
167
168         // 複数選択時の起点になるアイテム (selection mark) を設定する
169         public static void ListView_SetSelectionMark(IntPtr hwndLV, int itemIndex)
170         {
171             SendMessage(hwndLV, SendMessageType.LVM_SETSELECTIONMARK, IntPtr.Zero, (IntPtr)itemIndex);
172         }
173         #endregion
174
175         #region "スクリーンセーバー起動中か判定"
176         [DllImport("user32", CharSet = CharSet.Auto)]
177         private static extern int SystemParametersInfo(
178                     int intAction,
179                     int intParam,
180                     ref bool bParam,
181                     int intWinIniFlag);
182         // returns non-zero value if function succeeds
183
184         //スクリーンセーバーが起動中かを取得する定数
185         private const int SPI_GETSCREENSAVERRUNNING = 0x0072;
186
187         public static bool IsScreenSaverRunning()
188         {
189             var isRunning = false;
190             SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref isRunning, 0);
191             return isRunning;
192         }
193         #endregion
194
195         #region "グローバルフック"
196         [DllImport("user32")]
197         private static extern int RegisterHotKey(IntPtr hwnd, int id,
198             int fsModifiers, int vk);
199         [DllImport("user32")]
200         private static extern int UnregisterHotKey(IntPtr hwnd, int id);
201         [DllImport("kernel32", CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
202         private static extern ushort GlobalAddAtom([MarshalAs(UnmanagedType.LPTStr)] string lpString);
203         [DllImport("kernel32")]
204         private static extern ushort GlobalDeleteAtom(ushort nAtom);
205
206         private static int registerCount = 0;
207         // register a global hot key
208         public static int RegisterGlobalHotKey(int hotkeyValue, int modifiers, Form targetForm)
209         {
210             ushort hotkeyID = 0;
211             try
212             {
213                 // use the GlobalAddAtom API to get a unique ID (as suggested by MSDN docs)
214                 registerCount++;
215                 var atomName = Thread.CurrentThread.ManagedThreadId.ToString("X8") + targetForm.Name + registerCount.ToString();
216                 hotkeyID = GlobalAddAtom(atomName);
217                 if (hotkeyID == 0)
218                 {
219                     throw new Exception("Unable to generate unique hotkey ID. Error code: " +
220                        Marshal.GetLastWin32Error().ToString());
221                 }
222
223                 // register the hotkey, throw if any error
224                 if (RegisterHotKey(targetForm.Handle, hotkeyID, modifiers, hotkeyValue) == 0)
225                 {
226                     throw new Exception("Unable to register hotkey. Error code: " +
227                        Marshal.GetLastWin32Error().ToString());
228                 }
229                 return hotkeyID;
230             }
231             catch (Exception)
232             {
233                 // clean up if hotkey registration failed
234                 UnregisterGlobalHotKey(hotkeyID, targetForm);
235                 return 0;
236             }
237         }
238
239         // unregister a global hotkey
240         public static void UnregisterGlobalHotKey(ushort hotkeyID, Form targetForm)
241         {
242             if (hotkeyID != 0)
243             {
244                 UnregisterHotKey(targetForm.Handle, hotkeyID);
245                 // clean up the atom list
246                 GlobalDeleteAtom(hotkeyID);
247                 hotkeyID = 0;
248             }
249         }
250         #endregion
251
252         #region "プロセスのProxy設定"
253         [DllImport("wininet.dll", SetLastError =true)]
254         private static extern bool InternetSetOption(IntPtr hInternet,
255                                                      int dwOption,
256                                                      IntPtr lpBuffer,
257                                                      int lpdwBufferLength);
258
259         private struct INTERNET_PROXY_INFO : IDisposable
260         {
261             public int dwAccessType;
262             public IntPtr proxy;
263             public IntPtr proxyBypass;
264
265             public void Dispose()
266             {
267                 Dispose(true);
268             }
269
270             private void Dispose(bool disposing)
271             {
272                 if (proxy != IntPtr.Zero) Marshal.FreeHGlobal(proxy);
273                 if (proxyBypass != IntPtr.Zero) Marshal.FreeHGlobal(proxyBypass);
274             }
275         }
276
277         private static void RefreshProxySettings(string strProxy)
278         {
279             const int INTERNET_OPTION_PROXY = 38;
280             //const int INTERNET_OPEN_TYPE_PRECONFIG = 0;   //IE setting
281             const int INTERNET_OPEN_TYPE_DIRECT = 1;      //Direct
282             const int INTERNET_OPEN_TYPE_PROXY = 3;       //Custom
283
284             INTERNET_PROXY_INFO ipi;
285
286             // Filling in structure
287             if (!string.IsNullOrEmpty(strProxy))
288             {
289                 ipi.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
290                 ipi.proxy = Marshal.StringToHGlobalAnsi(strProxy);
291                 ipi.proxyBypass = Marshal.StringToHGlobalAnsi("local");
292             }
293             else if (strProxy == null)
294             {
295                 //IE Default
296                 var p = WebRequest.GetSystemWebProxy();
297                 if (p.IsBypassed(new Uri("http://www.google.com/")))
298                 {
299                     ipi.dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
300                     ipi.proxy = IntPtr.Zero;
301                     ipi.proxyBypass = IntPtr.Zero;
302                 }
303                 else
304                 {
305                     ipi.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
306                     ipi.proxy = Marshal.StringToHGlobalAnsi(p.GetProxy(new Uri("http://www.google.com/")).Authority);
307                     ipi.proxyBypass = Marshal.StringToHGlobalAnsi("local");
308                 }
309             }
310             else
311             {
312                 ipi.dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
313                 ipi.proxy = IntPtr.Zero;
314                 ipi.proxyBypass = IntPtr.Zero;
315             }
316
317             try
318             {
319                 // Allocating memory
320                 var pIpi = Marshal.AllocCoTaskMem(Marshal.SizeOf(ipi));
321                 if (pIpi.Equals(IntPtr.Zero)) return;
322                 try
323                 {
324                     // Converting structure to IntPtr
325                     Marshal.StructureToPtr(ipi, pIpi, true);
326                     var ret = InternetSetOption(IntPtr.Zero,
327                                                            INTERNET_OPTION_PROXY,
328                                                            pIpi,
329                                                            Marshal.SizeOf(ipi));
330                 }
331                 finally
332                 {
333                     Marshal.FreeCoTaskMem(pIpi);
334                 }
335             }
336             finally
337             {
338                 ipi.Dispose();
339             }
340         }
341
342         private static void RefreshProxyAccount(string username, string password)
343         {
344             const int INTERNET_OPTION_PROXY_USERNAME = 43;
345             const int INTERNET_OPTION_PROXY_PASSWORD = 44;
346
347             if (!string.IsNullOrEmpty(username) || !string.IsNullOrEmpty(password))
348             {
349                 var ret = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY_USERNAME, IntPtr.Zero, 0);
350                 ret = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY_PASSWORD, IntPtr.Zero, 0);
351             }
352             else
353             {
354                 var pUser = Marshal.StringToBSTR(username);
355                 var pPass = Marshal.StringToBSTR(password);
356                 try
357                 {
358                     var ret = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY_USERNAME, pUser, username.Length + 1);
359                     ret = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY_PASSWORD, pPass, password.Length + 1);
360                 }
361                 finally
362                 {
363                     Marshal.FreeBSTR(pUser);
364                     Marshal.FreeBSTR(pPass);
365                 }
366             }
367         }
368
369         public static void SetProxy(ProxyType pType, string host, int port, string username, string password)
370         {
371             string proxy = null;
372             switch (pType)
373             {
374             case ProxyType.IE:
375                 proxy = null;
376                 break;
377             case ProxyType.None:
378                 proxy = "";
379                 break;
380             case ProxyType.Specified:
381                 proxy = host + (port > 0 ? ":" + port.ToString() : "");
382                 break;
383             }
384             RefreshProxySettings(proxy);
385             RefreshProxyAccount(username, password);
386         }
387 #endregion
388     }
389 }