Vista以降のログオン前セッションとセッション0について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
結祈

Vista以降のログオン前セッションとセッション0について

#1

投稿記事 by 結祈 » 14年前

始めまして。結祈と申します。
現在、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アプリの開発を行った経験があります。

以上、よろしくお願いします。

結祈

Re: Vista以降のログオン前セッションとセッション0について

#2

投稿記事 by 結祈 » 14年前

※補足

一点忘れていたので

ソースコードの中で、calcとなっているところがありますが、
これはCreateProcessでoskが起動しないためです。。。
原因はまだ調べてません。。

そのため、現状CreateProcessで起動を確認できたcalcを変わりに確認しています。

また、これにより実装は自作の仮想キーボードになりそうです

砂布巾

Re: Vista以降のログオン前セッションとセッション0について

#3

投稿記事 by 砂布巾 » 14年前

何を行いたいのかは、書き込みからは良く判りませんが、ログオン画面の拡張なので、
CredentialProviderを作成して、その中でソフトウェアキーボードの処理を
行ったほうが良いと思われます。
http://msdn.microsoft.com/ja-jp/magazine/cc163489.aspx

閉鎖

“C言語何でも質問掲示板” へ戻る