回答編集履歴
6
誤字を修正
    
        answer	
    CHANGED
    
    | @@ -193,4 +193,4 @@ | |
| 193 193 | 
             
            ```C++
         | 
| 194 194 | 
             
            unsigned long _beginthread(void (_USERENTRY *__start)(void *), unsigned __stksize, void *__arg);
         | 
| 195 195 | 
             
            ```
         | 
| 196 | 
            -
            見ていただくとわかる通り ____fastcall ではありません。該当ページのサンプル | 
| 196 | 
            +
            見ていただくとわかる通り ____fastcall ではありません。該当ページのサンプルにならって ____fastcall を外していただければ問題ないかと思います。
         | 
5
_beginthread の定義を追記
    
        answer	
    CHANGED
    
    | @@ -182,4 +182,15 @@ | |
| 182 182 | 
             
            	}
         | 
| 183 183 |  | 
| 184 184 | 
             
            }
         | 
| 185 | 
            -
            ```
         | 
| 185 | 
            +
            ```
         | 
| 186 | 
            +
             | 
| 187 | 
            +
            ---
         | 
| 188 | 
            +
             | 
| 189 | 
            +
            追記4
         | 
| 190 | 
            +
            もはや C++ Builder の話なので別質問を立ててもらった方が良いと思いますが、内容が少ないので合わせて回答します。
         | 
| 191 | 
            +
            C++ Builder の[リファレンス](http://docwiki.embarcadero.com/RADStudio/Rio/ja/Beginthread)では以下のように定義されています。
         | 
| 192 | 
            +
             | 
| 193 | 
            +
            ```C++
         | 
| 194 | 
            +
            unsigned long _beginthread(void (_USERENTRY *__start)(void *), unsigned __stksize, void *__arg);
         | 
| 195 | 
            +
            ```
         | 
| 196 | 
            +
            見ていただくとわかる通り ____fastcall ではありません。該当ページのサンプルを見てもらったら分かる通り、____fastcall だけ外せば問題ないかと思います。
         | 
4
SetThreadDesktop の用法誤りを訂正
    
        answer	
    CHANGED
    
    | @@ -59,4 +59,127 @@ | |
| 59 59 | 
             
            	return 0;
         | 
| 60 60 | 
             
            }
         | 
| 61 61 | 
             
            ```
         | 
| 62 | 
            -
            考えてみたら質問者が作成されているプログラムは Windows アプリであるためデスクトップを切り替えた後、元に戻さないと正しく動作しないので、その処理も組み込んであります。スレッド単位での切り替えになるので、スクリーンセーバー解除処理だけを別スレッドで実行しても良いかと思います。
         | 
| 62 | 
            +
            考えてみたら質問者が作成されているプログラムは Windows アプリであるためデスクトップを切り替えた後、元に戻さないと正しく動作しないので、その処理も組み込んであります。スレッド単位での切り替えになるので、スクリーンセーバー解除処理だけを別スレッドで実行しても良いかと思います。
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            ---
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            追記3
         | 
| 67 | 
            +
            あまり使わない API だったのですっかり忘れてましたが、一回ウィンドウ作成したら SetThreadDesktop は失敗します。この場合、別スレッドが必須でした。昔の C++ Builder でも _beginthread は有効でしたので、VC++ のコードのまま提示します。
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            ```C++
         | 
| 70 | 
            +
            //    標準ヘッダー宣言
         | 
| 71 | 
            +
            #include <windows.h>
         | 
| 72 | 
            +
            #include <process.h>
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            //    プロトタイプ宣言
         | 
| 75 | 
            +
            LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
         | 
| 76 | 
            +
            char szClassName[] = "ウィンドウクラス・ネーム";
         | 
| 77 | 
            +
            void screenSaver(void*);
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst,
         | 
| 80 | 
            +
            	LPSTR lpszCmdLine, int nCmdShow)
         | 
| 81 | 
            +
            {
         | 
| 82 | 
            +
            	HWND        hWnd;
         | 
| 83 | 
            +
            	MSG            msg;
         | 
| 84 | 
            +
            	WNDCLASS    myProg;
         | 
| 85 | 
            +
            	bool        screensaver;
         | 
| 86 | 
            +
            	HDC hdc;
         | 
| 87 | 
            +
            	PAINTSTRUCT ps;
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            	//    ウィンドウ・クラスの登録
         | 
| 90 | 
            +
            	if (!hPreInst)
         | 
| 91 | 
            +
            	{
         | 
| 92 | 
            +
            		myProg.style = CS_HREDRAW | CS_VREDRAW;
         | 
| 93 | 
            +
            		myProg.lpfnWndProc = WndProc;                        //    プロシージャ名
         | 
| 94 | 
            +
            		myProg.cbClsExtra = 0;
         | 
| 95 | 
            +
            		myProg.cbWndExtra = 0;
         | 
| 96 | 
            +
            		myProg.hInstance = hInstance;                        //    インスタンス
         | 
| 97 | 
            +
            		myProg.hIcon = NULL;
         | 
| 98 | 
            +
            		myProg.hCursor = LoadCursor(NULL, IDC_ARROW);
         | 
| 99 | 
            +
            		myProg.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
         | 
| 100 | 
            +
            		myProg.lpszMenuName = NULL;
         | 
| 101 | 
            +
            		myProg.lpszClassName = szClassName;
         | 
| 102 | 
            +
            		if (!RegisterClass(&myProg))
         | 
| 103 | 
            +
            		{
         | 
| 104 | 
            +
            			return (false);
         | 
| 105 | 
            +
            		}
         | 
| 106 | 
            +
            	}
         | 
| 107 | 
            +
             | 
| 108 | 
            +
            	//    ウィンドウの生成
         | 
| 109 | 
            +
            	hWnd = CreateWindow(szClassName,
         | 
| 110 | 
            +
            		"猫でも分かるプログラミング",            //    タイトルバーにこの名前が表示される
         | 
| 111 | 
            +
            		WS_OVERLAPPEDWINDOW,                    //    ウィンドウの種類
         | 
| 112 | 
            +
            		CW_USEDEFAULT,                            //    X座標
         | 
| 113 | 
            +
            		CW_USEDEFAULT,                            //    Y座標
         | 
| 114 | 
            +
            		CW_USEDEFAULT,                            //    幅
         | 
| 115 | 
            +
            		CW_USEDEFAULT,                            //    高さ
         | 
| 116 | 
            +
            		NULL,                                    //    親ウィンドウのハンドル,親を作るときはNULL
         | 
| 117 | 
            +
            		NULL,                                    //  メニューハンドル,クラスメニューを使うときはNULL
         | 
| 118 | 
            +
            		hInstance,                                //    インスタンスハンドル
         | 
| 119 | 
            +
            		NULL);
         | 
| 120 | 
            +
            	ShowWindow(hWnd, nCmdShow);
         | 
| 121 | 
            +
            	UpdateWindow(hWnd);
         | 
| 122 | 
            +
            	while (GetMessage(&msg, NULL, 0, 0))
         | 
| 123 | 
            +
            	{
         | 
| 124 | 
            +
            		TranslateMessage(&msg);
         | 
| 125 | 
            +
            		DispatchMessage(&msg);
         | 
| 126 | 
            +
            		//    下記モジュールのみをコールするだけだとスクリーンセーバーがかからないので,
         | 
| 127 | 
            +
            		//    スクリーンセーバーの抑止(キーボードの押す/離す)していることを確認
         | 
| 128 | 
            +
            //        screenSaver(hWnd);                        //    スクリーンセーバーの解除
         | 
| 129 | 
            +
             | 
| 130 | 
            +
            		//    スクリーンセーバー状態の取得
         | 
| 131 | 
            +
            		SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, (void *)&screensaver, 0);
         | 
| 132 | 
            +
            		//        SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, (void *)&screensaver, 0);
         | 
| 133 | 
            +
            				//    スクリーンセーバーが有効の場合
         | 
| 134 | 
            +
            		if (screensaver == true)
         | 
| 135 | 
            +
            		{
         | 
| 136 | 
            +
            			//    5秒後
         | 
| 137 | 
            +
            			Sleep(5000);
         | 
| 138 | 
            +
             | 
| 139 | 
            +
            			// ウィンドウを作成すると SetThreadDesktop できないのでスレッドを起動する。
         | 
| 140 | 
            +
            			_beginthread(screenSaver, 0, NULL);
         | 
| 141 | 
            +
            		}
         | 
| 142 | 
            +
            	}
         | 
| 143 | 
            +
            	return (int)msg.wParam;
         | 
| 144 | 
            +
            }
         | 
| 145 | 
            +
             | 
| 146 | 
            +
            //    ウィンドウプロシージャ
         | 
| 147 | 
            +
            LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
         | 
| 148 | 
            +
            {
         | 
| 149 | 
            +
            	switch (msg)
         | 
| 150 | 
            +
            	{
         | 
| 151 | 
            +
            	case WM_DESTROY:
         | 
| 152 | 
            +
            		PostQuitMessage(0);
         | 
| 153 | 
            +
            		break;
         | 
| 154 | 
            +
            	default:
         | 
| 155 | 
            +
            		return (DefWindowProc(hWnd, msg, wParam, lParam));
         | 
| 156 | 
            +
            	}
         | 
| 157 | 
            +
             | 
| 158 | 
            +
            	return (0L);
         | 
| 159 | 
            +
            }
         | 
| 160 | 
            +
             | 
| 161 | 
            +
            void screenSaver(void*)
         | 
| 162 | 
            +
            {
         | 
| 163 | 
            +
            	//    元のデスクトップハンドルを退避
         | 
| 164 | 
            +
            	HDESK hdesk_old = GetThreadDesktop(GetCurrentThreadId());
         | 
| 165 | 
            +
            	//    スクリーンセーバーのデスクトップを開く
         | 
| 166 | 
            +
            //    HDESK hdesk = OpenDesktop(L"Screen-saver", 0, FALSE, GENERIC_ALL);
         | 
| 167 | 
            +
            	HDESK hdesk = OpenDesktop("Screen-saver", 0, FALSE, GENERIC_ALL);
         | 
| 168 | 
            +
            	if (hdesk != NULL)
         | 
| 169 | 
            +
            	{
         | 
| 170 | 
            +
            		//    現在のスレッドのデスクトップを変更
         | 
| 171 | 
            +
            		SetThreadDesktop(hdesk);
         | 
| 172 | 
            +
            	}
         | 
| 173 | 
            +
            	//    スクリーンセーバー解除処理
         | 
| 174 | 
            +
            	keybd_event(VK_ESCAPE, 0, 0, 0);
         | 
| 175 | 
            +
            	keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
         | 
| 176 | 
            +
             | 
| 177 | 
            +
            	//    元のデスクトップに戻す
         | 
| 178 | 
            +
            	SetThreadDesktop(hdesk_old);
         | 
| 179 | 
            +
            	if (hdesk != NULL)
         | 
| 180 | 
            +
            	{
         | 
| 181 | 
            +
            		CloseDesktop(hdesk);
         | 
| 182 | 
            +
            	}
         | 
| 183 | 
            +
             | 
| 184 | 
            +
            }
         | 
| 185 | 
            +
            ```
         | 
3
コードの誤りを修正
    
        answer	
    CHANGED
    
    | @@ -33,18 +33,30 @@ | |
| 33 33 | 
             
            	// スクリーンセーバー起動まで待機
         | 
| 34 34 | 
             
            	Sleep(90000);
         | 
| 35 35 |  | 
| 36 | 
            +
            	// 元のデスクトップハンドルを退避しておく。
         | 
| 37 | 
            +
            	HDESK hdeskOld = GetThreadDesktop(GetCurrentThreadId());
         | 
| 38 | 
            +
             | 
| 36 39 | 
             
            	// スクリーンセーバーのデスクトップを開く
         | 
| 37 40 | 
             
            	HDESK hdesk = OpenDesktop(L"Screen-saver", 0, FALSE, GENERIC_ALL);
         | 
| 41 | 
            +
            	if (hdesk != NULL)
         | 
| 42 | 
            +
            	{
         | 
| 43 | 
            +
            		// 現在のスレッドのデスクトップを変更
         | 
| 44 | 
            +
            		SetThreadDesktop(hdesk);
         | 
| 45 | 
            +
            	}
         | 
| 38 46 |  | 
| 39 | 
            -
            	// 現在のスレッドのデスクトップを変更
         | 
| 40 | 
            -
            	SetThreadDesktop(hdesk);
         | 
| 41 | 
            -
             | 
| 42 47 | 
             
            	// スクリーンセーバー解除処理を実施
         | 
| 43 48 | 
             
            	keybd_event(VK_ESCAPE, 0, 0, 0);
         | 
| 44 49 | 
             
            	keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
         | 
| 45 50 |  | 
| 51 | 
            +
            	// 元のデスクトップに戻す。
         | 
| 46 | 
            -
            	 | 
| 52 | 
            +
            	SetThreadDesktop(hdeskOld);
         | 
| 47 53 |  | 
| 54 | 
            +
            	if (hdesk != NULL)
         | 
| 55 | 
            +
            	{
         | 
| 56 | 
            +
            		CloseDesktop(hdesk);
         | 
| 57 | 
            +
            	}
         | 
| 58 | 
            +
             | 
| 48 59 | 
             
            	return 0;
         | 
| 49 60 | 
             
            }
         | 
| 50 | 
            -
            ```
         | 
| 61 | 
            +
            ```
         | 
| 62 | 
            +
            考えてみたら質問者が作成されているプログラムは Windows アプリであるためデスクトップを切り替えた後、元に戻さないと正しく動作しないので、その処理も組み込んであります。スレッド単位での切り替えになるので、スクリーンセーバー解除処理だけを別スレッドで実行しても良いかと思います。
         | 
2
修正コードを追記
    
        answer	
    CHANGED
    
    | @@ -17,4 +17,34 @@ | |
| 17 17 | 
             
            ---
         | 
| 18 18 |  | 
| 19 19 | 
             
            追記
         | 
| 20 | 
            -
            どうやら通常起動時もスクリーンセーバーは別デスクトップで動作するようになっているようです。提示のコードでスクリーンセーバーを解除できるのはプレビューモード時のみでした。
         | 
| 20 | 
            +
            どうやら通常起動時もスクリーンセーバーは別デスクトップで動作するようになっているようです。提示のコードでスクリーンセーバーを解除できるのはプレビューモード時のみでした。
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            ---
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            追記2
         | 
| 25 | 
            +
            コメントを受けて作成したコードになります。紆余曲折ありましたが、もっとも簡単そうなサンプルということでこのようになりました。Windows 10 ではこれでスクリーンセーバーを解除できています。なお、『再開時にログオン画面に戻る』設定が有効である場合もログオン画面までは表示されます。
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            ```C++
         | 
| 28 | 
            +
            #define UNICODE
         | 
| 29 | 
            +
            #include <windows.h>
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
         | 
| 32 | 
            +
            {
         | 
| 33 | 
            +
            	// スクリーンセーバー起動まで待機
         | 
| 34 | 
            +
            	Sleep(90000);
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            	// スクリーンセーバーのデスクトップを開く
         | 
| 37 | 
            +
            	HDESK hdesk = OpenDesktop(L"Screen-saver", 0, FALSE, GENERIC_ALL);
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            	// 現在のスレッドのデスクトップを変更
         | 
| 40 | 
            +
            	SetThreadDesktop(hdesk);
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            	// スクリーンセーバー解除処理を実施
         | 
| 43 | 
            +
            	keybd_event(VK_ESCAPE, 0, 0, 0);
         | 
| 44 | 
            +
            	keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            	CloseDesktop(hdesk);
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            	return 0;
         | 
| 49 | 
            +
            }
         | 
| 50 | 
            +
            ```
         | 
1
回答内容の誤りを修正
    
        answer	
    CHANGED
    
    | @@ -1,15 +1,20 @@ | |
| 1 | 
            -
            Windows 標準のスクリーンセーバーは WM_KEYDOWN イベントでスクリーンセーブ状態が解除されるため、提示のコードでは解除できません。キーを押すことと離すことをエミュレートするために以下のようにする必要があります。
         | 
| 1 | 
            +
            ~~Windows 標準のスクリーンセーバーは WM_KEYDOWN イベントでスクリーンセーブ状態が解除されるため、提示のコードでは解除できません。キーを押すことと離すことをエミュレートするために以下のようにする必要があります。~~
         | 
| 2 2 | 
             
            ```C
         | 
| 3 3 | 
             
            keybd_event( VK_ESCAPE, 0, 0, 0 );
         | 
| 4 4 | 
             
            keybd_event( VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0 );
         | 
| 5 5 | 
             
            ```
         | 
| 6 6 |  | 
| 7 | 
            -
            ただし、上記のコードはスクリーンセーバーがプレビューモードで起動しているときか『再開時にログオン画面に戻る』設定が無効な場合のみ動作します。
         | 
| 7 | 
            +
            ~~ただし、上記のコードはスクリーンセーバーがプレビューモードで起動しているときか『再開時にログオン画面に戻る』設定が無効な場合のみ動作します。~~
         | 
| 8 8 |  | 
| 9 9 | 
             
            
         | 
| 10 | 
            -
            上図のように『再開時にログオン画面に戻る』設定が有効である場合、スクリーンセーバーは別デスクトップで動作するため、現在画面が起動しているデスクトップからキーボードイベントを送信することはできません。その場合、別デスクトップに対してキーボードイベントを送信する必要があるのですが、現在ログオンしているセッションとは別のセッションとなるため操作できない気がしました。試すのは面白そうな題材ではありますが。
         | 
| 10 | 
            +
            ~~上図のように『再開時にログオン画面に戻る』設定が有効である場合、スクリーンセーバーは別デスクトップで動作するため、現在画面が起動しているデスクトップからキーボードイベントを送信することはできません。その場合、別デスクトップに対してキーボードイベントを送信する必要があるのですが、現在ログオンしているセッションとは別のセッションとなるため操作できない気がしました。試すのは面白そうな題材ではありますが。~~
         | 
| 11 11 |  | 
| 12 12 | 
             
            あと、C++ Builder の IDE がそうだったかの記憶は昔過ぎてありませんが、VC++ の IDE はブレークポイントがヒットしている行のコードは未実行状態となります。ログに出力するなどの別の確認手段を持たれた方が良いかもしれません。ブレークポイントを使うのであれば仮想環境を用意するなりしてリモートデバッグで試されるのが良いかと思います。
         | 
| 13 13 |  | 
| 14 14 |  | 
| 15 | 
            -
            余談ですが、20年ぐらい前に VC++ と BCB を比較したときに VC++ より BCB の方が Visual だなと思ったのが懐かしい記憶です。それ以来 C++ Builder は主を変え続ける状況になったのが残念なことです。
         | 
| 15 | 
            +
            余談ですが、20年ぐらい前に VC++ と BCB を比較したときに VC++ より BCB の方が Visual だなと思ったのが懐かしい記憶です。それ以来 C++ Builder は主を変え続ける状況になったのが残念なことです。
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            ---
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            追記
         | 
| 20 | 
            +
            どうやら通常起動時もスクリーンセーバーは別デスクトップで動作するようになっているようです。提示のコードでスクリーンセーバーを解除できるのはプレビューモード時のみでした。
         |