需求:通过Unity启动外部的一个winform程序,传参数进行初始化。 程序启动后,untiy通过winApi给启动的程序发消息。
unity调用HoneyWellSDK显示视频,关闭的时候藏至后台。(后续发现,honeywell能通过Rtsp的方式,直接调用视频)
Untiy端:
Process myprocess;//摄像头程序进程
public const int WM_COPYDATA = 0x004A; //进程发送信息标识,之前用别的不行,用这个winform才接收到消息
public string HoneyWellWindowName = "HoneyWellVideoMonitor";
///
/// 创建新进程
///
///
///
private void CreateNewProcess(string args,string fileName="")
{
if(string.IsNullOrEmpty(fileName))
{
if (IsSDKInit) return;
fileName = Application.dataPath + "\\..\\release\\HUSSDKDemo.exe";
if (!File.Exists(fileName))
{
UnityEngine.Debug.LogErrorFormat("path:{0} not exist!", fileName);
return;
}
IsSDKInit = true;
}
myprocess = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo(fileName, args);
myprocess.StartInfo = startInfo;
myprocess.StartInfo.UseShellExecute = false;
myprocess.Start();
}
///
/// 开启视屏程序
///
///
///
private void StartProcess(string args)
{
try
{
string fileName = Application.dataPath + "\\..\\release\\HUSSDKDemo.exe";
if (!File.Exists(fileName))
{
UnityEngine.Debug.LogErrorFormat("path:{0} not exist!", fileName);
}
if (myprocess == null)
{
UnityEngine.Debug.LogError("create myprocess.StartInfo");
CreateNewProcess(args,fileName);
}
else if (myprocess.HasExited)
{
UnityEngine.Debug.LogError("Camera:myprocess.HasExited");
CreateNewProcess(args,fileName);
}
else
{
//这一部分,好像没有作用。根据名称找窗口,还是为0
IntPtr hWnd = myprocess.MainWindowHandle; //获取Form1.exe主窗口句柄
int pId = -1;
if (hWnd.ToInt32() == 0)
{
//HoneyWellWindowName = "HoneyWellVideoMonitor"; 窗体名为中文时,找不到。改成英文可以
pId = FindWindow(null, HoneyWellWindowName);
}
else
{
pId = hWnd.ToInt32();
}
string sendString = args;
byte[] sarr = System.Text.Encoding.Default.GetBytes(sendString);
int len = sarr.Length;
COPYDATASTRUCT cds;
cds.dwData = (IntPtr)0;
cds.cbData = len + 1;
cds.lpData = sendString;
ThreadManager.Run(()=>
{
//下方pid为0的情况,所有程序的 DefWndProc方法,都能接收到Untiy发的信息,这也是需要优化的地方
SendMessage(pId, WM_COPYDATA, 0, ref cds); //SendMessage是同步的,考虑放在线程里,防止卡住主线程
//想用PostMessage的方式,异步发送消息。但是测试没成功,后续得再调整
},()=>
{
UnityEngine.Debug.LogError("Show camera:" + args);
},"");
}
}
catch (Exception ex)
{
UnityEngine.Debug.LogError("Error : CameraVideoManage.StartProcess:" + ex.Message);
}
}
private void OnDestroy()
{
//winform关闭时,拦截了关闭消息。默认让它隐藏在后台,所以关闭untiy时,通过进程把程序关了。
if (myprocess != null) myprocess.CloseMainWindow(); //程序关闭识,把进程关闭。不然再打开程序,会有多个视频进程
}
#region WinAPI
[DllImport("User32.dll", EntryPoint = "FindWindow")]
private static extern int FindWindow(string lpClassName, string lpWindowName);
///
/// 根据句柄查找进程ID
///
///
///
///
[System.Runtime.InteropServices.DllImport("User32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);
///
/// 使用COPYDATASTRUCT来传递字符串
///
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
//消息发送API
[DllImport("User32.dll", EntryPoint = "SendMessage")]
public static extern int SendMessage(
IntPtr hWnd, // 信息发往的窗口的句柄
int Msg, // 消息ID
int wParam, // 参数1
int lParam //参数2
);
//消息发送API
[DllImport("User32.dll", EntryPoint = "SendMessage")]
public static extern int SendMessage(
int hWnd, // 信息发往的窗口的句柄
int Msg, // 消息ID
int wParam, // 参数1
ref COPYDATASTRUCT lParam //参数2
);
//消息发送API
[DllImport("User32.dll", EntryPoint = "PostMessage")]
public static extern int PostMessage(
IntPtr hWnd, // 信息发往的窗口的句柄
int Msg, // 消息ID
int wParam, // 参数1
int lParam // 参数2
);
//异步消息发送API
[DllImport("User32.dll", EntryPoint = "PostMessage")]
public static extern int PostMessage(
int hWnd, // 信息发往的窗口的句柄
int Msg, // 消息ID
int wParam, // 参数1
ref COPYDATASTRUCT lParam // 参数2
);
#endregion
WinFrom端:
程序启动入口,通过unity打开程序,能够收到传递的参数:
static class Program
{
///
/// The main entry point for the application.
///
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
ShowLog(args);
}
static void ShowLog(string[] args)
{
args = new string[] {"192.168.1.1|admin|admin|dddddd" };
if (args.Length <= 0)
{
Application.Run(new Form_SDKDemo());
}
if (args.Length == 1)
{
//MessageBox.Show("成功启动,参数为" + args.ToString());
SingleLiveForm form = new SingleLiveForm(args);
Application.Run(form);
}
}
}
功能界面:SingleLiveForm 只放部分用到的代码
///
/// 使用COPYDATASTRUCT来传递字符串
///
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
private static int WMA_InterPro = 0x004A;
protected override void DefWndProc(ref Message m)
{
if (m.Msg == WMA_InterPro)
{
COPYDATASTRUCT cds = new COPYDATASTRUCT();
Type t = cds.GetType();
cds = (COPYDATASTRUCT)m.GetLParam(t);
string receiveInfo = cds.lpData;
this.Show();
this.ShowInTaskbar = true;
string[] values = receiveInfo.Split('|');
if (values.Length < 4)
{
return;
}
string devGuid = values[3];
ShowVideo(devGuid);
}
else
{
base.DefWndProc(ref m);
}
}
private void SingleLiveForm_FormClosing(object sender, FormClosingEventArgs e)
{
//取消关闭窗口 ,隐藏至后台
e.Cancel = true;
this.Hide();
this.ShowInTaskbar = false;
}