I did something to control the vwork software to run protocol file through LIMS interface of vwork, for at that time I do not have the vwork API manual. I think do as the manual will be the best way. But it will be possible to control vwork, and I share the code.
using log4net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Xml;
namespace ScratchNet.Agilent.Controller
{
class VWorkRunItem
{
protected static readonly ILog log = LogManager.GetLogger("vwork");
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_CLOSE = 0xF060;
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern int PostMessage(IntPtr hwnd, uint msg, IntPtr wparam, IntPtr lparam);
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("User32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public const int SW_SHOWMINNOACTIVE = 7;
[DllImport("user32.dll")]
static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int msg, int Param, string s);
const int WM_SETTEXT = 0x000c;
private void SetTextt(IntPtr hWnd, int item, string text)
{
IntPtr boxHwnd = GetDlgItem(hWnd, item);
SendMessage(boxHwnd, WM_SETTEXT, 0, text);
}
/// <summary>
/// 启动vwork软件,并登录
/// </summary>
/// <returns></returns>
public Process StartVWork(string binPath, string user, string password)
{
//var ps = new ProcessStartInfo(binPath);
//ps.CreateNoWindow = false;
//ps.UseShellExecute = true;
var px = Process.Start(binPath);
Thread.Sleep(5000);
//登录窗口句柄
IntPtr huser = IntPtr.Zero;
while (huser == IntPtr.Zero)
{
//主窗口句柄
IntPtr handle = px.MainWindowHandle;
//SetForegroundWindow(handle);
ShowWindow(handle, SW_SHOWMINNOACTIVE);
//菜单栏句柄
//IntPtr h2 = FindWindowEx(handle, IntPtr.Zero, "ProfUIS-DockBar", "Menubar");
//Console.WriteLine(string.Format("{0:X2}", h2.ToInt32()));
//获得工具栏句柄
//IntPtr h3 = FindWindowEx(h2, IntPtr.Zero, "ProfUIS-ControlBar", "Control Toolbar");
//Console.WriteLine(string.Format("{0:X2}", h3.ToInt32()));
//发送点击登录按钮消息
PostMessage(handle, 0x0111, new IntPtr(0x03E9), IntPtr.Zero);
//Console.WriteLine("Send Completed");
Thread.Sleep(200);
//查找登录窗口
huser = FindWindowByCaption(IntPtr.Zero, "User Authentication");
}
log.Info("find the login dialog " + huser);
//填写用户名和密码
//Console.WriteLine(huser);
Thread.Sleep(50);
var btnHandler = FindWindowEx(huser, IntPtr.Zero, "Button", "OK");
SetTextt(huser, 1000, user);
SetTextt(huser, 1012, password);
//发送点击OK按钮消息
PostMessage(huser, 0x0111, new IntPtr(0x01), btnHandler);
DateTime timeout = DateTime.Now.AddSeconds(5);
Thread.Sleep(50);
huser = FindWindowByCaption(IntPtr.Zero, "User Authentication");
while (huser != IntPtr.Zero && timeout > DateTime.Now)
{
Thread.Sleep(50);
huser = FindWindowByCaption(IntPtr.Zero, "User Authentication");
}
Thread.Sleep(150);
//查找登录失败窗口
timeout = DateTime.Now.AddSeconds(2);
var failedHandler = FindWindow("#32770", "Login Error");
while (failedHandler == IntPtr.Zero && timeout > DateTime.Now)
{
Thread.Sleep(50);
failedHandler = FindWindow("#32770", "Login Error");
}
log.Info("finding the login failure dialog " + failedHandler);
//Console.WriteLine(huser + ", " + failedHandler);
if (huser != IntPtr.Zero || failedHandler != IntPtr.Zero)
{
log.Error("login to vwork failed with " + user + "/" + password);
throw new Exception("Failed to login to vwork");// Language.LoginFailedDesc);
}
return px;
}
public string ModifiedProtocol { get; private set; }//因为运行后文件被打开,任何修改已经都没用了,所以必须用一个新名字
public string StartFile { get; private set; }
public string CompleteFile { get; private set; }
public string OriginalProtocol { get; private set; }
public event EventHandler<EventArgs> Started;
public event EventHandler<EventArgs> Completed;
public VWorkRunItem(string protocol, string modifiedProtocolPath, string startFile, string completeFile)
{
OriginalProtocol = protocol;
ModifiedProtocol = modifiedProtocolPath;
StartFile = startFile;
CompleteFile = completeFile;
ModifyProtocol(protocol, modifiedProtocolPath, startFile, completeFile);
}
bool IsAborting = false;
public void Abort()
{
IsAborting = true;
}
public void Run(string inputfile, int waitStartTimeout=5, int waitCompletTimeout=0)
{
IsAborting = false;
if (File.Exists(StartFile))
File.Delete(StartFile);
if (File.Exists(CompleteFile))
File.Delete(CompleteFile);
log.Info("run modified protocol: " + ModifiedProtocol);
PrepareInputFile(inputfile);
bool waitStarted = false;
//如果开始失败,重试几次
waitStarted = WaitFile(StartFile, waitStartTimeout);
//如果开始还是失败,则通知用户
if (!waitStarted)
{
log.Error("failed to start the profocol, and ask for restarting the vwork software");
throw new TimeoutException("Timeout when starting the protocol");
}
//删除开始文件
Thread.Sleep(200);
File.Delete(StartFile);
Started?.Invoke(this, new EventArgs());
if (!WaitFile(CompleteFile, waitCompletTimeout))
{
log.Error("no complete file found");
MessageBox.Show("failed to complete");
}
//删除结束文件
Thread.Sleep(100);
File.Delete(CompleteFile);
int retry = 5;
if (retry>0 && !WaitAndCloseVWorksDlg())
{
log.Error("failed to close the complete dialog");
retry--;
Thread.Sleep(200);
}
Completed?.Invoke(this, new EventArgs());
}
void PrepareInputFile(string inputfile)
{
var temp = Path.GetTempFileName();
StreamWriter writer = new StreamWriter(new FileStream(temp, FileMode.Create));
writer.Write(ModifiedProtocol.Replace("\\", "/"));
writer.Flush();
writer.Close();
File.Move(temp, inputfile);
}
bool WaitFile(string file, int timeout = 60)
{
log.Info("wait for " + file);
if (timeout <= 0)
{
while (!IsAborting)
{
if (File.Exists(file))
{
//Console.WriteLine("find file " + file);
return true;
}
Thread.Sleep(200);
}
return false;
}
else
{
DateTime t = DateTime.Now.AddSeconds(timeout);
while (DateTime.Now < t)
{
if (File.Exists(file))
{
//Console.WriteLine("find file " + file);
return true;
}
if (IsAborting)
return false;
Thread.Sleep(200);
}
return false;
}
}
bool WaitAndCloseVWorksDlg(int timeout = 10)
{
//Console.WriteLine("finding the dlg");
DateTime t = DateTime.Now.AddSeconds(timeout);
IntPtr handler = IntPtr.Zero;//dlg handler
while (DateTime.Now < t)
{
handler = FindWindow("#32770", "VWorks");
if (handler != IntPtr.Zero)
{
//Console.WriteLine("find dlg " + handler);
break;
}
Thread.Sleep(50);
}
if (handler == IntPtr.Zero)
return false;
Thread.Sleep(200);
SendMessage(handler, WM_SYSCOMMAND, SC_CLOSE, 0);
return true;
}
void ModifyProtocol(string protocol, string modifiedProtocol, string startFile, string completeFile)
{
XmlDocument doc = new XmlDocument();
doc.Load(protocol);
var node = doc.SelectSingleNode("Velocity11/File_Info");
SetScript(doc, node, "StartScript", CreateScript(startFile, "started"));
SetScript(doc, node, "FinishScript", CreateScript(completeFile, "completed"));
doc.Save(modifiedProtocol);
}
string CreateScript(string file, string content)
{
string script = "var obj=new File();obj.Open(\"" + file.Replace("\\", "/") + "\");obj.Write(\"" + content + "\");obj.Close();";
return script;
}
void SetScript(XmlDocument doc, XmlNode node, string name, string script)
{
var snode = node.Attributes[name];
if (snode == null)
{
snode = doc.CreateAttribute(name);
node.Attributes.Append(snode);
}
snode.Value = script;
}
}
}
for handling user name and passwork in login dialog, following code was used (run under administrator)
huser = FindWindowByCaption(IntPtr.Zero, "User Authentication");
var btnHandler = FindWindowEx(huser, IntPtr.Zero, "Button", "OK");
SetTextt(huser, 1000, user);
SetTextt(huser, 1012, password);