HTTP コマンド・リスナー :【VB.NET】


(ソース+バイナリ)
ブラウザのアドレスバーからコマンド入力
Command_listener
起動するとタスクバーに常駐します。

ブラウザのアドレスバーにコマンドを入力して、http 通信でアプリケーションを起動します。
ブラウザで無くても、http プロトコルであれば他のプロセスからのリクエクストを受けて
処理を行います

例えば、Flex AIR では、ローカルのアプリケーションを起動できませんが、
http 通信は可能なので運用の幅が広がると思います。
Command_listener
終了は、上記ポップアップメニューで終了するか、http://pc名:50000/quit を送信します
ソースコード
VB.NET を利用する為のサンプルコードとして有用です

1) タスクバーに常駐
2) ポップアップメニュー
3) スレッド
4) http サーバー
5) http 経由でのスレッド終了

通常であれば作成される Form1.Designer.vb は削除してあります
( ここでは Form を使用しないので )

※ myNotifyIcon.Dispose() でタスクバーのアイコンの終了処理をしないと
※ アイコンが自動的に表示上削除されません
#Region "Imports はもともとプロジェクトで利用可能な名前を修飾する必要がなくなるだけです"

Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports System.Diagnostics
Imports System.Windows.Forms
Imports System.Threading

#End Region

Public Class Form1
	Inherits System.Windows.Forms.Form

	<System.STAThread()> _
	Public Shared Sub Main()
		System.Windows.Forms.Application.Run(New Form1)
	End Sub	'Main

	Private components As System.ComponentModel.IContainer
	Private myContextMenu As ContextMenu
	Friend WithEvents myMenuItem As MenuItem
	Friend WithEvents myNotifyIcon As NotifyIcon

	' ************************************************************
	' コンストラクタ
	' MSDN の見本通りに常駐タスクバーに入る処理
	' ************************************************************
	Public Sub New()

		components = New System.ComponentModel.Container()
		myContextMenu = New ContextMenu()
		myMenuItem = New MenuItem()
		myContextMenu.MenuItems.AddRange(New MenuItem() {myMenuItem})
		myMenuItem.Index = 0
		myMenuItem.Text = "終了"

		myNotifyIcon = New NotifyIcon(components)
		myNotifyIcon.Icon = New Icon("db.ico")
		myNotifyIcon.Text = "lightbox コマンドサーバー"
		myNotifyIcon.Visible = True


		myNotifyIcon.ContextMenu = myContextMenu

		MyBase.ShowInTaskbar = False
		' とりあえず見えない
		MyBase.WindowState = FormWindowState.Minimized
		MyBase.Opacity = 0

	End Sub

	' ************************************************************
	' サーバースレッド開始
	' ************************************************************
	Private Sub Form1_Load(ByVal sender As System.Object, _
	ByVal e As System.EventArgs) Handles MyBase.Load

		' スレッド開始
		Dim ThreadServer As New Thread(AddressOf ThreadEntry)
		ThreadServer.Start()

	End Sub

	' ************************************************************
	' 特に使っていない
	' ************************************************************
	Private Sub InitializeComponent()
		Me.SuspendLayout()
		'
		'Form1
		'
		Me.ClientSize = New System.Drawing.Size(292, 273)
		Me.Name = "Form1"
		Me.ResumeLayout(False)

	End Sub

	' ************************************************************
	' 終了用
	' ************************************************************
	Private Sub menuItem1_Click(ByVal Sender As Object, _
	ByVal e As EventArgs) Handles myMenuItem.Click

		' スレッドに終了を伝える
		Dim hostname = System.Net.Dns.GetHostName()
		Dim command As New System.Net.WebClient()
		command.OpenRead("http://" + hostname + ":50000/quit")

	End Sub

	' ************************************************************
	' 完全に非表示
	' ************************************************************
	Private Sub Form1_Shown(ByVal sender As System.Object, _
	 ByVal e As System.EventArgs) Handles MyBase.Shown

		Me.Visible = False

	End Sub


	' ************************************************************
	' スレッドの入り口
	' ************************************************************
	Private Sub ThreadEntry()

		Dim server As TcpListener = Nothing

		Try
			' 50000 番ポート使用
			Dim port As Int32 = 50000
			' ローカル
			Dim hostname = System.Net.Dns.GetHostName()
			Dim he As System.Net.IPHostEntry = System.Net.Dns.GetHostEntry(hostname)
			Dim iptop As System.Net.IPAddress = he.AddressList(0)

			Dim localAddr As IPAddress = IPAddress.Parse(iptop.ToString())
			Dim header As String = _
			"HTTP/1.1 200 OK" + ControlChars.CrLf + _
			"Content-Type: text/plain; Charset=shift_jis" + ControlChars.CrLf + _
			"Expires: Wed, 31 May 2000 14:59:58 GMT" + ControlChars.CrLf + ControlChars.CrLf + _
			"lightbox コマンドサーバー" + ControlChars.CrLf + _
			"( 使用方法 http://pc名:50000/コマンド または http://pc名:50000/コマンド|引数 )" + ControlChars.CrLf + _
			"※ http://pc名:50000/quit でサービス終了" + ControlChars.CrLf + _
			"※ URLエンコードは UTF8 で引き渡します" + ControlChars.CrLf + _
			"※ 空白は %20 で引き渡します" + ControlChars.CrLf + _
			"※ ファイルのパスは ダブルクォートで囲むと、拡張子による実行をブラウザが行いません" + ControlChars.CrLf

			server = New TcpListener(localAddr, port)

			' サーバー開始
			server.Start()

			' 読み込みバッファ
			Dim bytes(1024) As Byte
			' コマンドワーク
			Dim data As String = Nothing
			' レスポンスワーク
			Dim ret As String = Nothing

			' **********************************************
			' コマンド待ちのループ
			' **********************************************
			Do While True

				' サービス終了
				If data = "quit" Then
					Exit Do
				End If

				Console.WriteLine("Waiting ... ")

				' 待機( 接続されると次の行へ )
				Dim client As TcpClient = server.AcceptTcpClient()
				' 受信したので処理開始
				Console.WriteLine("Connected")

				data = ""

				' 受信用ストリーム
				Dim stream As NetworkStream = client.GetStream()

				Dim i As Integer
				Dim cd As Integer = 0

				' ストリームからデータを取得( 初回 )
				i = stream.Read(bytes, 0, bytes.Length)
				' **********************************************
				' データ読み込みのループ
				'   改行(\r\n)を見つけると、それまでに取得した
				'   文字列( data )をコマンドとして実行する
				' **********************************************
				Do While i <> 0
					cd = 0
					ret = ""

					' 読み込んだデータの1バイト(8ビット符号なし整数)サーチ
					For idx As Integer = 0 To i - 1
						' 改行の始まり(\r)発見
						If bytes(idx) = &HD Then
							cd += 1
						End If
						' 通常の文字列データ( data )の作成
						If cd = 0 Then
							data += _
							 Encoding.ASCII.GetString(bytes, idx, 1)
						End If

						' 改行区切り(\n)でコマンドを取得
						If bytes(idx) = &HA And cd = 1 Then
							' URL エンコードは UTF8 で
							data = data.Replace("%20", "@")
							data = System.Web.HttpUtility.UrlDecode(data)
							ret += data + ControlChars.CrLf
							Console.WriteLine("Received: {0}", data)
							Dim Command As String() = data.Split(" ")
							If Command(0) = "GET" Then
								data = Command(1).Substring(1)
								data = data.Replace("@", " ")
								Console.WriteLine("Command: {0}", data)

								' サービス終了
								If data = "quit" Then
									Dim msg As Byte() = _
									 Encoding.GetEncoding(932).GetBytes( _
									 header + "● quit コマンドにより、サービスを終了しました")
									stream.Write(msg, 0, msg.Length)
									Exit Do
								End If

								' コマンドと引数の区切りの処理
								Dim delimStr As String = "|"
								Dim delimiter As Char() = delimStr.ToCharArray()
								' 配列定義
								Dim split As String() = Nothing
								' トークン分割
								split = data.Split(delimiter)
								Try
									' 引数無し
									If split.Length = 1 Then
										ret += "【実行】" + data + ControlChars.CrLf
										Process.Start(data)
									Else
										' 引数あり
										ret += "【実行】" + split(0) + " " + split(1) + ControlChars.CrLf
										Process.Start(split(0), split(1))
									End If
								Catch ex As System.ComponentModel.Win32Exception
									ret += "【ERROR】" + ex.Message + ControlChars.CrLf
								End Try
							End If
							' 1行のコマンド処理が終了したので、変数を初期化
							cd = 0
							data = ""
							'Exit For
						End If
					Next

					If data = "" Then
						' OK を返す
						Dim msg As Byte() = _
						 Encoding.GetEncoding(932).GetBytes( _
						 header + ret)
						stream.Write(msg, 0, msg.Length)
						Exit Do
					End If
					' **********************************************
					' ストリームからデータを取得
					'   改行を見つけられず、データが残っている場合
					' **********************************************
					i = stream.Read(bytes, 0, bytes.Length)

				Loop

				' 処理終了で接続解除してサービス終了
				client.Close()

			Loop

		Catch ex As SocketException
			Console.WriteLine("SocketException: {0}", ex)
		Finally
			server.Stop()
		End Try

		' タスクバーのアイコンを開放
		myNotifyIcon.Dispose()
		' アプリケーション終了
		System.Windows.Forms.Application.Exit()

	End Sub

End Class