Windwos サービス から 特定ユーザ に メッセージを 表示する

  • デル株式会社
  • サービスからメッセージボックスを表示する要件が出てきたので、
    ちょっと調べてみた。
    通常のメッセージボックスだと、色々と困った事になるので、
    下記の関数を使用する。

    ※なぜ困った事になるかは、やったらわかる。

    BOOL WTSSendMessage(
    HANDLE hServer,
    DWORD SessionId,
    LPTSTR pTitle,
    DWORD TitleLength,
    LPTSTR pMessage,
    DWORD MessageLength,
    DWORD Style,
    DWORD Timeout,
    DWORD *pResponse,
    BOOL bWait
    );

    この関数は、別のPCだったりの指定ユーザへメッセージボックスを
    表示したい場合に使用するんでけども、今回は、同一PC上の指定ユーザへの表示で行う。
    ちなみに、別PCの場合は、WTSOpenServer を使用して、ハンドル取得後に行います。

    別PCには、同一ユーザで且つ、同一パスワードを設定していないとできないっぽい。
    この辺は、別途調査しようかなと。

    関数の詳細は、MSDNを参照してもらうとして、

    MSDN WTSSendMessage


    ここの記事でも書いたサンプルを少しいじって作成。

    Windowsサービスから現在のログオンユーザを取得する

    サンプルここから

    #include "wtsapi32.h"
    #pragma comment(lib, "wtsapi32.lib")
    
    {
        PWTS_SESSION_INFOW pStSesInf = NULL;
        
        DWORD dwCount = 0;
        DWORD dwSesId = 0;
        DWORD dwSize  = 0;
        
        LPTSTR lpNameTmp  = NULL;
    
        // ログオンユーザのセッションリストを取得する
        if( ::WTSEnumerateSessionsW( NULL,
                                        0,                    // 予約(必ず0を指定)
                                        1,                    // 列挙要求のバージョン(必ず1を指定)
                                        &pStSesInf,           // 構造体の配列へのポインタを受取る
                                        &dwCount ) == FALSE ) // 構造体の数格納用(セッションリスト数)
        {
            // 取得失敗
            return;
        }
    
    
        for( DWORD dwLoop = 0; dwLoop < dwCount; dwLoop++ )
        {
            // セッションリストから順次セッション情報を取得する
            if( ::WTSQuerySessionInformation( WTS_CURRENT_SERVER_HANDLE,      // ターミナルサーバハンドル
                                              pStSesInf[ dwLoop ].SessionId,  // セッションの識別子
                                              WTSUserName,                    // セッションに関連付けられたユーザー受取を指定
                                              &lpNameTmp,                     // ユーザ名ポインタ格納用
                                              &dwSize ) == TRUE )             // 受取のデータサイズ    
    
    
            { 
                // 現在アクティブなセッションのIDを取得
                dwSesId = ::WTSGetActiveConsoleSessionId();
                
                // セッションIDを比較しアクティブなセッションIDと同一ならユーザ名を表示する
                if( pStSesInf[ dwLoop ].SessionId == dwSesId )
                {                
                    CString strName;
                    strName.Format( "\nLogonUser:%s\n", lpNameTmp );
    
    
    // --------------------------- この辺から今回 -----------------------------------
    
                    // メッセージ出力対象ユーザか?
                    if( CString( lpNameTmp ).MakeUpper() == _T( "CPNAME" ) )
                    {
    
                        DWORD deRet = 0;
    
                        TCHAR szTi[] = _T("WTSSendMessage" );
                        TCHAR szMs[] = _T("メッセージ 5秒後 自動消滅" );
    
                        ::WTSSendMessage( WTS_CURRENT_SERVER_HANDLE,
                                          dwSesId,
                                          szTi,
                                          sizeof( szTi ),
                                          szMs,
                                          sizeof( szMs ),
                                          MB_OK,  
                                          5,
                                          &deRet,
                                          TRUE );
    
                        
                        // メッセージの戻り値判定
                        if( deRet == IDOK )
                        {
                            // メッセージボックスでOKが押下された場合。
                        }
                        else if( deRet == IDTIMEOUT )
                        {
                            // 設定時間を経過しタイムアウトとなった場合。
                        }
                        else
                        {
    
                        }
                    }
    
    
                    break;
    
    // --------------------------- ここまで       -----------------------------------
    
                }
                else
                {
                    // たぶん複数ユーザでログインしている場合でアクティブじゃないユーザが表示される?
                    // 未確認・・確認した誰か教えて・・
                    CString strName;
                    strName.Format( "\nLogonUser:%s\n", lpNameTmp );
                    
                    // デバック出力
                    TRACE( strName );
                }
    
            }
            else
            {
                // 取得失敗
                return;
            
            }
        }
    
        if( lpNameTmp != NULL )
        { 
            // 解放
            WTSFreeMemory( lpNameTmp );
            lpNameTmp = NULL;
        }
    
        if( pStSesInf != NULL )
        {
            // 解放
            WTSFreeMemory( pStSesInf );
            pStSesInf = NULL;
        }
    
    }
    


    うんな感じ。いつものように、自己責任で。。

    関連記事

    ページ上部へ戻る