In my C# Winforms application I implemented a watcher that notify me when a new process starts in the local OS.
ManagementEventWatcher watcher = new ManagementEventWatcher(new ManagementScope("\\\\.\\root\\cimv2"), new WqlEventQuery("__InstanceCreationEvent", new TimeSpan(0, 0, 0, 1), "TargetInstance ISA 'Win32_Process'"));
watcher.Scope.Options.EnablePrivileges = true;
watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
I'm not directly interested in the process started but in an eventual file that caused the process to start.
Think about a double click on "d:\documents\doc.txt" that causes notepad.exe to be launched.
The watcher notifies me about the new notepad.exe process and then I can check if there is a file responsible for its starting.
This is the code that notifies me when the event arrives.
void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
ManagementBaseObject mbo = (ManagementBaseObject)e.NewEvent["TargetInstance"];
string executable = mbo.GetPropertyValue("ExecutablePath").ToString().ToLower();
string commandLine = mbo.GetPropertyValue("CommandLine").ToString().ToLower();
[...]
}
Inside the variable commandLine I find the full command line, in my example:
c:\windows\system32\notepad.exe d:\documents\doc.txt
The code works well for almost every program but I found a problem with files whose extensions are linked with no program.
When I double click on one of this file the Open With dialog (the process name is openwith.exe) pops up and I am regularly notified by the watcher but when I read the CommandLine property I found something like this:
c:\windows\system32\openwith.exe -embedding
instead of the expected:
c:\windows\system32\openwith.exe d:\documents\document.unlinkedExt
All the properties I can analize from the mbo oject don't help me. My assumption is that this kind of instance is not using an usual command line to execute the process.
The question is: how can I extract the full file path that caused the Open With dialog opening?
Checked on Windows 8.1 and 10 with .NET framework 2.0 and 4.0.
Related
I am trying to run an application that accepts command line arguments from within a C# application, when I launch the application without arguments, it works fine, but if I put in the arguments, I see a window flash on the screen for only a second. The arguments contain forward slashes.
Here is the code:
private void BtnStartStress_Click(object sender, EventArgs e)
{
Process GpuTest = new Process();
GpuTest.StartInfo.FileName = #"C:\Users\Computer_User\source\repos\StressTool\GpuTest\GpuTest.exe";
GpuTest.StartInfo.Arguments = "/test=fur";
GpuTest.StartInfo.UseShellExecute = false;
GpuTest.StartInfo.CreateNoWindow = false;
GpuTest.Start();
}
I can't figure out why it won't work with the arguments.
Edit: I found it works if I put the executable (and related DLLs) in the bin folder with the executable for my application. The issue appears to be with the GpuTest executable being in a different folder than my application's executable.
FYI, the software I am using is the GPU Test from Geeks3D https://www.geeks3d.com/gputest/
I'm building a simple Windows Service (basically combining this tutorial with this class).
Now I have a "FROM" directory and two "TO" (TO1, TO2) directories. When I place a file into FROM, it should be copied both to TO1 and TO2. I install the service and I start it in the Service Control Manager where I see it's running. On the first run, it copies the file to TO1 and TO2 and the service is still running after that.
Then, when I place another file to FROM (with a different name), nothing happens. And refreshing the services I find that the service stopped.
Why does the service stop? It seems it stops just in the moment when I place the second file.
Here I register the file system watcher:
// File System Watcher
var fileSystemWatcher = new FileSystemWatcher();
fileSystemWatcher.Created += FileSystemWatcher_MoveOnCreate;
fileSystemWatcher.Path = this.fromPath;
fileSystemWatcher.EnableRaisingEvents = true;
And here is the event handler:
private void FileSystemWatcher_MoveOnCreate(object sender, FileSystemEventArgs e)
{
string FROM = Path.Combine(fromPath, e.Name);
string TO1 = Path.Combine(toPathOne, e.Name);
string TO2 = Path.Combine(toPathTwo, e.Name);
File.Copy(FROM, TO1);
File.Copy(FROM, TO2)
}
If the Windows Service stops there was an unhandled exception in your code somewhere. Try to surround the key point of your code ( maybe the entire body of the function FileSystemWatcher_MoveOnCreate ) with try{}catch(){} and log what's happening. In general you should add log to your windows service is the only way you can understand if things are going on anyway.
I have created a windows form program that does some Business Intelligence but have subsequently needed to access this via a webform. I am fairly new to programming so I don't know what can be achieved here. But essentially I am wanting someone to go on to the net and when the user presses a button it sends a message to the windows form executable in a file and tells it to run and then press a button on the form, which runs a method to generate images of graphs. Is this possible?
Here is the relevant code.
In the webform I have this button.
protected void rolloutSmartSheets(object sender, EventArgs e)
{
string message = string.Format("Starting processes");
ltMessage.Text = message;
Process process = new Process();
process.StartInfo.FileName = #"P:\Visual Studio 2013\Projects\Smartsheet\SmartsheetAPI\obj\Debug\SmartSheetAPI.exe";
process.Start();
message = string.Format("Ended all processes");
ltMessage.Text = message;
}
That runs the executable but it opens the windows form and I imagine if the executable is sitting on another computer wouldn't that open on that computer? In which case i want it to tell it to press this button on the windows form which runs the method I need and then the user doesn't need to worry about it.
public void commitToDatabase_Click(object sender, EventArgs e)
{
commitToDataBase();
}
If you are able to have the clients install something in advance, you can provide this functionality using a custom protocol handler.
Example protocol handler from MSDN Article
HKEY_CLASSES_ROOT
alert
(Default) = "URL:Alert Protocol"
URL Protocol = ""
DefaultIcon
(Default) = "alert.exe,1"
shell
open
command
(Default) = "C:\Program Files\Alert\alert.exe" "%1"
Then add a link onto your webform like this
href="alert://test"
As long as the client has the handler installed, both in the registry and the executable file, it will run C:\Program Files\Alert\alert.exe, passing "test" to it as the first paramater.
You can easily change this to provide the ability to run the local graph generator, and pass any parameters from the webform you might need.
I have an issue with an auto update software that I am trying to make. The application runs as a server application and checks via FTP for updates and downloads them if there is a newer version available. This then unzips a folder called update in the programs root directory. it then launches a file called update.bat that does any file copying etc that I may need to do for that update. Once this is finished the update.bat launches the new server application. Once the program goes to check for updates again it is suppose to delete the update directory that is in the root directory of the server application as well as the update.rar file that was downloaded from the update server. All of this works perfectly except the folder is being used and will not delete. I have read all kinds of things about releasing the handle and changing the current directory etc.. but just can't seem to get it to work. I would appreciate someone helping me out here. Here is the code for this update.
private void Form1_Load(object sender, EventArgs e)
{
foreach (string s in Directory.GetDirectories("C:/my update dir"))
{
if (s.Contains("Instance"))
{
var _instance = Regex.Match(s, #"\d+");
Process p = new Process();
ProcessStartInfo pinfo = new ProcessStartInfo();
pinfo.FileName = "cmd.exe";
pinfo.WorkingDirectory = "C:/mySQL/bin";
pinfo.Arguments = "/C mysql.exe -u** -p** dbnameHere" + _instance.ToString() +
" < \"C:/my update dir/update/update.sql\"";
p.StartInfo = pinfo;
p.Start();
p.WaitForExit();
p.Close();
p.Dispose();
Directory.SetCurrentDirectory("C:/");
}
}
Directory.SetCurrentDirectory("C:/");
this.Dispose();
Application.Exit();
}
I'm going to guess that your problem is here:
Once this is finished the update.bat launches the new server
application.
Windows is going to "lock" the directories all the way down to the .BAT file. So if the .BAT runs a server process from that directory, that process is going to inherit the CWD and file descriptors of the calling process.
It's not clear from your code that this is what's happening, but you may also want to try changing the CWD prior to spawning the process.
This is a possible duplicate. Couldn't find the exact one, I remember going through one such long time back.
The tool needs a capability to detect if any MS Word file is opened anywhere from the computer. So we use a process watcher, like this:
string query = "SELECT TargetInstance FROM __Instance" + Event + "Event WITHIN 0.5 " +
"WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.Name = '" + processName + "'";
string scope = #"\\.\root\CIMV2";
//Create a watcher and listen for events
watcher = new ManagementEventWatcher(scope, query);
watcher.EventArrived += eventHandler;
watcher.Start();
Now whatever that is, here is the tricky part: I need to get the word automation instance of the currently opened WINWORD process. So I use Marshal.GetActiveObject to get the running instance. But an opened Word application gets registered in the running object table only if the word app loses focus (as documented by msdn). How do I manually register the word application in ROT if I have the process with me? Some pseudo code below
//process started
private void ProcessStarted(object sender, EventArrivedEventArgs e)
{
// Marshal.GetActiveObject fails since there is no object yet.
// Process.GetProcessesByName("WINWORD") got it.
// now how to register this word process to ROT?
// so that I have a global instance of word application?
}
Note: I can with some heavy API calls programmatically force focus away from opened word window and then bring it back, but thats a complete mess.
Any normal way of registering?
As far as I know there is no way to register another application's objects in the ROT without its direct cooperation. The table doesn't track processes, it tracks class factories and their associated monikers. In order to register something in the ROT you need its IUnknown pointer, which is not something you're going to get from Word directly.