宇宙仮面の
C# Programming

 
Image

Net Send (リモートのPCへポップアップメッセージを送る)

開発環境: Visual Studio 2003 

1.目次

2.目的

NET SEND コマンドで、メッセージを送ることができます。
それを .NET/C# から実行する方法です。

メッセージは、こんな感じです。
Image

3.参考書

(1) .NET/C# eGroup の1376番スレッドで質問があり、市村さんが回答しています。それを参考にしています。
(2) MSDN NetMessageBufferSend

4.NET SENDを知らない人のために

 
コマンドウィンドウ(DOS窓)で NET HELP とタイプしてみてください。
次のような NET に続くコマンドで、さまざまな処理ができるコマンドラインインターフェースです。

NET ACCOUNTS
NET HELP
NET SHARE
NET COMPUTER
NET HELPMSG
NET START
NET CONFIG
NET LOCALGROUP
NET STATISTICS
NET CONFIG SERVER
NET NAME NET STOP
NET CONFIG WORKSTATION
NET PAUSE
NET TIME
NET CONTINUE
NET PRINT
NET USE
NET FILE
NET SEND
NET USER
NET GROUP
NET SESSION
NET VIEW

例えば、NET USE ・・・でネットワークリソースへのアクセスを可能にしてくれます。
また、NET START でサービスを開始することができます。

この中で NET START がありますが、次のようにコマンドウィンドウ(DOS窓)で NET SEND 名前 メッセージ
と実行してみてください。

Image

すると、次のようなポップアップダイアログが表示されます。

Image

自分自身にメッセージを飛ばしても、あまりメリットはありませんが、
ネットワーク上のほかのユーザー、コンピュータ、またはメッセージ宛先名に、
例えば”もうすぐシャットダウンします”というようなメッセージを飛ばすことができます。

注意
パラメータの指定によっては、すべてのユーザにメッセージが送られてしまいます。
会社や学校でテストする場合は、注意してね。

5.NetMessageBufferSend プラットフォームSDK呼び出し

この NET SEND コマンドと同じことをやるには、NetMessageBufferSend プラットフォームSDK呼び出しが必要になります。

NetMessageBufferSend
NET_API_STATUS NetMessageBufferSend(
LPCWSTR servername,    // 実行対象のリモートサーバー
LPCWSTR msgname,      // 送信先のメッセージエイリアス
LPCWSTR fromname,     // メッセージの送信元
LPBYTE buf,           // メッセージテキストを保持しているバッファ
DWORD buflen          // バッファサイズ
);
//
//
// ヘッダー:Lmmsg.h 内で宣言、Lm.h をインクルード
// インポートライブラリ:Netapi32.lib を使用
対象OS
Windows NT/2000:Windows NT 3.1 以降
Windows 95/98:対応していません

6.C#からの呼び出し方法


C#での宣言
using System.Runtime.InteropServices;

・・・

[DllImport("Netapi32",CharSet=CharSet.Unicode)]

static extern int NetMessageBufferSend(
string servername,
string msgname,
string fromname,
string buf,
int buflen );

注意 (DllImport CharSet引数)
NetMessageBufferSend() はUnicode 文字列を要求します。
DllImport のCharSet は標準で CharSet.Ansi ですので、
このため明示的に CharSet=CharSet.Unicode と指定する必要があります。
注意 (servername 引数)
servername は、null にしておくと、ローカルコンピュータになります。
通常は、null でOKですが、リモートサーバからメッセージを送る場合は、DNS名もしくはNetBIOS 名を指定します。
このとき、@"\\ServerName" というように、\\ をつける必要があります。
リモートサーバを指定する場合は、アクセスコントロール(ACL)が影響しますので、MSDN を読んでね。
注意 (buflen 引数)
バッファーのメッセージテキストの長さをバイト単位で指定します。
ここでは、System.Encoding.Unicode.GetByteCount(msg) としていますが、
終端文字(\0)を考慮すると、
Encoding.Unicode.GetByteCount(buf) + UnicodeEncoding.CharSize;
としないといけないですね。
ただ、終端文字が必要なのかどうかマニュアルに書いていないので、
何とも判断できません。
C#での呼び出し方
string msg = "これはテストです。 ";
int ret = NetMessageBufferSend(
null,
"Uchukamen",
msg,
Encoding.Unicode.GetByteCount(msg)
);

// エラー処理
if( ret != 0 )
throw new Win32Exception( ret );

7.テスト用ソースコード

変更履歴
2003/10/22   初版作成

Form1.cs
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;
using System.Text;

namespace NetMessageBufferSend
{
        /// <summary>
        /// Form1 の概要の説明です。
        /// </summary>
        public class Form1 : System.Windows.Forms.Form
        {
        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.TextBox textBoxHost;
        private System.Windows.Forms.TextBox textBoxMsg;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Label label2;
        private System.Windows.Forms.Label label3;
        private System.Windows.Forms.TextBox textBoxServer;
                /// <summary>
                /// 必要なデザイナ変数です。
                /// </summary>
                private System.ComponentModel.Container components = null;

                public Form1()
                {
                        //
                        // Windows フォーム デザイナ サポートに必要です。
                        //
                        InitializeComponent();

                        //
                        // TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
                        //
                }

                /// <summary>
                /// 使用されているリソースに後処理を実行します。
                /// </summary>
                protected override void Dispose( bool disposing )
                {
                        if( disposing )
                        {
                                if (components != null) 
                                {
                                        components.Dispose();
                                }
                        }
                        base.Dispose( disposing );
                }

                #region Windows フォーム デザイナで生成されたコード 
                /// <summary>
                /// デザイナ サポートに必要なメソッドです。このメソッドの内容を
                /// コード エディタで変更しないでください。
                /// </summary>
                private void InitializeComponent()
                {
            this.textBoxHost = new System.Windows.Forms.TextBox();
            this.button1 = new System.Windows.Forms.Button();
            this.textBoxMsg = new System.Windows.Forms.TextBox();
            this.label1 = new System.Windows.Forms.Label();
            this.label2 = new System.Windows.Forms.Label();
            this.label3 = new System.Windows.Forms.Label();
            this.textBoxServer = new System.Windows.Forms.TextBox();
            this.SuspendLayout();
            // 
            // textBoxHost
            // 
            this.textBoxHost.Location = new System.Drawing.Point(80, 48);
            this.textBoxHost.Name = "textBoxHost";
            this.textBoxHost.Size = new System.Drawing.Size(248, 19);
            this.textBoxHost.TabIndex = 0;
            this.textBoxHost.Text = "";
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(240, 280);
            this.button1.Name = "button1";
            this.button1.TabIndex = 2;
            this.button1.Text = "Send";
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // textBoxMsg
            // 
            this.textBoxMsg.Location = new System.Drawing.Point(8, 104);
            this.textBoxMsg.Multiline = true;
            this.textBoxMsg.Name = "textBoxMsg";
            this.textBoxMsg.Size = new System.Drawing.Size(320, 160);
            this.textBoxMsg.TabIndex = 3;
            this.textBoxMsg.Text = "";
            // 
            // label1
            // 
            this.label1.Location = new System.Drawing.Point(8, 16);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(56, 23);
            this.label1.TabIndex = 4;
            this.label1.Text = "サーバ";
            // 
            // label2
            // 
            this.label2.Location = new System.Drawing.Point(8, 48);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(56, 19);
            this.label2.TabIndex = 5;
            this.label2.Text = "送信先";
            // 
            // label3
            // 
            this.label3.Location = new System.Drawing.Point(8, 80);
            this.label3.Name = "label3";
            this.label3.Size = new System.Drawing.Size(56, 23);
            this.label3.TabIndex = 6;
            this.label3.Text = "メッセージ";
            // 
            // textBoxServer
            // 
            this.textBoxServer.Location = new System.Drawing.Point(80, 16);
            this.textBoxServer.Name = "textBoxServer";
            this.textBoxServer.Size = new System.Drawing.Size(248, 19);
            this.textBoxServer.TabIndex = 7;
            this.textBoxServer.Text = "";
            // 
            // Form1
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
            this.ClientSize = new System.Drawing.Size(336, 310);
            this.Controls.Add(this.textBoxServer);
            this.Controls.Add(this.label3);
            this.Controls.Add(this.label2);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.textBoxMsg);
            this.Controls.Add(this.button1);
            this.Controls.Add(this.textBoxHost);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }
                #endregion

                /// <summary>
                /// アプリケーションのメイン エントリ ポイントです。
                /// </summary>
                [STAThread]
                static void Main() 
                {
                        Application.Run(new Form1());
                }

//        NET_API_STATUS NetMessageBufferSend(
//            LPCWSTR servername,  // 実行対象のリモートサーバー
//            LPCWSTR msgname,     // 送信先のメッセージエイリアス
//            LPCWSTR fromname,    // メッセージの送信元
//            LPBYTE buf,          // メッセージテキストを保持しているバッファ
//            DWORD buflen         // バッファサイズ
//            );
//        Windows NT/2000:Windows NT 3.1 以降
//        Windows 95/98:対応していません
//
//        ヘッダー:Lmmsg.h 内で宣言、Lm.h をインクルード
//        インポートライブラリ:Netapi32.lib を使用

        [DllImport("Netapi32",CharSet=CharSet.Unicode)]
        static extern int NetMessageBufferSend(
            string servername, string msgname, string fromname, string buf, int buflen );

        private void button1_Click(object sender, System.EventArgs e)
        {
            try
            {
                string servername = this.textBoxServer.Text;
                if(servername != "" && !servername.StartsWith( @"\\" ) )
                    servername = @"\\" + servername;

                string dest = this.textBoxHost.Text;
                string msg = this.textBoxMsg.Text;
                int buflen = Encoding.Unicode.GetByteCount(msg);
                int ret = NetMessageBufferSend(servername, dest, null, msg, buflen);
                if( ret != 0 )
                    throw new Win32Exception( ret );
            }
            catch(Exception exc)
            {
                MessageBox.Show(exc.Message, "NetMessageBufferSend", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        }
}