質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.12%

Windowsのユーザ切替でメールスロットのやり取りを行えるか?

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,009

nobureon2

score 17

確認したいこと

そもそもやろうとしていることが実現可能か助言いただきたいです。
また、不可能な場合、ほかの方法があれば教えていただきたいです。
ユーザ切替を利用することは確定事項となります。

実現したいこと

Windowsのユーザ切替を利用して、事前にログインしたユーザが起動したプロセスに対して、
別のログインしたユーザからメールスロットでメッセージを送信したいです。
具体的な手順は以下になっています。

1、ユーザAさんでログインし、プロセスAを起動
2、ユーザ切替で、ユーザBさんでログインし、プロセスBを起動
3、ユーザ切替で、ユーザAでログインし、メッセージ表示を確認

■プロセスAでやっていること
タイマーを発行して、10秒間隔でメールスロットの読み取りを行い、
メッセージがある場合、メッセージボックスに受信メッセージを表示する。

■プロセスBでやっていること
メッセージへの書き込み

現状の動作

プロセスBのCreateFile関数でハンドルが取得できません。
GetLastWin32Errorで0x00000005(アクセスが拒否されました。)が返却されます。

環境

Windows10 Pro
VisualStudio 2013
.net framework4.5.1

補足

単一ユーザではメッセージが受信できることは確認済み。
メールスロットの受信/送信は以下のソース。

        // メールスロットの受信
        private string ReadMailSlot(string slot, uint bufSize)
        {
            string ret = string.Empty;
            try
            {
                if (_handleMailslot.IsInvalid)
                    return ret;

                uint maxMessageSize = 1;
                uint nextSize = 0;
                uint messageCount = 0;
                uint readTimeout = 0;

                GetMailslotInfo(_handleMailslot, ref maxMessageSize, ref nextSize, ref messageCount, ref readTimeout);

                if (messageCount > 0 && nextSize != (uint)MailSlotStatus.MAILSLOT_NO_MESSAGE)
                {
                    byte[] buf = new byte[bufSize];
                    int len = _fs.Read(buf, 0, buf.Length);

                    // 適時、文字コードは送信元に合わせてください
                    ret = Encoding.Unicode.GetString(buf, 0, len);
                }
            }
            catch (Exception ex)
            {
                // 何かエラーだって!
                MessageBox.Show(ex.Message);
            }

            return ret;
        }
        // メールスロットの送信
        public void WriteMailSlot(string slot, string message)
        {

            try
            {
                //メールスロットを開く
                SafeFileHandle fileHandle = CreateFile(slot,
                        DesiredAccess.GENERIC_READ | DesiredAccess.GENERIC_WRITE,
                        ShareMode.FILE_SHARE_READ | ShareMode.FILE_SHARE_WRITE,
                        0,
                        CreationDisposition.OPEN_EXISTING,
                        FlagsAndAttributes.FILE_ATTRIBUTE_NORMAL,
                        (IntPtr)0);

                if( fileHandle.IsInvalid )
                {
                    int errCode = Marshal.GetLastWin32Error();
                    MessageBox.Show("Win32エラー・コード:" +
                      String.Format("{0:X8}", errCode));
                }


                // 指定の文字列を出力する
                using (FileStream fs = new FileStream(fileHandle, FileAccess.Write))
                {
                    byte[] msg = Encoding.UTF8.GetBytes(message);
                    fs.Write(msg, 0, msg.Length);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.StackTrace);
                throw ex;
            }
        }
        // 下記URLを参考に修正
        // https://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=16274&forum=7

        public void WriteMailSlot(string slot, string message)
        {
            System.IntPtr hNmPipe = IntPtr.Zero;    // 名前付きパイプハンドル

            //セキュリティ記述子作成 
            SECURITY_DESCRIPTOR sd = new SECURITY_DESCRIPTOR();
            bool bTemp = InitializeSecurityDescriptor(ref sd, 1);
            bool bTemp2 = SetSecurityDescriptorDacl(ref sd, 1, IntPtr.Zero, 0);
            GCHandle sdHandle = GCHandle.Alloc(sd, GCHandleType.Pinned);

            try
            {
                SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
                sa.nLength = Marshal.SizeOf(sa);
                sa.lpSecurityDescriptor = sdHandle.AddrOfPinnedObject();
                sa.bInheritHandle = 0;

                //メールスロットを開く
                SafeFileHandle fileHandle = CreateFile(slot,
                        DesiredAccess.GENERIC_READ | DesiredAccess.GENERIC_WRITE,
                        ShareMode.FILE_SHARE_READ | ShareMode.FILE_SHARE_WRITE,
                        ref sa,
                        CreationDisposition.OPEN_EXISTING,
                        FlagsAndAttributes.FILE_ATTRIBUTE_NORMAL,
                        (IntPtr)0);

                if (fileHandle.IsInvalid)
                {
                    int errCode = Marshal.GetLastWin32Error();
                    MessageBox.Show("Win32エラー・コード:" +
                      String.Format("{0:X8}", errCode));
                }


                // 指定の文字列を出力する
                using (FileStream fs = new FileStream(fileHandle, FileAccess.Write))
                {
                    byte[] msg = Encoding.UTF8.GetBytes(message);
                    fs.Write(msg, 0, msg.Length);
                }

            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.StackTrace);
                throw ex;
            }
            finally
            {
                sdHandle.Free();
            }
        }
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

単純にセキュリティディスクリプタが設定されていないだけではないでしょうか?

対象は異なりますが、C# で DACL を設定しているサンプルがあったので、これと同様に CreateFile の 4 番目のパラメータの SECURITY_ATTRIBUTES を指定してみてはどうでしょう? CreateMailSlot の最後のパラメータに指定してみましょう。
https://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=16274&forum=7

CreateNamedPipe に渡している ref sa ってやつですね。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/07/09 17:44

    回答ありがとうございます。
    参考で掲載いただたURLの内容をほぼコピーしてみましたが、別のエラーになりました。
    修正したソースも掲載します。

    0x000003F0 存在しないトークンを参照しようとしました。

    セキュリティディスクリプタについてよくわかってないのですが、
    この場合、メールスロットで生成した仮想ファイルにDACLが設定されていないということでしょうか?

    キャンセル

  • 2019/07/10 01:38

    すみません。思いっきり回答間違ってましたので、修正しました。

    キャンセル

  • 2019/07/10 09:42

    回答ありがとうございます!
    おかげさまで、出来ました。

    セキュリティディスクリプタについて理解出来ていないので、
    理解したうえで活用させてもらいます!

    ありがとうございました!!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる