I currently have an application (.Net Frameowork) that gets triggered via CMD request. I would like to only have one instance of the application running and I would like to handle the arguments being passed in. Right now I have the application identifying if there is a currently running instance.
Example:
cmd ReceiptApplication.exe -r:blah -c:foo
cmd ReceiptApplication.exe -r:blah2 -c:foo2
The second request would pass blah2 and foo2 to the currently running process of ReceiptApplication.exe and kill the second application.
What is the process or pattern for passing the parameters?
using System.Linq;
using System.Windows;
namespace ReceiptApplication
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
/// <summary>
/// Startup the application,
/// Process:
/// Get the arguments passed in
/// Validate the arguments
/// check to see if there is a running instance of the application
/// if there is a running app
/// Pass the arguments to the running application
/// kill the current application.
/// else
/// process the request
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Application_Startup(object sender, StartupEventArgs e)
{
string receiptID = GetArgument(e.Args, "-r");
string creditUnionFile = GetArgument(e.Args, "-c");
if(receiptID == null || creditUnionFile == null)
{
System.Windows.Forms.Application.Exit();
}
if (AppCurrntlyRunning())
{
//pass arguments to the current running application
Process alreadyRunningApplication = GetOriginalProcess();
var streamWriter = alreadyRunningApplication.StandardInput;
streamWriter.WriteLine("-r:blah -c:yay");
//kill this one
System.Windows.Forms.Application.Exit();
}
MessageBox.Show("Starting UI!");
MainWindow wnd = new MainWindow();
wnd.PullReceipt(receiptID, creditUnionFile);
wnd.Show();
}
}
}
If you want to pass information to your application during runtime you could use the standard input stream. This is how it's done: How to write to stdin in C#
Then in your running application you can read the written data with Console.ReadLine();
On the linked answer on how to write to stdin in C# mind that instead of starting a new application you want to store a reference to your already running one:
//DON'T do this
//var process = new Process();
//process.StartInfo = startInfo;
//process.Start();
//DO this
var processes = Process[] localByName = Process.GetProcessesByName("The Title Of My Application"); //This should give back multiple processes if you start your application for a second time so be mindful about that
Process alreadyRunningApplication;
if(processes.Length > 1)
{
if (processes[0].Id == Process.GetCurrentProcess.Id)
{
alreadyRunningApplication = processes[1];
}
else
{
alreadyRunningApplication = processes[0];
}
var streamWriter = alreadyRunningApplication.StandardInput;
streamWriter.WriteLine("I'm supplying input!");
}
else
{
//If we get into this else, it means this instance is the first running instance so your normal program behavior should go here for example using Console.ReadLine();
}
Related
So I need to make a Metro GUI App that uses an external fingerprint reader for user identification.
I've come so far as to make a DLL in C++ so I can call a method I made called CaptureSample() in C# referencing that DLL. The CaptureSample() method provides me with a byte array that represents the scanned fingerprint (a greyscale image from the fingerprint reader). So good so far. The way it does this, is to use the Microsoft Biometrics Framework to access the reader, wait for the reader to detect that a finger was laid on top of it, then send the data back of the scanned fingerprint.
This all works great. There is one catch however: I HAVE to run whatever application I am making as Administrator to make use of the framework. This is also why I can't just run the framework from the Webservice because the Webservice is run as a Network User or similar, making the library deny any access when tried to using it. So I have to make an extra console program that can run it instead.
Now here is where things get hairy. In order to make the fingerprint reader work with a Windows Metro GUI App, you'd have to run the app as admin. This is not possible as all Metro GUI apps run in a sandbox. I have to make an external console application that calls the DLL functionality for the app and then send the result of that back to the app.
To make things even more complicated I've found out that the Windows Phone subset of .NET does not have MSMQ which would have been nice to use. So instead, I made a local WCF Service that the Metro app needs to call, then the WCF Service calls the console program via MSMQ and sends the info back to the Metro GUI App whenever it receives it from the Console app.
So far so good. In theory. I've run into a problem in this process because the Console Application does run and is ready to scan when asked. But when I scan my finger nothing happens. The console needs focus in order to work, and that's out of the question as the app runs like a Kiosk and should never leave the Metro GUI App at all unless for maintenance.
I've looked at various solutions for detecting keyboard input outside a C# application but I don't think that applies to a Fingerprint Reader or if it does, I don't know how I'd do that. Any suggestions?
Just for good meassure I included a workflow chart so it's easier to understand. (It's a P5100 Zvetcobiometrics Fingerprint Reader, if anyone is curious):
So, I ran across an issue like this with Windows Forms, but not exactly with the issues that you described.
I understand that my solution isn't a pre-coded easy-day solution for you but I feel that with some minor modifications, an obstacle I overcame a few years ago may be of use to you. If you think my solution may help you, I can send you any missing pieces.
I created an inventory management system that utilized barcode scanners and I decided to implement the capability of being able to handle the input from a device by marshalling in some C++ classes without requiring the use of an input control such as a textbox. I needed the application to be able to process barcode input and make decisions without any additional user interactions or requirements. Just scan and go. The immediate use of the input from a keyboard/HID device is why I feel that this solution fits your question.
While testing the application I wrote, I was able to be inside of a full-screen game and still was able to utilize the barcode scanner as expected in the windows forms inventory application. This same functionality should work just as well in a console environment as console applications don't stop when they're in the background. You can even set it as NT AUTHORITY and prevent it from displaying to the desktop while running as a service and it should still chug away.
What I did was I used the Win32API to reflect through the devices, matched the device with the device specified via the application (User-chosen) and basically established a listener for that specific device.
You could use your console application to trigger the fingerprint sensor by running the console application as the local service account or programmatically obtaining necessary authorization (which would allow you to run it in elevated permissions without the UAC stuff getting in your way) and then use this inside of your metro app to read the input from the device as the device sends it.
Below are some of the code files for going about what I describe and have been modified to be specific towards my barcode scanner functionality.
Again, please contact me privately if you'd like to see any missing pieces.
PS: This technically could be used as a hack for intercepting keys and the sort so I will put a disclaimer for you to use at your own discretion and I am not responsible for anything that someone stupid may do with this code.
BarcodeScannerListenerInteropHelper.h:
#include <winuser.h>
BEGIN_INTEROP_NAMESPACE
using namespace System;
using namespace System::Collections::Generic;
using namespace HFSLIB::Barcode;
using namespace HFSLIB::Barcode::Interop;
using namespace HFSLIB::Barcode::Infrastructure::BarcodeScannerListener;
/// <summary>
/// Provides some helper methods that help the BarcodeScannerListener use native
/// Windows APIs without resorting to P/Invoking from C#.
/// </summary>
public ref class BarcodeScannerListenerInteropHelper
{
public:
/// <summary>
/// Returns a dictionary of barcode device handles to information about
/// the device.
/// </summary>
/// <param name="hardwareIds">The enumerable of hardware IDs to filter by.</param>
/// <returns>The device handle-to-information mapping of the filtered hardware IDs.</returns>
Dictionary<IntPtr, BarcodeScannerDeviceInfo^>^ InitializeBarcodeScannerDeviceHandles(
IEnumerable<String^>^ hardwareIds);
/// <summary>
/// Registers ourselves to listen to raw input from keyboard-like devices.
/// </summary>
/// <param name="hwnd">the handle of the form that will receive the raw
/// input messages</param>
/// <exception cref="InvalidOperationException">if the call to register with the
/// raw input API fails for some reason</exception>
void HookRawInput(IntPtr hwnd);
/// <summary>
/// Gets information from a WM_INPUT message.
/// </summary>
/// <param name="rawInputHeader">The LParam from the WM_INPUT message.</param>
/// <param name="deviceHandle">[Out] The device handle that the message came from.</param>
/// <param name="handled">[Out] True if the message represents a keystroke from that device.</param>
/// <param name="buffer">[Out] If handled is true, this contains the characters that the keystroke represents.</param>
void GetRawInputInfo(
IntPtr rawInputHeader,
IntPtr% deviceHandle,
bool% handled,
String^% buffer);
private:
/// <summary>
/// Converts a native raw input type into our version.
/// </summary>
/// <param name="rawInputType">The raw input type.</param>
/// <returns>Our version of the type.</returns>
static BarcodeScannerDeviceType GetBarcodeScannerDeviceType(DWORD rawInputType);
};
END_INTEROP_NAMESPACE
BarcodeScannerListenerInteropHelper.cpp:
#include "BarcodeScannerListenerInteropHelper.h"
using namespace System::ComponentModel;
BEGIN_INTEROP_NAMESPACE
/// <summary>
/// Gets information from a WM_INPUT message.
/// </summary>
/// <param name="rawInputHeader">The LParam from the WM_INPUT message.</param>
/// <param name="deviceHandle">[Out] The device handle that the message came from.</param>
/// <param name="handled">[Out] True if the message represents a keystroke from that device.</param>
/// <param name="buffer">[Out] If handled is true, this contains the characters that the keystroke represents.</param>
void BarcodeScannerListenerInteropHelper::GetRawInputInfo(
IntPtr rawInputHeader,
IntPtr% deviceHandle,
bool% handled,
String^% buffer)
{
UINT cbSize;
HRAWINPUT hRawInput;
hRawInput = (HRAWINPUT)rawInputHeader.ToPointer();
if (GetRawInputData(hRawInput, RID_INPUT, NULL, &cbSize, sizeof(RAWINPUTHEADER)) == 0)
{
RAWINPUT* raw;
raw = (RAWINPUT*)malloc(cbSize);
if (GetRawInputData(hRawInput, RID_INPUT, raw, &cbSize, sizeof(RAWINPUTHEADER)) == cbSize)
{
deviceHandle = IntPtr(raw->header.hDevice);
handled = raw->header.dwType == RIM_TYPEKEYBOARD &&
raw->data.keyboard.Message == WM_KEYDOWN;
if (handled)
{
BYTE state[256];
// Force the keyboard status cache to update
GetKeyState(0);
// Note: GetKeyboardState only returns valid state when
// the application has focus -- this is why we weren't
// getting shift keys when the application was not focused
if (GetKeyboardState(state))
{
WCHAR unmanagedBuffer[64];
if (ToUnicode(raw->data.keyboard.VKey,
raw->data.keyboard.MakeCode,
state,
unmanagedBuffer,
64,
0) > 0)
{
buffer = gcnew String(unmanagedBuffer);
}
}
}
}
free(raw);
}
}
/// <summary>
/// Registers ourselves to listen to raw input from keyboard-like devices.
/// </summary>
/// <param name="hwnd">the handle of the form that will receive the raw
/// input messages</param>
/// <exception cref="InvalidOperationException">if the call to register with the
/// raw input API fails for some reason</exception>
void BarcodeScannerListenerInteropHelper::HookRawInput(IntPtr hwnd)
{
RAWINPUTDEVICE rid[1];
rid[0].dwFlags = 0;
rid[0].hwndTarget = (HWND)hwnd.ToPointer();
rid[0].usUsage = 0x06; // Keyboard Usage ID
rid[0].usUsagePage = 0x01; // USB HID Generic Desktop Page
if (!RegisterRawInputDevices(rid, 1, sizeof(RAWINPUTDEVICE)))
{
InvalidOperationException^ e;
e = gcnew InvalidOperationException(
"The barcode scanner listener could not register for raw input devices.",
gcnew Win32Exception());
throw e;
}
}
/// <summary>
/// Returns a dictionary of barcode device handles to information about
/// the device.
/// </summary>
Dictionary<IntPtr, BarcodeScannerDeviceInfo^>^ BarcodeScannerListenerInteropHelper::InitializeBarcodeScannerDeviceHandles(IEnumerable<String^>^ hardwareIds)
{
Dictionary<IntPtr, BarcodeScannerDeviceInfo^>^ devices;
UINT uiNumDevices;
UINT cbSize;
devices = gcnew Dictionary<IntPtr, BarcodeScannerDeviceInfo^>();
uiNumDevices = 0;
cbSize = sizeof(RAWINPUTDEVICELIST);
if (GetRawInputDeviceList(NULL, &uiNumDevices, cbSize) != -1)
{
PRAWINPUTDEVICELIST pRawInputDeviceList;
if (pRawInputDeviceList = (PRAWINPUTDEVICELIST)malloc(cbSize * uiNumDevices))
{
if (GetRawInputDeviceList(pRawInputDeviceList, &uiNumDevices, cbSize) != -1)
{
for (UINT i = 0; i < uiNumDevices; ++i)
{
UINT pcbSize;
RAWINPUTDEVICELIST rid;
rid = pRawInputDeviceList[i];
if (GetRawInputDeviceInfo(rid.hDevice, RIDI_DEVICENAME, NULL, &pcbSize) >= 0 &&
pcbSize > 0)
{
WCHAR* deviceName;
deviceName = (WCHAR*)malloc(sizeof(WCHAR) * (pcbSize + 1));
if (GetRawInputDeviceInfo(rid.hDevice, RIDI_DEVICENAME, deviceName, &pcbSize) >= 0)
{
bool add;
IntPtr deviceHandle;
BarcodeScannerDeviceInfo^ info;
String^ managedDeviceName;
add = false;
deviceHandle = IntPtr(rid.hDevice);
managedDeviceName = gcnew String(deviceName);
for each (String^ hardwareId in hardwareIds)
{
if (managedDeviceName->IndexOf(hardwareId, StringComparison::OrdinalIgnoreCase) >= 0)
{
add = true;
break;
}
}
if (add)
{
info = gcnew BarcodeScannerDeviceInfo(
managedDeviceName,
BarcodeScannerListenerInteropHelper::GetBarcodeScannerDeviceType(rid.dwType),
deviceHandle);
devices->Add(deviceHandle, info);
}
}
free(deviceName);
}
}
}
free(pRawInputDeviceList);
}
}
return devices;
}
/// <summary>
/// Converts a native raw input type into our version.
/// </summary>
/// <param name="rawInputType">The raw input type.</param>
/// <returns>Our version of the type.</returns>
BarcodeScannerDeviceType BarcodeScannerListenerInteropHelper::GetBarcodeScannerDeviceType(DWORD rawInputType)
{
BarcodeScannerDeviceType type;
switch (rawInputType)
{
case RIM_TYPEHID:
type = BarcodeScannerDeviceType::HumanInterfaceDevice;
break;
case RIM_TYPEKEYBOARD:
type = BarcodeScannerDeviceType::Keyboard;
break;
default:
type = BarcodeScannerDeviceType::Unknown;
break;
}
return type;
}
END_INTEROP_NAMESPACE
BarcodeScannerListener.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Permissions;
using System.Text;
using System.Windows.Forms;
using HFSLIB.Barcode.Infrastructure.BarcodeScannerListener;
using HFSLIB.Barcode.Interop;
namespace HFSLIB.Barcode
{
/// <summary>
/// This class uses Windows's native Raw Input API to listen for input from
/// a certain set of barcode scanners and devices. This way, the application
/// can receive input from a barcode scanner without the user having to
/// worry about whether or not a certain text field has focus, which was a
/// big problem
/// </summary>
public class BarcodeScannerListener : NativeWindow
{
/// <summary>
/// A mapping of device handles to information about the barcode scanner
/// devices.
/// </summary>
private Dictionary<IntPtr, BarcodeScannerDeviceInfo> devices;
/// <summary>
/// The WM_KEYDOWN filter.
/// </summary>
private BarcodeScannerKeyDownMessageFilter filter;
/// <summary>
/// The barcode currently being read.
/// </summary>
private StringBuilder keystrokeBuffer;
/// <summary>
/// The interop helper.
/// </summary>
private BarcodeScannerListenerInteropHelper interopHelper =
new BarcodeScannerListenerInteropHelper();
/// <summary>
/// Event fired when a barcode is scanned.
/// </summary>
public event EventHandler BarcodeScanned;
/// <summary>
/// Attaches the listener to the given form.
/// </summary>
/// <param name="form">The form to attach to.</param>
public void Attach(Form form)
{
IntPtr hwnd;
if (form == null)
{
throw new ArgumentNullException("form");
}
hwnd = form.Handle;
this.keystrokeBuffer = new StringBuilder();
this.InitializeBarcodeScannerDeviceHandles();
this.interopHelper.HookRawInput(hwnd);
this.HookHandleEvents(form);
this.AssignHandle(hwnd);
this.filter = new BarcodeScannerKeyDownMessageFilter();
Application.AddMessageFilter(this.filter);
}
/// <summary>
/// Hook into the form's WndProc message. We listen for WM_INPUT and do
/// special processing on the raw data.
/// </summary>
/// <param name="m">the message</param>
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case NativeMethods.WM_INPUT:
if (this.ProcessRawInputMessage(m.LParam))
{
this.filter.FilterNext = true;
}
break;
}
base.WndProc(ref m);
}
/// <summary>
/// Fires the barcode scanned event.
/// </summary>
/// <param name="deviceInfo">information about the device that generated
/// the barcode</param>
private void FireBarcodeScanned(BarcodeScannerDeviceInfo deviceInfo)
{
string barcode;
EventHandler handler;
barcode = this.keystrokeBuffer.ToString();
if (barcode != null && barcode.Length > 0)
{
handler = this.BarcodeScanned;
this.keystrokeBuffer = new StringBuilder();
if (handler != null)
{
handler(this, new BarcodeScannedEventArgs(barcode, deviceInfo));
}
}
}
/// <summary>
/// Hooks into the form's HandleCreated and HandleDestoryed events
/// to ensure that we start and stop listening at appropriate times.
/// </summary>
/// <param name="form">the form to listen to</param>
private void HookHandleEvents(Form form)
{
form.HandleCreated += this.OnHandleCreated;
form.HandleDestroyed += this.OnHandleDestroyed;
}
/// <summary>
/// Initializes the barcode scanner device handles.
/// </summary>
private void InitializeBarcodeScannerDeviceHandles()
{
BarcodeScannerListenerConfigurationSection config;
BarcodeScannerListenerConfigurationElementCollection hardwareIdsConfig;
IEnumerable<string> hardwareIds;
config = BarcodeScannerListenerConfigurationSection.GetConfiguration();
hardwareIdsConfig = config.HardwareIds;
hardwareIds = from hardwareIdConfig in hardwareIdsConfig.Cast<BarcodeScannerListenerConfigurationElement>()
select hardwareIdConfig.Id;
this.devices = this.interopHelper.InitializeBarcodeScannerDeviceHandles(hardwareIds);
}
/// <summary>
/// When the form's handle is created, let's hook into it so we can see
/// the WM_INPUT event.
/// </summary>
/// <param name="sender">the form whose handle was created</param>
/// <param name="e">the event arguments</param>
private void OnHandleCreated(object sender, EventArgs e)
{
this.AssignHandle(((Form)sender).Handle);
}
/// <summary>
/// When the form's handle is destroyed, let's unhook from it so we stop
/// listening and allow the OS to free up its resources.
/// </summary>
/// <param name="sender">the form whose handle was destroyed</param>
/// <param name="e">the event arguments</param>
private void OnHandleDestroyed(object sender, EventArgs e)
{
this.ReleaseHandle();
}
/// <summary>
/// Process the given WM_INPUT message.
/// </summary>
/// <param name="rawInputHeader">the rawInputHeader of the message</param>
/// <returns>whether or not the keystroke was handled</returns>
private bool ProcessRawInputMessage(IntPtr rawInputHeader)
{
BarcodeScannerDeviceInfo deviceInfo;
bool handled;
bool keystroke;
string localBuffer;
IntPtr rawInputDeviceHandle;
handled = false;
keystroke = false;
localBuffer = string.Empty;
rawInputDeviceHandle = IntPtr.Zero;
this.interopHelper.GetRawInputInfo(
rawInputHeader,
ref rawInputDeviceHandle,
ref keystroke,
ref localBuffer);
if (this.devices.TryGetValue(rawInputDeviceHandle, out deviceInfo) && keystroke)
{
handled = true;
if (localBuffer.Length == 1 && localBuffer[0] == 0xA)
{
this.FireBarcodeScanned(deviceInfo);
}
else
{
this.keystrokeBuffer.Append(localBuffer);
}
}
return handled;
}
}
}
I want to kill a running IIS Instance programmatically that is occupying a specific port, but it seems there is no way to figure out what IIS Instance is using a specific port.
netstat.exe just shows that the process is having the PID 4, but that's the system process. "netsh http show urlacl" does not display the occupied port at all.
The IIS Express Tray program knows this somehow. When I try to start another IIS Express instance while the port is occupied I get the following error:
"Port '40000' is already being used by process 'IIS Express' (process ID '10632').
Anyone got a clue how I can get this information?
It seems like the PID is 4 (System) because the actual listening socket is under a service called http.
I looked at what iisexpresstray.exe was using to provide a list of all running IISExpress applications. Thankfully it's managed .NET code (all in iisexpresstray.dll) that's easily decompiled.
It appears to have at least three different ways of getting the port number for a process:
Reading /port from the command-line arguments (unreliable as we know)
Running netsh http show servicestate view=requestq and parsing the output
Calling Microsoft.Web.RuntimeStatusClient.GetWorkerProcess(pid) and parsing the site URL
Unfortunately, most of the useful stuff in iisexpresstray.dll like the IisExpressHelper class is declared internal (although I imagine there're tools to generate wrappers or copy the assembly and publicize everything).
I opted to use Microsoft.Web.dll. It was in my GAC, though for some reason wasn't appearing in the list of assemblies available to add as a reference in Visual Studio, so I just copied the file out from my GAC. Once I had Microsoft.Web.dll it was just a matter of using this code:
using (var runtimeStatusClient = new RuntimeStatusClient())
{
var workerProcess = runtimeStatusClient.GetWorkerProcess(process.Id);
// Apparently an IISExpress process can run multiple sites/applications?
var apps = workerProcess.RegisteredUrlsInfo.Select(r => r.Split('|')).Select(u => new { SiteName = u[0], PhysicalPath = u[1], Url = u[2] });
// If we just assume one app
return new Uri(apps.FirstOrDefault().Url).Port;
}
You can also call RuntimeClient.GetAllWorkerProcesses to retrieve only actual worker processes.
I looked into RegisteredUrlsInfo (in Microsoft.Web.dll) as well and found that it's using two COM interfaces,
IRsca2_Core (F90F62AB-EE00-4E4F-8EA6-3805B6B25CDD)
IRsca2_WorkerProcess (B1341209-7F09-4ECD-AE5F-3EE40D921870)
Lastly, I read about a version of Microsoft.Web.Administration apparently being able to read IISExpress application info, but information was very scarce, and the one I found on my system wouldn't even let me instantiate ServerManager without admin privileges.
Here is a C# implementation of calling netsh.exe as recommended within the answer by #makhdumi:
Usage:
static public bool TryGetCurrentProcessRegisteredHttpPort(out List<int> ports, out Exception ex)
{
NetshInvoker netsh = new NetshInvoker();
return netsh.TryGetHttpPortUseByProcessId(Process.GetCurrentProcess().Id, out ports, out ex);
}
Implementation:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace YourCompanyName.Server.ServerCommon.Utility
{
/// <summary>
/// Invoke netsh.exe and extract information from its output.
/// Source: #crokusek, https://stackoverflow.com/questions/32196188
/// #GETah, https://stackoverflow.com/a/8274758/538763
/// </summary>
public class NetshInvoker
{
const string NetshHttpShowServiceStateViewRequestqArgs = "http show servicestate view=requestq";
public NetshInvoker()
{
}
/// <summary>
/// Call netsh.exe to determine the http port number used by a given windowsPid (e.g. an IIS Express process)
/// </summary>
/// <param name="windowsPid">For example an IIS Express process</param>
/// <param name="port"></param>
/// <param name="ex"></param>
/// <returns></returns>
public bool TryGetHttpPortUseByProcessId(Int32 windowsPid, out List<Int32> ports, out Exception ex)
{
ports = null;
try
{
if (!TryQueryProcessIdRegisteredUrls(out Dictionary<Int32, List<string>> pidToUrlMap, out ex))
return false;
if (!pidToUrlMap.TryGetValue(windowsPid, out List<string> urls))
{
throw new Exception(String.Format("Unable to locate windowsPid {0} in '{1}' output.",
windowsPid, "netsh " + NetshHttpShowServiceStateViewRequestqArgs));
}
if (!urls.Any())
{
throw new Exception(String.Format("WindowsPid {0} did not reference any URLs in '{1}' output.",
windowsPid, "netsh " + NetshHttpShowServiceStateViewRequestqArgs));
}
ports = urls
.Select(u => new Uri(u).Port)
.ToList();
return true;
}
catch (Exception ex_)
{
ex = ex_;
return false;
}
}
private bool TryQueryProcessIdRegisteredUrls(out Dictionary<Int32, List<string>> pidToUrlMap, out Exception ex)
{
if (!TryExecNetsh(NetshHttpShowServiceStateViewRequestqArgs, out string output, out ex))
{
pidToUrlMap = null;
return false;
}
bool gotRequestQueueName = false;
bool gotPidStart = false;
int currentPid = 0;
bool gotUrlStart = false;
pidToUrlMap = new Dictionary<int, List<string>>();
foreach (string line in output.Split('\n').Select(s => s.Trim()))
{
if (!gotRequestQueueName)
{
gotRequestQueueName = line.StartsWith("Request queue name:");
}
else if (!gotPidStart)
{
gotPidStart = line.StartsWith("Process IDs:");
}
else if (currentPid == 0)
{
Int32.TryParse(line, out currentPid); // just get the first Pid, ignore others.
}
else if (!gotUrlStart)
{
gotUrlStart = line.StartsWith("Registered URLs:");
}
else if (line.ToLowerInvariant().StartsWith("http"))
{
if (!pidToUrlMap.TryGetValue(currentPid, out List<string> urls))
pidToUrlMap[currentPid] = urls = new List<string>();
urls.Add(line);
}
else // reset
{
gotRequestQueueName = false;
gotPidStart = false;
currentPid = 0;
gotUrlStart = false;
}
}
return true;
}
private bool TryExecNetsh(string args, out string output, out Exception exception)
{
output = null;
exception = null;
try
{
// From #GETah, https://stackoverflow.com/a/8274758/538763
Process p = new Process();
p.StartInfo.FileName = "netsh.exe";
p.StartInfo.Arguments = args;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
output = p.StandardOutput.ReadToEnd();
return true;
}
catch (Exception ex)
{
exception = ex;
return false;
}
}
}
}
In my case I just output "Command line" column in Task manager and it's getting obvious, which IISExpress is that:
You can run below command to get the information of the executable and its PID
netstat -a -n -o -b | find "iisexpress.exe"
I am writing a few automated web tests using C# Watin framework.
I was hoping anyone can help me out,
How do i open new IE instance in "in private" browse mode? (i.e incognito mode)
The need for "in private" browsing, is because some of the tests, require log in. (and i run a few in parallel)
I could not find any resources on the matter. (other than half patch i found in some forum)
Thanks for your help!
The only solution i was able to find, is to open IE instance via command in incognito mode, then attach Watin to it.
//gen random url so we can find the window later
Random rnd = new Random();
int id = rnd.Next(1000, 10000);
string url = "id" + id+".com";
//opening explorer
Process.Start("IExplore.exe", "-private -nomerge " + url);
browser = Browser.AttachTo<IE>(Find.ByUrl(new Regex(url)));
browser.GoTo("http://www.google.com");
I downloaded WatiN source codes, opened IE.cs and edited the method CreateIExploreInNewProcess
private static Process CreateIExploreInNewProcess()
{
var arguments = "about:blank";
if (GetMajorIEVersion() >= 8 && Settings.MakeNewIe8InstanceNoMerge)
arguments = "-nomerge " + arguments;
if (Settings.OpenInIncognitoMode == true)
{
arguments = "-private " + arguments;
}
var m_Proc = Process.Start("IExplore.exe", arguments);
if (m_Proc == null) throw new WatiNException("Could not start IExplore.exe process");
return m_Proc;
}
Then, added this to Settings.cs:
/// <summary>
/// Gets or sets a value indicating whether the browser will be opened in incognito mode.
/// </summary>
/// <value>
/// <c>true</c> if IE instance needs to be opened in incognito mode, otherwise <c>false</c>.
/// </value>
public static bool OpenInIncognitoMode
{
get { return Instance.OpenInIncognitoMode; }
set { Instance.OpenInIncognitoMode = value; }
}
After that, added this to ISettings.cs
/// <summary>
/// Gets or sets a value indicating whether the browser will be opened in incognito mode.
/// </summary>
/// <value>
/// <c>true</c> if IE instance needs to be opened in incognito mode, otherwise <c>false</c>.
/// </value>
bool OpenInIncognitoMode { get; set; }
Finally, edited DefaultSettings.cs like this:
private struct settingsStruct
{
...
...
public bool makeNewIe8InstanceNoMerge;
public bool closeExistingFireFoxInstances;
public bool incognitoMode;
}
public bool OpenInIncognitoMode
{
get { return settings.incognitoMode; }
set { settings.incognitoMode = value; }
}
private void SetDefaults()
{
settings = new settingsStruct
{
...
...
makeNewIe8InstanceNoMerge = true,
closeExistingFireFoxInstances = true,
incognitoMode = false
};
}
Compile it and add the new DLL to your project. After this, all you need to do in your project is this:
Settings.OpenInIncognitoMode = true;
var browser = new IE(url, true);
The trick is to pass the argument -private to the call of IExplore.exe like here:
string argument = "-private -nomerge about:blank";
process = Process.Start("IExplore.exe", argument);
if (process == null)
throw new InvalidOperationException("The IExplore.exe process can't be started");
Thread.Sleep(3000);
handle = process.MainWindowHandle.ToInt32();
var allBrowsers = new SHDocVw.ShellWindows();
if (handle != 0)
{
foreach (InternetExplorer browser in allBrowsers)
if (browser.HWND == handle)
{
ie = browser;
iehandle = (IntPtr)ie.HWND;
break;
}
}
Hey so I have a logger class that is called frequently, sometimes when its called fast repeatedly it will throw an exception that the file is already open being used by another application. The only way we found a way around this was to catch the exception then try to open it again... I'm not sure how to handle this properly.
/// <summary>
/// Open a log file based on a date
/// </summary>
/// <param name="date"> Date of the file to open </param>
public static void OpenLogFile(DateTime date)
{
while (true)
{
try
{
logStream = File.Open("Logs/ems." + date.ToString("yyyy-MM-dd") + ".log", FileMode.Append);
break;
}
catch
{
continue;
}
}
}
/// <summary>
/// Writes to a log file the specified input
/// </summary>
/// <param name="input"> Content to write to the log file </param>
public static void Log(string className, string methodName, string input)
{
OpenLogFile(DateTime.Now);
using (StreamWriter s = new StreamWriter(logStream))
{
s.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + '[' + className + '.' + methodName + "] " + input);
}
CloseLogFile();
}
/// <summary>
/// Closes the current log file
/// </summary>
public static void CloseLogFile()
{
if (logStream != null)
{
logStream.Close();
logStream = null;
}
}
Since this is a log file, I think the obvious (and correct) solution, is to leave the file open for the duration of your program's execution.
If you don't want to use an already-implemented 3rd party logger, like Apache's log4net, you could write your own little logger class that uses thread-safe mechanisms for writing lines to the file.
It would probably be a static class, or singleton. Generally, execution at the beginning and end of your program is quite predictable, so it should be clear where to initialize, and close out the object/class.
A bit of order is required, not a disk free-for-all. Store log messages in a queue and have a single thread dequeue and write items.
Is there a way to automate the turning on or off of a Receive Location in BizTalk? It seems like there should be some kind of API or some such for this kind of thing. I would prefer to work in C#, but WMI or some kind of script would work too.
Besides ExplorerOM, as you've found out, you can also enable/disable receive locations (and control send ports) using WMI.
I have a sample PowerShell script that shows how to do those things here, if you're interested.
I found a solution. It appears that the Microsoft.BizTalk.ExplorerOM.dll is what I wanted. Here is an excerpt from the BizTalk documentation that should get anyone else started:
using System;
using Microsoft.BizTalk.ExplorerOM;
public static void EnumerateOrchestrationArtifacts()
{
// Connect to the local BizTalk Management database
BtsCatalogExplorer catalog = new BtsCatalogExplorer();
catalog.ConnectionString = "Server=.;Initial Catalog=BizTalkMgmtDb;Integrated Security=SSPI;";
// Enumerate all orchestrations and their ports/roles
Console.WriteLine("ORCHESTRATIONS: ");
foreach(BtsAssembly assembly in catalog.Assemblies)
{
foreach(BtsOrchestration orch in assembly.Orchestrations)
{
Console.WriteLine(" Name:{0}\r\n Host:{1}\r\n Status:{2}",
orch.FullName, orch.Host.Name, orch.Status);
// Enumerate ports and operations
foreach(OrchestrationPort port in orch.Ports)
{
Console.WriteLine("\t{0} ({1})",
port.Name, port.PortType.FullName);
foreach(PortTypeOperation operation in port.PortType.Operations)
{
Console.WriteLine("\t\t" + operation.Name);
}
}
// Enumerate used roles
foreach(Role role in orch.UsedRoles)
{
Console.WriteLine("\t{0} ({1})",
role.Name, role.ServiceLinkType);
foreach(EnlistedParty enlistedparty in role.EnlistedParties)
{
Console.WriteLine("\t\t" + enlistedparty.Party.Name);
}
}
// Enumerate implemented roles
foreach(Role role in orch.ImplementedRoles)
{
Console.WriteLine("\t{0} ({1})",
role.Name, role.ServiceLinkType);
}
}
}
}
One caveat, apparently this dll does not support 64 bit. Since I am only writing a simple utility it's not a big deal for me (just compiling as 32-bit), but it is something to be aware of.
Glad to see that you seem to have found a solution.
Wanted to mention a similar alternative which is also using Powershell, ExplorerOM, and the BizTalk API to set BizTalk artifacts to various statuses.
Receive Locations being one of them.
The script accepts XML configuration files, where you list the artifacts and what status you would like to set them to.
The script has been published to Microsoft Script Center:
http://gallery.technet.microsoft.com/scriptcenter/Set-Artifact-Status-270f43a0
In response to Alhambraeidos comment. Here's is some excerpts of code I used in a Windows app to disable a Receive Location remotely:
/// <summary>
/// Gets or sets the biz talk catalog.
/// </summary>
/// <value>The biz talk catalog.</value>
private BtsCatalogExplorer BizTalkCatalog { get; set; }
/// <summary>
/// Initializes the biz talk artifacts.
/// </summary>
private void InitializeBizTalkCatalogExplorer()
{
// Connect to the local BizTalk Management database
BizTalkCatalog = new BtsCatalogExplorer();
BizTalkCatalog.ConnectionString = "server=BiztalkDbServer;database=BizTalkMgmtDb;integrated security=true";
}
/// <summary>
/// Gets the location from biz talk.
/// </summary>
/// <param name="locationName">Name of the location.</param>
/// <returns></returns>
private ReceiveLocation GetLocationFromBizTalk(string locationName)
{
ReceivePortCollection receivePorts = BizTalkCatalog.ReceivePorts;
foreach (ReceivePort port in receivePorts)
{
foreach (ReceiveLocation location in port.ReceiveLocations)
{
if (location.Name == locationName)
{
return location;
}
}
}
throw new ApplicationException("The following receive location could not be found in the BizTalk Database: " + locationName);
}
/// <summary>
/// Turns the off receive location.
/// </summary>
/// <param name="vendorName">Name of the vendor.</param>
public void TurnOffReceiveLocation(string vendorName)
{
ReceiveLocation location = Locations[vendorName].ReceiveLocation;
location.Enable = false;
BizTalkCatalog.SaveChanges();
}
You'll notice that there is some I left out, like I was creating a dictionary of receive locations called "Locations", but you should be able to get the idea. The pattern pretty much holds true for any BizTalk object you want to interact with.