-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathShintaCommonWindows.cs
200 lines (178 loc) · 6.48 KB
/
ShintaCommonWindows.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// ============================================================================
//
// よく使う一般的な定数や関数(Windows に依存するもの)
// Copyright (C) 2021-2024 by SHINTA
//
// ============================================================================
// ----------------------------------------------------------------------------
// 以下のパッケージがインストールされている前提
// Microsoft.Windows.CsWin32
// ----------------------------------------------------------------------------
// ============================================================================
// Ver. | 更新日 | 更新内容
// ----------------------------------------------------------------------------
// -.-- | 2021/03/28 (Sun) | 作成開始。
// 1.00 | 2021/03/28 (Sun) | ShintaCommon より移管。
// (1.01) | 2022/02/02 (Wed) | GetMonitorRects() を作成。
// (1.02) | 2022/02/06 (Sun) | GetMonitorRects() を廃止。
// (1.03) | 2023/11/19 (Sun) | Microsoft.Windows.CsWin32 パッケージを導入。
// 1.10 | 2024/04/08 (Mon) | IsMsix() を作成。
// 1.20 | 2024/04/08 (Mon) | SettingsFolder() を作成。
// (1.21) | 2024/04/08 (Mon) | AdjustWindowRect() を廃止。
// ============================================================================
using Windows.Storage;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.WindowsAndMessaging;
namespace Shinta;
public class CommonWindows
{
// ====================================================================
// public 関数
// ====================================================================
/// <summary>
/// ミューテックスを取得できない場合は、同名のプロセスのウィンドウをアクティベートする
/// </summary>
/// <param name="mutexName"></param>
/// <returns>既存プロセスが存在しミューテックスが取得できなかった場合:null
/// 既存プロセスが存在せずミューテックスが取得できた場合:取得したミューテックス(使い終わった後で呼び出し元にて解放する必要がある) </returns>
public static Mutex? ActivateAnotherProcessWindowIfNeeded(String mutexName)
{
// ミューテックスを取得する
Mutex ownedMutex = new(false, mutexName);
try
{
if (ownedMutex.WaitOne(0))
{
// ミューテックスを取得できた
return ownedMutex;
}
}
catch (AbandonedMutexException)
{
// ミューテックスが放棄されていた場合にこの例外となるが、取得自体はできている
return ownedMutex;
}
// ミューテックスが取得できなかったため、同名プロセスを探し、そのウィンドウをアクティベートする
ActivateSameNameProcessWindow();
return null;
}
/// <summary>
/// 外部プロセスのウィンドウをアクティベートする
/// </summary>
/// <param name="hWnd"></param>
public static void ActivateExternalWindow(HWND hWnd)
{
if (hWnd.IsNull)
{
return;
}
// ウィンドウが最小化されていれば元に戻す
if (PInvoke.IsIconic(hWnd))
{
PInvoke.ShowWindowAsync(hWnd, SHOW_WINDOW_CMD.SW_RESTORE);
}
// アクティベート
PInvoke.SetForegroundWindow(hWnd);
}
/// <summary>
/// 指定プロセスと同名プロセスのウィンドウをアクティベートする
/// </summary>
/// <param name="specifyProcess"></param>
public static void ActivateSameNameProcessWindow(Process? specifyProcess = null)
{
List<Process> sameNameProcesses = Common.SameNameProcesses(specifyProcess);
if (sameNameProcesses.Any())
{
ActivateExternalWindow((HWND)sameNameProcesses[0].MainWindowHandle);
}
}
#if false
/// <summary>
/// ウィンドウがスクリーンから完全にはみ出している場合はスクリーン内に移動する
/// 必要であれば WPF 用のライブラリに移す
/// </summary>
/// <param name="windowRect"></param>
/// <returns></returns>
public static Rect AdjustWindowRect(Rect windowRect)
{
Rect screenRect = new(0, 0, SystemParameters.VirtualScreenWidth, SystemParameters.VirtualScreenHeight);
// ウィンドウとスクリーンがぴったりの場合は移動不要
if (screenRect == windowRect)
{
return windowRect;
}
// ウィンドウとスクリーンが一部重なっている場合は移動不要
// ※ウィンドウがスクリーンより完全に大きい場合を除く
Rect intersect = Rect.Intersect(screenRect, windowRect);
if (!intersect.IsEmpty && intersect != screenRect)
{
return windowRect;
}
// 移動の必要がある
return new Rect(0, 0, windowRect.Width, windowRect.Height);
}
#endif
/// <summary>
/// ZoneID を削除
/// </summary>
/// <param name="path"></param>
/// <returns>削除できたら true</returns>
public static Boolean DeleteZoneID(String path)
{
return PInvoke.DeleteFile(path + STREAM_NAME_ZONE_ID);
}
/// <summary>
/// ZoneID を削除(フォルダ配下のすべてのファイル)
/// </summary>
/// <param name="folder"></param>
/// <param name="option"></param>
/// <returns>ファイル列挙で何らかのエラーが発生したら Error、削除できなくても Ok は返る</returns>
public static Boolean DeleteZoneID(String folder, SearchOption option)
{
try
{
String[] files = Directory.GetFiles(folder, "*", option);
foreach (String file in files)
{
DeleteZoneID(file);
}
}
catch
{
return false;
}
return true;
}
/// <summary>
/// MSIX パッケージで実行されているかどうか
/// </summary>
/// <returns></returns>
public static Boolean IsMsix()
{
UInt32 length = 0;
WIN32_ERROR error = PInvoke.GetCurrentPackageFullName(ref length, null);
return !error.HasFlag(WIN32_ERROR.APPMODEL_ERROR_NO_PACKAGE);
}
/// <summary>
/// 設定保存用フォルダー(末尾 '\\')
/// </summary>
/// <returns></returns>
public static String SettingsFolder()
{
if (IsMsix())
{
// MSIX パッケージの場合は Local\Packages\... 配下
return Path.GetDirectoryName(ApplicationData.Current.LocalFolder.Path) + "\\" + Common.FOLDER_NAME_SETTINGS;
}
else
{
// 非 MSIX パッケージの場合は Roaming\SHINTA\... 配下
return Common.UserAppDataFolderPath();
}
}
// ====================================================================
// private 定数
// ====================================================================
private const String STREAM_NAME_ZONE_ID = ":Zone.Identifier";
}