The end goal of what I am trying to do is get the MMC (Microsoft Management Console) Computer Management snap-in (compmgmt.msc) process to be embedded into a Windows Form, or a workaround that will treat it like a modal pop-up menu.
Right now, I am just trying to get mmc.exe itself working, before I try to load a snap-in. The first part of the problem is the mmc.exe process almost exits immediately.
Edit: mmc.exe only exits immediately if the application is built as 32-bit (my machine is 64-bit). If the application is built to be 64-bit, the first process stays, which is what the expected behavior is.
However, I am still curious for an explanation as to why the strange temporary process behavior occurs. Note that the temporary mmc.exe process that is launched is 32-bit, but the final mmc.exe launched is 64-bit. Strange.
The following code will successfully embed iexplore.exe inside a Windows Form, but it fails to embed mmc.exe.
The reason it fails is an exception that occurs at the call to p.WaitForInputIdle();
An unhandled exception of type 'System.InvalidOperationException'
occurred in System.dll
Additional information: Cannot process request because the process has
exited.
As you can see from the error message, the process exits within milliseconds, but from a user's point of view, the MMC's GUI does still pop up as a separate, unrelated process to the original one I started.
This means that another mmc.exe process is being created which seems to have no connection to the original process created.
So the question is: Why is the MMC process immediately closing, with another MMC process opening almost immediately?
Relevant Windows Form code, similar to this question.
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
private void Form1_KeyPress(object sender, EventArgs e)
{
/// Uncomment *one* of these:
//Process p = Process.Start("mmc.exe");
//Process p = Process.Start("iexplore.exe");
Thread.Sleep(500);
p.WaitForInputIdle();
Console.WriteLine("MainWindowHandle: " + p.MainWindowHandle);
Console.WriteLine("Handle: " + p.Handle);
Thread.Sleep(5000);
SetParent(p.MainWindowHandle, this.Handle);
}
Related, but question seems to be more about the Console GUI itself closing, not allowing for editing, as opposed to some underlying process closing.
https://superuser.com/questions/194252/mmc-exe-starts-and-then-immediately-stops
A subsequent issue to this was that even when I located the new mmc process that pops up, it appears to have MainWindowHandle set to null, possibly meaning Windows doesn't recognize it as having a GUI.
The workaround to this was as simple adding sleep (a pause) between creating the "temporary" mmc process, and waiting for the new process to actually be ready. Note that process.WaitForInputIdle(); did not serve as a long-enough wait.
For anyone that might be having the same trouble as I had:
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = Environment.SystemDirectory + "\\" + "mmc.exe";
startInfo.Arguments = "\"" + Environment.SystemDirectory + "\\compmgmt.msc\" /s";
Process tempProcess = Process.Start(startInfo);
tempProcess.WaitForExit();
Thread.Sleep(500); // Added pause!
// Better alternative is to use a while loop on (MainWindowHandle == null)
// with some sort of timeout
Process[] processes = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(startInfo.FileName));
foreach (Process process in processes)
{
// do what you want with the process
Console.WriteLine("MainWindowHandle: " + process.MainWindowHandle);
// Set Computer Management window on top
SetWindowPos(process.MainWindowHandle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
SetParent(process.MainWindowHandle, this.Handle);
SetWindowLong(process.MainWindowHandle, GWL_STYLE, WS_VISIBLE);
process.WaitForExit();
}
But the main issue is figuring out why the first MMC process exits.
It exits because it may need to use a different bit-depth of MMC to run the snapin. As I am just learning now, snapins can be 32-bit or 64-bit. Windows may need to restart the snapin using either C:\Windows\SysWOW64\mmc.exe (1.34 MB (1,409,024 bytes)) or using C:\Windows\System32\mmc.exe (1.71 MB (1,802,240 bytes)).
https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms692753(v=vs.85)
So, for me, the task at hand seems to be how to discover, before launching a snapin, that snapin's bit-depth.
Related
I have 2 exe, A.exe and B.exe. A.exe is added to the registry's run key so that it starts with windows start up.
Inside of A's main, there is this code:
Process pr = new Process();
pr.StartInfo.FileName = "B.exe";
pr.StartInfo.Arguments = SomeArgs;
pr.Start();
Both A and B is in the same directory. If I launch A manually by double clicking it, it works fine, B starts up fine. But, when I tried to restart windows to check if it works fine at windows start up, every time A.exe crashed and hence B.exe was never launched. I thought it was some other problem in A, maybe system was slow to load some dependencies but no, when I removed the above part of code, everything works fine on windows start up, A dont crash but B is not launched. So what could be the problem or how to solve this?
Edit: used a try catch, and this came up, I have no idea why this came up though:
System.ComponentModel.Win32Exception: The system cannot find the file
specified at
System.Diagonstics.Process.StartWithShellExecuteEx(ProcessStartInfo
startInfo) at System.Diagonostics.Process.Start() at
System.Diagonostics.Process.Start(ProcessStartInfo startInfo) at
System.Diagnostics.Process.Start(String fileName, String arguments) at
....
I even tried with full file path still same error. But, manually launching it causes no error and works perfectly fine. Its just that this windows start up is messing it up.
try that one
Process pr = new Process();
pr.StartInfo.FileName = Application.StartupPath+"/B.exe";
pr.StartInfo.Arguments = SomeArgs;
pr.Start();
I believe you may be running into a Security error. Process requires certain permissions to work. See the Security section notes here:
Process Class
Figure out a way to log the issue and see if this is the problem you are running into.
Try to specify WorkingDirectory:
Process pr = new Process();
pr.StartInfo.WorkingDirectory = #"C:\path\to";
pr.StartInfo.FileName = "B.exe";
pr.StartInfo.Arguments = SomeArgs;
pr.Start();
I'm having problems with a program and its buttons (I know, I'm awesome lol) the buttons can be "programmed" to run programs. They also can be set to run as admin (different credentials).
If I set up simply notepad or cmd or explorer it runs like charm. But if I start iexplore it has got no admin rights.
I had problems before with running explorer.exe the solution was that I had to run it by typing the full path C:\windows\explorer.exe to be able to run it but that I solved it by setting up the VB2015 compiler (?) to Platform target: x64.
My other problem is that if I try to run dsa.msc or generally anything ends with msc it throws the following exception, even if I set up the full path to the syswow64 (or the system32) folder like c:\windows\syswow64\dsa.msc
"The specified executable is not a valid application for this OS platform."
Running the C:\Windows\System32\mmc.exe "services.msc" (or syswow64, with or without the /computer= switch) throws
"The requested operation requires elevation." which I have since I'm able to run services.msc (and all other msc-s from command line with the same user rights)
Thank you.
A beginner.
Basically you don't need to run the host app as administrator! There is a variable (inside your Process instance) called StartInfo (which is an instance of the ProcessStartInfo Class), where Verbs could be used as followed:
Process p = new Process()
{
StartInfo = new ProcessStartInfo("E:\\Users\\Temp\\app.exe")
{
Verb = "runas"
}
};
p.Start();
This will prompt the user to run the app.exe as administrator.
Edit
Running a Process as a defined user:
Process p = new Process()
{
StartInfo = new ProcessStartInfo("E:\\Users\\Temp\\app.exe")
{
Verb = "runas",
Arguments = "/user:Vira"
}
};
For more information about those RUNAS Arguments, click me! :)
I have a windows service that I would like to be automatically and silently updated. I started using wyBuild to implement this, but have had some issues with it, and decided to try to build my own. I've written a standalone exe that can be called to do the update procedure: checks for a new zip file with the update, downloads it, unzips, stop the windows service, copy files from the zip, then restart the service. This exe works fine when I run it from the commandline and wasn't really difficult to write.
However, now I would like the service (the same one being updated) to shell out to the updater exe to update itself. I first tried Process.Start:
var proc = Process.Start(pathToUpdaterExe);
proc.WaitForExit(60000);
This called the updater, but when the updater stops the service, the process is killed and the update stops. I did some searching and it sounds like the solution is to use a separate AppDomain. This is what I have now:
Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
Evidence objEvidence = new System.Security.Policy.Evidence(baseEvidence);
AppDomainSetup setup = new AppDomainSetup();
var updateDomain = AppDomain.CreateDomain("updateDomain", objEvidence, setup);
updateDomain.ExecuteAssembly(updater);
AppDomain.Unload(updateDomain);
However, now I get the error System.IO.IOException: "The process cannot access the file 'C:\Program Files (x86)\Company\Service\Service.dll' because it is being used by another process" when attempting to copy over the new Service.dll
Again, I've stopped the service at this point. I've confirmed this with logging. I can't imagine what would have Service.dll still locked, so I added code to check to see what is locking it:
public static IEnumerable<Process> GetProcessesLocking(string filePath)
{
var result = new List<Process>();
result.Clear();
var processes = Process.GetProcesses();
foreach (Process proc in processes)
{
try
{
if (proc.HasExited) continue;
foreach (ProcessModule module in proc.Modules)
{
if ((module.FileName.ToLower().CompareTo(filePath.ToLower()) == 0))
{
result.Add(proc);
break;
}
}
}
catch (Exception ex)
{
Log(ex.ToString());
Log("There was an error checking " + proc.ProcessName );
}
}
return result;
}
However this code indicates that nothing has a lock on the dll (result is empty and nothing is logged indicating an error).
I suspect I'm running afoul of some UAC issue that is the real cause of the IOException. The windows service runs as LocalSystem. All that to ask: How should I be running the update exe from the windows service such that it has rights to copy files in c:\Program Files?
Update
As the comments and answer suggest, Process.Start can work, but there is some nuance. You have to start cmd.exe and use it to start the updater. I also found I could not use a full path for the updater exe and that I needed to set UseShellExecute=false. This is my final working code that launches the updater from the .NET service:
var cmd = "/c start updater.exe";
var startInfo = new ProcessStartInfo("cmd.exe");
startInfo.Arguments = cmd;
startInfo.WorkingDirectory = AssemblyDirectory;
startInfo.UseShellExecute = false;
var proc = Process.Start(startInfo);
I did this exact thing - using a simpler (some might say kludgy) approach. The service:
Produces a batch command,
Downloads the new executables to a staging location,
Starts a process: cmd.exe which, in turn, runs the batch script w/o waiting for it to complete, and then
Immediately terminates itself.
The batch command:
Pings 127.0.0.1 five times,
Copies the executables to the final location and,
Restarts the service.
Works like clockwork. The ping is a reliable 5 second delay - lets the service shutdown before copying the files.
Edit:
Just for completeness - I realized that by batch cmd is pinging 127.0.0.1 not 128.0.0.1 and so I edited this answer to reflect that. I suppose either works - but 128.0.0.1 pings timeout, where 127.0.0.1 resolves to "me". Since I'm only using it as a poor-man's delay, it serves the purpose either way.
I'm making a program which opens a configured application after with the passed paramters through an url with shell execute. I achieved this with the following:
ProcessStartInfo procinfo = new ProcessStartInfo(URI);
procinfo.UseShellExecute = true;
Process App = Process.Start(procinfo);
I want to kill this process later after some minutes through this project that I could do by App.Kill() but the problem is that the Process.Start() always returns null if I pass the URI. How could I reach that process?
If the address of the executable file to start is a URL, the process
is not started and null is returned.
http://msdn.microsoft.com/en-us/library/53ezey2s.aspx
Even if you specify a browser, the process could be a simple handler that sends a message to an existing process (or opens another process) and closes itself immediately.
But you may explicitly launch the browser you want if you know how its process works.
Process p = Process.Start(browserExePath, url);
I am working on windows application. i have to run some window exe from my app, i am able to do the same but when i close my application these exe remains on running condition, i am not getting how can i close those exe. Please suggest some tips.
To run the Process
private void StartChildProcess(string fileName)
{
Process newProcess = new Process();
newProcess.StartInfo = new ProcessStartInfo(fileName); ;
newProcess.Start();
localProcess.Push(newProcess);
}
To close the process
private void CloseStartedProcesses()
{
while (localProcess.Count > 0)
{
Process process = localProcess.Pop();
if (process != null && !process.HasExited)
{
process.CloseMainWindow();
process.Close();
}
}
}
Some options:
Setup some communication system so the Main application can alert the other application to shutdown (read up on some WCF information or remoting)
Create a do.shutdown file and let the second application check if that file exists, simple but efficient.
Use the process.Kill options
Use Sendkey or equivalent to send a 'quit' key combination
Use Windows API - P/Invoke. FindWindow() or EnumWindows() to get the window handle. Then you can send WM_CLOSE or WM_QUIT to end the application via the SendMessage() function.
Note that if the application checks for user input on exiting (like a MessageBox asking weather the user really wants to quit) the only option might be to send WM_DESTROY which would be equivalent to Process.Kill (at least in respects to causing data loss - I am not certain it is the absolute equivalent).
Try this:
Process[] p = Process.GetProcessesByName("osk");
foreach (var item in p)
{
item.Kill();
}
The reason that the EXE you've ran from your application doesn't terminate once you close your application is probably because the 2nd application runs as a DIFFERENT, SEPARATE process.
If you run another process with System.Diagnostics.Process, it will remain in background until terminated manually or until it finishes it's job.
try this Process proc = Process.GetProcessesByName("processname");
proc.Kill();