回答編集履歴

6

誤字を修正

2019/05/12 10:57

投稿

atata0319
atata0319

スコア881

test CHANGED
@@ -388,4 +388,4 @@
388
388
 
389
389
  ```
390
390
 
391
- 見ていただくとわかる通り ____fastcall ではありません。該当ページのサンプルを見てもらったら分かる通り、____fastcall だけ外せば問題ないかと思います。
391
+ 見ていただくとわかる通り ____fastcall ではありません。該当ページのサンプルにならっ____fastcall を外していただけば問題ないかと思います。

5

_beginthread の定義を追記

2019/05/12 10:57

投稿

atata0319
atata0319

スコア881

test CHANGED
@@ -367,3 +367,25 @@
367
367
  }
368
368
 
369
369
  ```
370
+
371
+
372
+
373
+ ---
374
+
375
+
376
+
377
+ 追記4
378
+
379
+ もはや C++ Builder の話なので別質問を立ててもらった方が良いと思いますが、内容が少ないので合わせて回答します。
380
+
381
+ C++ Builder の[リファレンス](http://docwiki.embarcadero.com/RADStudio/Rio/ja/Beginthread)では以下のように定義されています。
382
+
383
+
384
+
385
+ ```C++
386
+
387
+ unsigned long _beginthread(void (_USERENTRY *__start)(void *), unsigned __stksize, void *__arg);
388
+
389
+ ```
390
+
391
+ 見ていただくとわかる通り ____fastcall ではありません。該当ページのサンプルを見てもらったら分かる通り、____fastcall だけ外せば問題ないかと思います。

4

SetThreadDesktop の用法誤りを訂正

2019/05/12 10:55

投稿

atata0319
atata0319

スコア881

test CHANGED
@@ -121,3 +121,249 @@
121
121
  ```
122
122
 
123
123
  考えてみたら質問者が作成されているプログラムは Windows アプリであるためデスクトップを切り替えた後、元に戻さないと正しく動作しないので、その処理も組み込んであります。スレッド単位での切り替えになるので、スクリーンセーバー解除処理だけを別スレッドで実行しても良いかと思います。
124
+
125
+
126
+
127
+ ---
128
+
129
+
130
+
131
+ 追記3
132
+
133
+ あまり使わない API だったのですっかり忘れてましたが、一回ウィンドウ作成したら SetThreadDesktop は失敗します。この場合、別スレッドが必須でした。昔の C++ Builder でも _beginthread は有効でしたので、VC++ のコードのまま提示します。
134
+
135
+
136
+
137
+ ```C++
138
+
139
+ // 標準ヘッダー宣言
140
+
141
+ #include <windows.h>
142
+
143
+ #include <process.h>
144
+
145
+
146
+
147
+ // プロトタイプ宣言
148
+
149
+ LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
150
+
151
+ char szClassName[] = "ウィンドウクラス・ネーム";
152
+
153
+ void screenSaver(void*);
154
+
155
+
156
+
157
+ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst,
158
+
159
+ LPSTR lpszCmdLine, int nCmdShow)
160
+
161
+ {
162
+
163
+ HWND hWnd;
164
+
165
+ MSG msg;
166
+
167
+ WNDCLASS myProg;
168
+
169
+ bool screensaver;
170
+
171
+ HDC hdc;
172
+
173
+ PAINTSTRUCT ps;
174
+
175
+
176
+
177
+ // ウィンドウ・クラスの登録
178
+
179
+ if (!hPreInst)
180
+
181
+ {
182
+
183
+ myProg.style = CS_HREDRAW | CS_VREDRAW;
184
+
185
+ myProg.lpfnWndProc = WndProc; // プロシージャ名
186
+
187
+ myProg.cbClsExtra = 0;
188
+
189
+ myProg.cbWndExtra = 0;
190
+
191
+ myProg.hInstance = hInstance; // インスタンス
192
+
193
+ myProg.hIcon = NULL;
194
+
195
+ myProg.hCursor = LoadCursor(NULL, IDC_ARROW);
196
+
197
+ myProg.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
198
+
199
+ myProg.lpszMenuName = NULL;
200
+
201
+ myProg.lpszClassName = szClassName;
202
+
203
+ if (!RegisterClass(&myProg))
204
+
205
+ {
206
+
207
+ return (false);
208
+
209
+ }
210
+
211
+ }
212
+
213
+
214
+
215
+ // ウィンドウの生成
216
+
217
+ hWnd = CreateWindow(szClassName,
218
+
219
+ "猫でも分かるプログラミング", // タイトルバーにこの名前が表示される
220
+
221
+ WS_OVERLAPPEDWINDOW, // ウィンドウの種類
222
+
223
+ CW_USEDEFAULT, // X座標
224
+
225
+ CW_USEDEFAULT, // Y座標
226
+
227
+ CW_USEDEFAULT, // 幅
228
+
229
+ CW_USEDEFAULT, // 高さ
230
+
231
+ NULL, // 親ウィンドウのハンドル,親を作るときはNULL
232
+
233
+ NULL, // メニューハンドル,クラスメニューを使うときはNULL
234
+
235
+ hInstance, // インスタンスハンドル
236
+
237
+ NULL);
238
+
239
+ ShowWindow(hWnd, nCmdShow);
240
+
241
+ UpdateWindow(hWnd);
242
+
243
+ while (GetMessage(&msg, NULL, 0, 0))
244
+
245
+ {
246
+
247
+ TranslateMessage(&msg);
248
+
249
+ DispatchMessage(&msg);
250
+
251
+ // 下記モジュールのみをコールするだけだとスクリーンセーバーがかからないので,
252
+
253
+ // スクリーンセーバーの抑止(キーボードの押す/離す)していることを確認
254
+
255
+ // screenSaver(hWnd); // スクリーンセーバーの解除
256
+
257
+
258
+
259
+ // スクリーンセーバー状態の取得
260
+
261
+ SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, (void *)&screensaver, 0);
262
+
263
+ // SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, (void *)&screensaver, 0);
264
+
265
+ // スクリーンセーバーが有効の場合
266
+
267
+ if (screensaver == true)
268
+
269
+ {
270
+
271
+ // 5秒後
272
+
273
+ Sleep(5000);
274
+
275
+
276
+
277
+ // ウィンドウを作成すると SetThreadDesktop できないのでスレッドを起動する。
278
+
279
+ _beginthread(screenSaver, 0, NULL);
280
+
281
+ }
282
+
283
+ }
284
+
285
+ return (int)msg.wParam;
286
+
287
+ }
288
+
289
+
290
+
291
+ // ウィンドウプロシージャ
292
+
293
+ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
294
+
295
+ {
296
+
297
+ switch (msg)
298
+
299
+ {
300
+
301
+ case WM_DESTROY:
302
+
303
+ PostQuitMessage(0);
304
+
305
+ break;
306
+
307
+ default:
308
+
309
+ return (DefWindowProc(hWnd, msg, wParam, lParam));
310
+
311
+ }
312
+
313
+
314
+
315
+ return (0L);
316
+
317
+ }
318
+
319
+
320
+
321
+ void screenSaver(void*)
322
+
323
+ {
324
+
325
+ // 元のデスクトップハンドルを退避
326
+
327
+ HDESK hdesk_old = GetThreadDesktop(GetCurrentThreadId());
328
+
329
+ // スクリーンセーバーのデスクトップを開く
330
+
331
+ // HDESK hdesk = OpenDesktop(L"Screen-saver", 0, FALSE, GENERIC_ALL);
332
+
333
+ HDESK hdesk = OpenDesktop("Screen-saver", 0, FALSE, GENERIC_ALL);
334
+
335
+ if (hdesk != NULL)
336
+
337
+ {
338
+
339
+ // 現在のスレッドのデスクトップを変更
340
+
341
+ SetThreadDesktop(hdesk);
342
+
343
+ }
344
+
345
+ // スクリーンセーバー解除処理
346
+
347
+ keybd_event(VK_ESCAPE, 0, 0, 0);
348
+
349
+ keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
350
+
351
+
352
+
353
+ // 元のデスクトップに戻す
354
+
355
+ SetThreadDesktop(hdesk_old);
356
+
357
+ if (hdesk != NULL)
358
+
359
+ {
360
+
361
+ CloseDesktop(hdesk);
362
+
363
+ }
364
+
365
+
366
+
367
+ }
368
+
369
+ ```

3

コードの誤りを修正

2019/05/11 17:51

投稿

atata0319
atata0319

スコア881

test CHANGED
@@ -68,15 +68,25 @@
68
68
 
69
69
 
70
70
 
71
+ // 元のデスクトップハンドルを退避しておく。
72
+
73
+ HDESK hdeskOld = GetThreadDesktop(GetCurrentThreadId());
74
+
75
+
76
+
71
77
  // スクリーンセーバーのデスクトップを開く
72
78
 
73
79
  HDESK hdesk = OpenDesktop(L"Screen-saver", 0, FALSE, GENERIC_ALL);
74
80
 
81
+ if (hdesk != NULL)
75
82
 
83
+ {
76
84
 
77
- // 現在のスレッドのデスクトップを変更
85
+ // 現在のスレッドのデスクトップを変更
78
86
 
79
- SetThreadDesktop(hdesk);
87
+ SetThreadDesktop(hdesk);
88
+
89
+ }
80
90
 
81
91
 
82
92
 
@@ -88,7 +98,19 @@
88
98
 
89
99
 
90
100
 
101
+ // 元のデスクトップに戻す。
102
+
103
+ SetThreadDesktop(hdeskOld);
104
+
105
+
106
+
107
+ if (hdesk != NULL)
108
+
109
+ {
110
+
91
- CloseDesktop(hdesk);
111
+ CloseDesktop(hdesk);
112
+
113
+ }
92
114
 
93
115
 
94
116
 
@@ -97,3 +119,5 @@
97
119
  }
98
120
 
99
121
  ```
122
+
123
+ 考えてみたら質問者が作成されているプログラムは Windows アプリであるためデスクトップを切り替えた後、元に戻さないと正しく動作しないので、その処理も組み込んであります。スレッド単位での切り替えになるので、スクリーンセーバー解除処理だけを別スレッドで実行しても良いかと思います。

2

修正コードを追記

2019/05/11 10:45

投稿

atata0319
atata0319

スコア881

test CHANGED
@@ -37,3 +37,63 @@
37
37
  追記
38
38
 
39
39
  どうやら通常起動時もスクリーンセーバーは別デスクトップで動作するようになっているようです。提示のコードでスクリーンセーバーを解除できるのはプレビューモード時のみでした。
40
+
41
+
42
+
43
+ ---
44
+
45
+
46
+
47
+ 追記2
48
+
49
+ コメントを受けて作成したコードになります。紆余曲折ありましたが、もっとも簡単そうなサンプルということでこのようになりました。Windows 10 ではこれでスクリーンセーバーを解除できています。なお、『再開時にログオン画面に戻る』設定が有効である場合もログオン画面までは表示されます。
50
+
51
+
52
+
53
+ ```C++
54
+
55
+ #define UNICODE
56
+
57
+ #include <windows.h>
58
+
59
+
60
+
61
+ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
62
+
63
+ {
64
+
65
+ // スクリーンセーバー起動まで待機
66
+
67
+ Sleep(90000);
68
+
69
+
70
+
71
+ // スクリーンセーバーのデスクトップを開く
72
+
73
+ HDESK hdesk = OpenDesktop(L"Screen-saver", 0, FALSE, GENERIC_ALL);
74
+
75
+
76
+
77
+ // 現在のスレッドのデスクトップを変更
78
+
79
+ SetThreadDesktop(hdesk);
80
+
81
+
82
+
83
+ // スクリーンセーバー解除処理を実施
84
+
85
+ keybd_event(VK_ESCAPE, 0, 0, 0);
86
+
87
+ keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
88
+
89
+
90
+
91
+ CloseDesktop(hdesk);
92
+
93
+
94
+
95
+ return 0;
96
+
97
+ }
98
+
99
+ ```

1

回答内容の誤りを修正

2019/05/11 07:31

投稿

atata0319
atata0319

スコア881

test CHANGED
@@ -1,4 +1,4 @@
1
- Windows 標準のスクリーンセーバーは WM_KEYDOWN イベントでスクリーンセーブ状態が解除されるため、提示のコードでは解除できません。キーを押すことと離すことをエミュレートするために以下のようにする必要があります。
1
+ ~~Windows 標準のスクリーンセーバーは WM_KEYDOWN イベントでスクリーンセーブ状態が解除されるため、提示のコードでは解除できません。キーを押すことと離すことをエミュレートするために以下のようにする必要があります。~~
2
2
 
3
3
  ```C
4
4
 
@@ -10,13 +10,13 @@
10
10
 
11
11
 
12
12
 
13
- ただし、上記のコードはスクリーンセーバーがプレビューモードで起動しているときか『再開時にログオン画面に戻る』設定が無効な場合のみ動作します。
13
+ ~~ただし、上記のコードはスクリーンセーバーがプレビューモードで起動しているときか『再開時にログオン画面に戻る』設定が無効な場合のみ動作します。~~
14
14
 
15
15
 
16
16
 
17
17
  ![スクリーンセーバーの設定](b84909e4afd73d30f622144c68449ef1.png)
18
18
 
19
- 上図のように『再開時にログオン画面に戻る』設定が有効である場合、スクリーンセーバーは別デスクトップで動作するため、現在画面が起動しているデスクトップからキーボードイベントを送信することはできません。その場合、別デスクトップに対してキーボードイベントを送信する必要があるのですが、現在ログオンしているセッションとは別のセッションとなるため操作できない気がしました。試すのは面白そうな題材ではありますが。
19
+ ~~上図のように『再開時にログオン画面に戻る』設定が有効である場合、スクリーンセーバーは別デスクトップで動作するため、現在画面が起動しているデスクトップからキーボードイベントを送信することはできません。その場合、別デスクトップに対してキーボードイベントを送信する必要があるのですが、現在ログオンしているセッションとは別のセッションとなるため操作できない気がしました。試すのは面白そうな題材ではありますが。~~
20
20
 
21
21
 
22
22
 
@@ -27,3 +27,13 @@
27
27
 
28
28
 
29
29
  余談ですが、20年ぐらい前に VC++ と BCB を比較したときに VC++ より BCB の方が Visual だなと思ったのが懐かしい記憶です。それ以来 C++ Builder は主を変え続ける状況になったのが残念なことです。
30
+
31
+
32
+
33
+ ---
34
+
35
+
36
+
37
+ 追記
38
+
39
+ どうやら通常起動時もスクリーンセーバーは別デスクトップで動作するようになっているようです。提示のコードでスクリーンセーバーを解除できるのはプレビューモード時のみでした。