現在、windowsサービスのプログラミングをしていて、ログオンするときにスクリーンキーボード(oskもしくは、自作の仮想キーボード)を表示してユーザにパスワードの入力を求め、ログオンするというサービスを作ろうと思っています。
(本当にしたいことはそこだけではないのですが、一番困っているのがこの部分なので・・・)
調べてみたところ、XPまでは特に問題なくできそうな感じなのですが、Vista以降だとUACの関係でセッション0の分離によりうまく実行できないようです・・・
当方、XPのデバッグ環境がないのでなんとも・・・。そろそろ用意するつもりです。
ログオンしてからは、CreateProcessAsUser関数で実行すればよいのでなんとかなりそうなのですが(これも難しいので、解決しないようであれば後日質問したいと思ってます。。。)
そもそもVista以降でログインする前にスクリーンキーボードを表示することは可能なのでしょうか?
もし、可能であれば解決策教えていただけると幸いです。
ちなみに、簡単入力によりスクリーンキーボードを表示させるのとは違って、あくまでサービス的にキーボードを表示するということです。
以下が、Vista以降で対話型サービスの検出とでるプログラムのソースコードです。
これは、ログオン前のところはまだ考慮していないもので、これからコーディング予定です。
/* インクルードヘッダ */
#include <windows.h>
#include <stdio.h>
/* システム定数 */
const char *SERVICE_PATH = "C:\\InterFaceLabo\\Debug\\DemoService.exe";
const char *SERVICE_NAME = "DemoService";
const char *SERVICE_DISP_NAME = "Demo Service";
const char *APPRICATION_PATH = "calc";
/* システム変数 */
SERVICE_STATUS_HANDLE g_ssh = NULL;
HANDLE g_event = NULL;
HANDLE g_event2 = NULL;
DWORD g_state = SERVICE_STOPPED;
/* プロトタイプ宣言 */
VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv);
VOID WINAPI ServiceHandler(DWORD fdwControl);
void execute();
/* Main Program */
int main(void)
{
SERVICE_TABLE_ENTRY services[] = {
{SERVICE_NAME, ServiceMain},
{NULL, NULL}
};
if(!StartServiceCtrlDispatcher(services)){
MessageBox(NULL,
"Serviceサービスでエラーが発生しました。",
"Serviceエラー",
MB_OK | MB_ICONERROR | MB_SERVICE_NOTIFICATION
);
}
return 0;
}
/* Windows サービス */
VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
SERVICE_STATUS status;
g_ssh = RegisterServiceCtrlHandler(
SERVICE_NAME, ServiceHandler);
if(g_ssh == NULL){
MessageBox(NULL,
"Serviceサービスを開始できませんでした。",
"Serviceエラー",
MB_OK | MB_ICONERROR | MB_SERVICE_NOTIFICATION
);
return;
}
g_event = CreateEvent(NULL, FALSE, FALSE, NULL);
g_event2 = CreateEvent(NULL, FALSE, FALSE, NULL);
g_state = SERVICE_RUNNING;
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
status.dwCurrentState = SERVICE_RUNNING;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
status.dwWin32ExitCode = 0;
status.dwServiceSpecificExitCode = 0;
status.dwCheckPoint = 0;
status.dwWaitHint = 0;
SetServiceStatus(g_ssh, &status);
OutputDebugString("Serviceサービスが開始しました\n");
while(1){
/* サービスの内容ここから */
execute(APPRICATION_PATH);
/* サービスの内容ここまで */
// 2秒間停止
if(WaitForSingleObject(g_event, 2000) == WAIT_TIMEOUT)
continue;
while(g_state == SERVICE_PAUSED){
SetEvent(g_event2);
WaitForSingleObject(g_event, INFINITE);
}
if(g_state == SERVICE_RUNNING)
SetEvent(g_event2);
else if(g_state == SERVICE_STOPPED)
break;
}
OutputDebugString("Serviceサービスが停止しました\n");
SetEvent(g_event2);
}
/* サービスハンドラ */
VOID WINAPI ServiceHandler(DWORD fdwControl)
{
char buf[256];
SERVICE_STATUS status = {
SERVICE_WIN32_OWN_PROCESS,
SERVICE_RUNNING,
SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE,
0, 0, 0, 0
};
switch(fdwControl){
case SERVICE_CONTROL_PAUSE:
g_state = SERVICE_PAUSED;
OutputDebugString("");
SetEvent(g_event);
WaitForSingleObject(g_event2, INFINITE);
break;
case SERVICE_CONTROL_CONTINUE:
g_state = SERVICE_RUNNING;
OutputDebugString("");
SetEvent(g_event);
WaitForSingleObject(g_event2, INFINITE);
break;
case SERVICE_CONTROL_STOP:
g_state = SERVICE_STOPPED;
OutputDebugString("");
SetEvent(g_event);
WaitForSingleObject(g_event2, INFINITE);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
sprintf(buf, "サポートしない制御コード : 0x%08lx\n", fdwControl);
OutputDebugString(buf);
}
status.dwCurrentState = g_state;
SetServiceStatus(g_ssh, &status);
return;
}
/* プロセスの生成 */
void execute(char *str)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
CreateProcess(
NULL,
str,
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE | CREATE_NO_WINDOW,
NULL,
NULL,
&si,
&pi
);
return;
}
サービスをインストールするソースはこちら。
#include <windows.h>
#include <stdio.h>
const char *SERVICE_PATH = "C:\\InterFaceLabo\\Debug\\DemoService.exe";
const char *SERVICE_NAME = "DemoService";
const char *SERVICE_DISP_NAME = "Demo Service";
void install(void)
{
SC_HANDLE scm, svc;
scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if(scm == NULL){
fprintf(stderr, "SCMをオープンできませんでした。\n");
return ;
}
svc = CreateService(
scm, // SCMのハンドル
SERVICE_NAME, // サービス名
SERVICE_DISP_NAME, // サービスの表示名
SERVICE_ALL_ACCESS, // 必要なアクセス権
SERVICE_WIN32_OWN_PROCESS, // サービスの種類
SERVICE_AUTO_START, // 開始方法
SERVICE_ERROR_NORMAL, // エラー発生時の対処
SERVICE_PATH, // サービスのパス名
NULL, // ロード順序グループの指定
NULL, // ロード順序グループ内のタグを受け取る
NULL, // 依存するサービス名のリスト
NULL, // アカウントのID
NULL // パスワード
);
if(svc != NULL){
CloseServiceHandle(svc);
printf("サービスがインストールされました。\n");
}else{
fprintf(stderr, "サービスがインストールできませんでした。\n");
}
CloseServiceHandle(scm);
return ;
}
/* メイン関数 */
int main(void)
{
install();
return 0;
}
インストーラーは、管理者権限で実行する必要があります。。。(UAC面倒くさい・・・)
その後、プロパティでデスクトップとの対話を許可します。
アンインストーラーはまだ未作成ですが、コマンドプロンプトから
>sc delete DemoService
で削除できます。
環境は、
OS:Win7 32bit
開発環境:VC++2008
開発言語:C++
当方、C言語暦6年程、Win32APIを利用した簡易的なWindowsアプリの開発を行った経験があります。
以上、よろしくお願いします。