1.我们要目标是要做一个在TFS上Build成功或者失败后的一个音乐提示,于是想到用TFS传送消息+Sokect编程+WindowsService实现,思路是这样的:
Sokect编程这一块实现主要的功能,包括监听一个端口,接受到指定的信息后播放成功或者失败的音乐。这个服务通过WindowsService来调用。最后的任务就是TFS发送成功或者失败的消息给这个地址。
2.目前实验的代码如下:
服务端代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Diagnostics;
using System.Xml.Linq;
namespace SocketConsole
{
public static class ServerHelper
{
public static void PlayBuildMusic()
{
try
{
TcpListener listener = new TcpListener(IPAddress.Any, 8888);
listener.Start();
//建立连接
while (true)
{
listener.BeginAcceptTcpClient(AsyncCallbackMethod, listener).AsyncWaitHandle.WaitOne();
}
}
catch (Exception ex)
{
using (StreamWriter stream = File.CreateText("D:\\log.txt"))
{
stream.WriteLine(ex.ToString());
}
}
}
private static void AsyncCallbackMethod(IAsyncResult ar)
{
string success = System.Configuration.ConfigurationSettings.AppSettings["success"];
string failed = System.Configuration.ConfigurationSettings.AppSettings["failed"];
MciPlaySound mciPlaySound = new MciPlaySound();
TcpListener tcpListener = ar.AsyncState as TcpListener;
TcpClient remoteClient = tcpListener.EndAcceptTcpClient(ar);
NetworkStream streamToClient = remoteClient.GetStream();
byte[] readBytes = ReadRequest(streamToClient);
string msg = Encoding.Unicode.GetString(readBytes, 0, readBytes.Length);
if (msg == "1")
{
mciPlaySound.FileName = success;
mciPlaySound.Play();
}
else if (msg == "2")
{
mciPlaySound.FileName = failed;
mciPlaySound.Play();
}
streamToClient.Dispose();
remoteClient.Close();
}
private static byte[] ReadRequest(NetworkStream networkStream)
{
MemoryStream bytesStream = new MemoryStream();
byte[] readByte = new byte[1024];
int length = networkStream.Read(readByte, 0, 1024);
bytesStream.Write(readByte, 0, length);
return bytesStream.ToArray();
}
}
}
首先是音乐的配置文件:
app.config
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="success" value="D:\Music\d-l-suc.wav"/>
<add key="failed" value="D:\Music\Medic_jeers11.wav"/>
</appSettings>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
服务端的代码如下:
WindowsService的代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using SocketConsole;
using System.Threading;
using System.Media;
using System.IO;
using System.Reflection;
namespace BuildMusciWindowsService
{
public partial class PlayBuildMusic : ServiceBase
{
public PlayBuildMusic()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Thread thread = new Thread(ServerHelper.PlayBuildMusic);
thread.Start();
}
protected override void OnStop()
{
}
}
}
客户端代码:
public class ClientConsole
{
static void Main(string[] args)
{
IPAddress ip = new IPAddress(Dns.GetHostByName("RICKYCAI").AddressList[0].Address);
const int BufferSize = 8192;
Console.WriteLine("Client Running...");
TcpClient client = new TcpClient();
try
{
client.Connect(ip, 8500);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
Console.WriteLine("Server Connected!{0}-->{1}", client.Client.LocalEndPoint, client.Client.RemoteEndPoint);
NetworkStream streamToServer = client.GetStream();
ConsoleKey key;
Console.WriteLine("Menu: S-Send,E-Exit");
do
{
key = Console.ReadKey(true).Key;
if (key == ConsoleKey.S)
{
Console.WriteLine("Please input the message");
string msg = Console.ReadLine();
byte[] buffer = Encoding.Unicode.GetBytes(msg);
lock (streamToServer)
{
streamToServer.Write(buffer, 0, buffer.Length);
}
Console.WriteLine("Sent:{0}", msg);
int bytesRead;
buffer = new byte[BufferSize];
lock (streamToServer)
{
bytesRead = streamToServer.Read(buffer, 0, BufferSize);
}
msg = Encoding.Unicode.GetString(buffer, 0, bytesRead);
Console.WriteLine("Received: {0}", msg);
}
} while (key != ConsoleKey.E);
}
}
3.但是在WindowsService中利用SoundPlayer类来播放音乐在windows7是行不通的,最终我们在网上找到了解决方案之一如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using System.Threading;
namespace SocketConsole
{
public class MciPlaySound
{
#region 変数
private StructMCI m_MciInfo = new StructMCI();
private StringBuilder m_sbCommand = new StringBuilder();
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
private string m_strShortName = "";
[MarshalAs(UnmanagedType.LPTStr, SizeConst = 128)]
private string m_strCommandResult = "";
private long m_lReturn = 0;
private string m_strDeviceName = "";
#endregion
#region
public enum State
{
// 準備中
Ready = 0,
// 再生中
Playing = 1,
// 再生完了
Stop = 2
};
public struct StructMCI
{
public string FileName;
public State State;
};
#endregion
#region 再生部品
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetShortPathName(
string lpszLongPath,
string shortFile,
int cchBuffer);
// WAVE再生部品
[DllImport("winmm.dll", EntryPoint = "mciSendString", CharSet = CharSet.Auto)]
private static extern int mciSendString(
string lpstrCommand,
string lpstrReturnString,
int uReturnLength,
IntPtr hwndCallback);
#endregion
#region
public string DeviceName
{
get
{
return m_strDeviceName;
}
}
public string FileName
{
get
{
return m_MciInfo.FileName;
}
set
{
lock (m_sbCommand)
{
if (!File.Exists(value))
{
m_MciInfo.FileName = "";
throw new Exception("文件不存在。");
}
m_MciInfo.FileName = value;
m_lReturn =
mciSendString("close all",
m_strCommandResult,
m_strCommandResult.Length,
IntPtr.Zero);
if (m_lReturn != 0)
{
throw new Exception("初期化失敗。");
}
ClearCommand();
m_strShortName = "";
m_strShortName = m_strShortName.PadLeft(260, Convert.ToChar(" "));
m_lReturn = GetShortPathName(m_MciInfo.FileName,
m_strShortName,
m_strShortName.Length);
m_sbCommand.Append("open \"");
m_sbCommand.Append(GetPath(m_strShortName));
m_sbCommand.Append("\" type WaveAudio alias micmediaplay");
m_lReturn =
mciSendString(m_sbCommand.ToString(),
m_strCommandResult,
m_strCommandResult.Length,
IntPtr.Zero);
if (m_lReturn != 0)
{
throw new Exception("初期化失敗。");
}
m_strDeviceName = "micmediaplay";
m_lReturn =
mciSendString("set micmediaplay time format milliseconds",
m_strCommandResult,
m_strCommandResult.Length,
IntPtr.Zero);
if (m_lReturn != 0)
{
throw new Exception("初期化失敗。");
}
m_MciInfo.State = State.Ready;
}
}
}
#endregion
#region
public void Play()
{
lock (m_sbCommand)
{
m_strCommandResult = "";
m_strCommandResult =
m_strCommandResult.PadLeft(128, Convert.ToChar(" "));
if (String.IsNullOrEmpty(m_MciInfo.FileName))
{
throw new Exception("音声文件不存在。");
}
if (m_MciInfo.State != State.Ready)
{
return;
}
m_lReturn = mciSendString("play micmediaplay from 0",
m_strCommandResult,
m_strCommandResult.Length,
IntPtr.Zero);
if (m_lReturn != 0)
{
throw new Exception("再生失敗。");
}
m_MciInfo.State = State.Playing;
}
}
public void StopPlay()
{
lock (m_sbCommand)
{
m_MciInfo.State = State.Stop;
}
}
public void Close()
{
m_lReturn = mciSendString("close all",
m_strCommandResult,
m_strCommandResult.Length,
IntPtr.Zero);
if (m_lReturn != 0)
{
throw new Exception("釈放失敗。");
}
}
public bool IsStop()
{
lock (m_sbCommand)
{
m_strCommandResult = "";
m_strCommandResult =
m_strCommandResult.PadLeft(128, Convert.ToChar(" "));
if (m_MciInfo.State == State.Stop)
{
if (String.IsNullOrEmpty(m_strDeviceName))
{
m_lReturn = mciSendString("close micmediaplay",
m_strCommandResult,
m_strCommandResult.Length,
IntPtr.Zero);
if (m_lReturn != 0)
{
throw new Exception("停止失敗。");
}
m_strDeviceName = "";
}
m_lReturn = mciSendString("close all",
m_strCommandResult,
m_strCommandResult.Length,
IntPtr.Zero);
if (m_lReturn != 0)
{
throw new Exception("停止失敗。");
}
return true;
}
m_lReturn = mciSendString("status micmediaplay mode",
m_strCommandResult,
m_strCommandResult.Length,
IntPtr.Zero);
if (m_lReturn != 0)
{
throw new Exception("状態取得失敗");
}
if (m_strCommandResult.IndexOf("stopped") >= 0)
{
// 状態を変更する
m_MciInfo.State = State.Ready;
return true;
}
return false;
}
}
private string GetPath(string strPath)
{
if (strPath.Length < 1)
{
return "";
}
strPath = strPath.Trim();
strPath = strPath.Substring(0, strPath.Length - 1);
return strPath;
}
private void ClearCommand()
{
if (m_sbCommand.Length != 0)
{
m_sbCommand.Remove(0, m_sbCommand.Length);
}
}
#endregion
}
}
4.最后就是在我们的Build工作流模板中加一个Invoke的流,让这个流成功或者失败后去run我们生成的客户端的exe程序即可实现。