diff --git a/VirtualHereLib.sln b/VirtualHereLib.sln new file mode 100644 index 0000000..de08381 --- /dev/null +++ b/VirtualHereLib.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33502.453 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VirtualHereLib", "VirtualHereLib\VirtualHereLib.csproj", "{39300A96-C77D-4224-8533-14AE52AE06CE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualHereTestApp", "VirtualHereTestApp\VirtualHereTestApp.csproj", "{785B44CA-363B-4E5A-88CC-40FC9BB2AD0D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39300A96-C77D-4224-8533-14AE52AE06CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39300A96-C77D-4224-8533-14AE52AE06CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39300A96-C77D-4224-8533-14AE52AE06CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39300A96-C77D-4224-8533-14AE52AE06CE}.Release|Any CPU.Build.0 = Release|Any CPU + {785B44CA-363B-4E5A-88CC-40FC9BB2AD0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {785B44CA-363B-4E5A-88CC-40FC9BB2AD0D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {785B44CA-363B-4E5A-88CC-40FC9BB2AD0D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {785B44CA-363B-4E5A-88CC-40FC9BB2AD0D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {14201486-EA89-427F-9D01-0E1BB732A586} + EndGlobalSection +EndGlobal diff --git a/VirtualHereLib/Exceptions/NotConnectedToVirtualHereException.cs b/VirtualHereLib/Exceptions/NotConnectedToVirtualHereException.cs new file mode 100644 index 0000000..3040c6a --- /dev/null +++ b/VirtualHereLib/Exceptions/NotConnectedToVirtualHereException.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace VirtualHereLib.Exceptions +{ + public class NotConnectedToVirtualHereException : Exception + { + static readonly string message = "Connection with the VirtualHere Client has not been established yet. " + + "Did you forget to call the method connectToApplication()?"; + public NotConnectedToVirtualHereException() : base(message) + { + + } + } +} diff --git a/VirtualHereLib/Exceptions/VirtualHereNotRunningException.cs b/VirtualHereLib/Exceptions/VirtualHereNotRunningException.cs new file mode 100644 index 0000000..e5d0d2c --- /dev/null +++ b/VirtualHereLib/Exceptions/VirtualHereNotRunningException.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace VirtualHereLib.Exceptions +{ + public class VirtualHereNotRunningException : Exception + { + static readonly string message = "Unable to communicate with the VirtualHere Client. " + + "Did you forget to start it? " + + "Starting the client might take some time."; + public VirtualHereNotRunningException(Exception pBaseException) : base (message,pBaseException) + { + + } + } +} diff --git a/VirtualHereLib/VirtualHereClient.cs b/VirtualHereLib/VirtualHereClient.cs new file mode 100644 index 0000000..d35e1c8 --- /dev/null +++ b/VirtualHereLib/VirtualHereClient.cs @@ -0,0 +1,203 @@ +using System.Diagnostics; +using System.Diagnostics.Metrics; +using System.IO.Pipes; +using VirtualHereLib.Exceptions; + +namespace VirtualHereLib +{ + public class VirtualHereClient + { + string folderPath; + string execName = "vhui64.exe"; + + Process vhProcess = null; + NamedPipeClientStream pipe; + + public VirtualHereClient(string pPathToExecFolder) + { + folderPath = pPathToExecFolder; + } + + public VirtualHereClient(string pPathToExecFolder, string pExecName) + { + folderPath = pPathToExecFolder; + execName = pExecName; + } + + ~VirtualHereClient() + { + if (pipe != null) + { + if (pipe.IsConnected) + { + pipe.Close(); + } + } + } + + public void start(bool pMinimized) + { + vhProcess = new Process(); + vhProcess.StartInfo.FileName = folderPath + "/" + execName; + if (pMinimized) + { + vhProcess.StartInfo.WindowStyle = ProcessWindowStyle.Minimized; + vhProcess.StartInfo.Arguments = "-g"; + } + vhProcess.Start(); + } + + public void connectToApplication() + { + pipe = openPipe(); + } + + public VirtualHereDevice[] getAvailableDevices() + { + List devices = new List(); + + string[]output = RunCmdAndGetOutput("list"); + + if (output.Length < 6) + { + return null; + } + + int counter = 4; + + while(counter < output.Length) + { + string tmp = output[counter]; + counter++; + if(!tmp.StartsWith(" -->")) + { + counter++; + continue; + } + + tmp = tmp.Substring(6); + string fullAddress = strBetweenChars('(', ')', tmp); + string hubName = fullAddress.Split(".")[0]; + int deviceAddress = int.Parse(fullAddress.Split(".")[1]); + + //Get additional stuff + string[] outputDeviceInfo = RunCmdAndGetOutput("device info," + fullAddress); + string deviceVendor = outputDeviceInfo[1].Split(": ")[1]; + string deviceVendorID = outputDeviceInfo[2].Split(": ")[1]; + string deviceProduct = outputDeviceInfo[3].Split(": ")[1]; + string deviceProductID = outputDeviceInfo[4].Split(": ")[1]; + string deviceUser = outputDeviceInfo[5].Split(": ")[1]; + if (deviceUser == "NO ONE") + { + deviceUser = null; + } + + //create Device obj + VirtualHereDevice device = new VirtualHereDevice(hubName, deviceAddress, deviceProduct, deviceProductID, deviceVendor, deviceVendorID, deviceUser); + devices.Add(device); + } + + return devices.ToArray(); + } + + public void useDevice(VirtualHereDevice pDevice) + { + string address = pDevice.hub + "." + pDevice.address; + RunCmd("use," + address); + } + + public void stopUsingDevice(VirtualHereDevice pDevice) + { + string address = pDevice.hub + "." + pDevice.address; + RunCmd("stop using," + address); + } + + public void stop() + { + //vhProcess.CloseMainWindow(); + //vhProcess.Kill(); + RunCmd("exit"); + } + + private string[] RunCmdAndGetOutput(string pCmd) + { + List result = new List(); + + RunCmd(pCmd); + + StreamReader sr = new StreamReader(pipe); + + List buffer = new List(); + + while (sr.Peek() >= 0) + { + char temp = (char)sr.Read(); + buffer.Add(temp); + } + + string line = ""; + for(int i = 0; i < buffer.Count; i++) + { + if (buffer[i] == '\n') + { + result.Add(line); + Console.WriteLine("Received from server: {0}", line); + line = ""; + } + else + { + line += buffer[i]; + } + } + + return result.ToArray(); + } + + private void RunCmd(string pCmd) + { + if(pipe == null) + { + throw new VirtualHereLib.Exceptions.NotConnectedToVirtualHereException(); + } + + pipe.Flush(); + + char[] WriteCMD = pCmd.ToCharArray(); + + StreamWriter sw = new StreamWriter(pipe); + sw.AutoFlush = true; + + sw.Flush(); + sw.Write(WriteCMD); + + pipe.WaitForPipeDrain(); + + } + + private NamedPipeClientStream openPipe() + { + NamedPipeClientStream pipeClient = new NamedPipeClientStream(".", "vhclient", PipeDirection.InOut); + + try + { + pipeClient.Connect(2000); + } + catch (System.TimeoutException e) + { + throw new VirtualHereNotRunningException(e); + } + + pipeClient.ReadMode = PipeTransmissionMode.Message; + + return pipeClient; + } + + private string strBetweenChars(char pStartChar, char pEndChar, string pString) + { + int pFrom = pString.IndexOf(pStartChar) + 1; + int pTo = pString.IndexOf(pEndChar); + + return pString.Substring(pFrom, pTo - pFrom); + } + } +} \ No newline at end of file diff --git a/VirtualHereLib/VirtualHereDevice.cs b/VirtualHereLib/VirtualHereDevice.cs new file mode 100644 index 0000000..5c8acd4 --- /dev/null +++ b/VirtualHereLib/VirtualHereDevice.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace VirtualHereLib +{ + public class VirtualHereDevice + { + public string hub { get; } + public int address { get; } + public string deviceVendor { get; } + public string deviceVendorID { get; } + public string deviceProduct { get; } + public string deviceProductID { get; } + public string usedBy { get; } + + public VirtualHereDevice(string pHub, int pAddress, string pDeviceProduct, string pDeviceProductID, string pDeviceVendor, string pDeviceVendorID, string pUsedBy) + { + hub = pHub; + address = pAddress; + deviceVendor = pDeviceVendor; + deviceVendorID = pDeviceVendorID; + deviceProduct = pDeviceProduct; + deviceProductID = pDeviceProductID; + usedBy = pUsedBy; + } + + } +} diff --git a/VirtualHereLib/VirtualHereLib.csproj b/VirtualHereLib/VirtualHereLib.csproj new file mode 100644 index 0000000..132c02c --- /dev/null +++ b/VirtualHereLib/VirtualHereLib.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/VirtualHereTestApp/Program.cs b/VirtualHereTestApp/Program.cs new file mode 100644 index 0000000..292293c --- /dev/null +++ b/VirtualHereTestApp/Program.cs @@ -0,0 +1,29 @@ +using System; +using VirtualHereLib; + +namespace VirtualHereTestApp +{ + internal class Program + { + static void Main(string[] args) + { + VirtualHereClient client = new VirtualHereClient("E:\\AppsNoInstall\\VirtualHere"); + client.start(true); + + Task.Delay(2000).Wait(); + + client.connectToApplication(); + VirtualHereDevice[] devices = client.getAvailableDevices(); + + client.useDevice(devices[0]); + + Task.Delay(4000).Wait(); + + client.stopUsingDevice(devices[0]); + + Task.Delay(4000).Wait(); + + client.stop(); + } + } +} \ No newline at end of file diff --git a/VirtualHereTestApp/VirtualHereTestApp.csproj b/VirtualHereTestApp/VirtualHereTestApp.csproj new file mode 100644 index 0000000..a970cd5 --- /dev/null +++ b/VirtualHereTestApp/VirtualHereTestApp.csproj @@ -0,0 +1,14 @@ + + + + Exe + net6.0 + enable + enable + + + + + + +