I came across some issue I cannot explain to myself.
I get a list of all running processes and their parent process using the following code:
foreach (var process in allProcesses)
{
try
{
int parent_process_id = 0;
//Get ProcessID of Parent Process
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = " + process.Id + "");
foreach (ManagementObject reader in searcher.Get())
{
parent_process_id = Convert.ToInt32(reader["ParentProcessId"]);
searcher.Dispose();
}
//Get Main Process Information
string process_path = process.MainModule.FileName;
string process_name_full = process.ProcessName;
//Get Parent Process Information
string parent_process_path = null;
string parent_process_name_full = null;
var parent_process = Process.GetProcessById(parent_process_id);
parent_process_name_full = parent_process.ProcessName;
parent_process_path = parent_process.MainModule.FileName;
process_log_information = "Periodic Scan detected and submitted the following processes:" + Environment.NewLine + "Main ProcessID: " + process.Id + Environment.NewLine + "Main Process Name: " + process.ProcessName + Environment.NewLine + "Main Process Path: " + process.MainModule.FileName + Environment.NewLine + "Parent ProcessID: " + parent_process_id + Environment.NewLine + "Parent Process Name: " + parent_process_name_full + Environment.NewLine + "Parent Process Path: " + parent_process_path;
Application_Control.Application_Control.Check_Process(process.Id, process_name_full, process_path, parent_process_id, parent_process_name_full, parent_process_path, true, process_log_information);
}
catch (Exception ex)
{
Logging.Logging.log_microsoft_defender_antivirus_cfa("Microsoft_Defender_AntiVirus.Periodic_Check.Check_Processes_Tick", "Process Query.", ex.Message);
}
}
Now if I look on the collected file paths behind the processes, it looks like this for example:
Main ProcessID: 4792
Main Process Name: ctfmon
Main Process Path: C:\Windows\system32\ctfmon.exe
Parent ProcessID: 4664
Parent Process Name: svchost
Parent Process Path: C:\Windows\System32\svchost.exe
Why is our main process path first letter of "system32" not in upper case?
Opposite example where the main process is in upper case, but the parent isn't:
Main ProcessID: 6344
Main Process Name: SystemSettingsBroker
Main Process Path: C:\Windows\System32\SystemSettingsBroker.exe
Parent ProcessID: 500
Parent Process Name: svchost
Parent Process Path: C:\Windows\system32\svchost.exe
As far as I know windows is not case sensitive, as long as you don't set a flag in the registry to be. But in any case I would like to get the correct case sensitive path.
I hope you understand my issue description and got some tips on this case.
Thank you!
Edit: Process Hacker displays the paths correctly.
Edit2: I need to correct myself. I wrote a small test application to collect process information:
var processes = Process.GetProcesses();
foreach (var proc in processes)
{
try
{
MessageBox.Show(proc.MainModule.FileName + " " + proc.Id.ToString());
}
catch
{
}
}
The first process that woke up my interest was svchost.exe because the path shown was: C:\Windows\system32\svchost.exe
Since the first letter of system32 was again lower case I decided to look on the process using Process Hacker. Following information is being displayed:
The image file names path is in upper case. If I look on the process modules and it's main module, it is also in upper case.
So why does Process.GetProcesses(); -> process.MainModule.Filename; gets the path with a lower case?
Another time the svchost process (different pid) is being shown correctly by process.MainModule.Filename; as:
C:\Windows\System32\svchost.exe
On Process Hacker I see the following information:
What differs is the "Command line" information. So I think while describing my issue I actually found the reason? I need to sleep now. Maybe you have a hint to this. Otherwise I will further investigate this issue tomorrow I think. Thank you
Edit: Before going to sleep I was to curious and looked on the information provided by the WMI. The executable path differs regarding the lower and upper case situation. For me I found out, the issue is not on my side. But maybe someone has a idea why that happens? I guess it is the path provided using a command line execution. Maybe I will check that theory tomorrow.
Related
So, I am running SSIS (through VS) and I have two segments that hang me up when my clients don't send in the exact files every day. I have a task that deletes old files, and then renames the current files to the filename with _OLD at the end of it.
The issue is: If the files that are in there aren't the exact same, it crashes, failing the entire thing.
An example:
A client sends in on Monday files: Names, Addresses, Grades, Schools
The same client, on Tuesday sends in: Names, Addresses, Schools
Since the Grades file doesn't exist, it still gets renamed to Grades_OLD but the SSIS fails.
The scripts are:
del Names_OLD.csv
bye
This will then go to the Rename Script:
ren Names.csv Names_OLD.csv
bye
and will then go on to Addresses, to do the same thing. It is super frustrating that these fail when a single file doesn't exist the next day, and there doesn't seem to be a need for it.
We have two scripts that generate the archive data to process:
public void Main()
{
Dts.Variables["ARCHIVEFILE"].Value = Path.GetFileNameWithoutExtension(Dts.Variables["FTPFILE"].Value.ToString()) + "_OLD" + Path.GetExtension(Dts.Variables["FTPFILE"].Value.ToString());
Dts.TaskResult = (int)ScriptResults.Success;
}
and
public void Main()
{
/*PSFTP_DEL_script.txt
del %1
bye
PSFTP_REN_script.txt
ren %1 %2
bye
*/
var lineOut = String.Empty;
var File1 = Dts.Variables["User::FTPWORKINGDIR"].Value.ToString() + "\\SSIS_PSFTP_DEL_script.txt";
var File2 = Dts.Variables["User::FTPWORKINGDIR"].Value.ToString() + "\\SSIS_PSFTP_REN_script.txt";
lineOut = "del " + Dts.Variables["User::ARCHIVEFILE"].Value.ToString() + Environment.NewLine + "bye";
System.IO.File.WriteAllText(File1, lineOut);
lineOut = "ren " + Dts.Variables["User::FTPFILE"].Value.ToString() + " " + Dts.Variables["User::ARCHIVEFILE"].Value.ToString() + Environment.NewLine + "bye";
System.IO.File.WriteAllText(File2, lineOut);
Dts.TaskResult = (int)ScriptResults.Success;
}
Researching it doesn't really give anything helpful, and kind of just leads me back to where I am right now.
Try using a foreach loop on files for each file that can be processed and put all the processing of the file inside it. And do not put any precendence constraints between the foreach loops.
This will process the files that are there an not fail when the others aren't there.
The foreach loop essentially works as a check if the file exists.
This assumes you do not need all the files to properly process them.
Why not checking if the file exists before writing the script:
if (System.IO.File.Exists(Dts.Variables["User::ARCHIVEFILE"].Value.ToString())){
lineOut = "del " + Dts.Variables["User::ARCHIVEFILE"].Value.ToString() + Environment.NewLine + "bye";
System.IO.File.WriteAllText(File1, lineOut);
}
if (Dts.Variables["User::FTPFILE"].Value.ToString())){
lineOut = "ren " + Dts.Variables["User::FTPFILE"].Value.ToString() + " " + Dts.Variables["User::ARCHIVEFILE"].Value.ToString() + Environment.NewLine + "bye";
System.IO.File.WriteAllText(File2, lineOut);
}
Im making a program that makes a Wi-Fi hotspot for you and enables Internet Connection Sharing automaticly using a powershell script.
The script works and runs perfectly, but i have to wait for it to be finished so i can notify the user its done. Im using below code which works but...
but it crashes and causes an error on my home computer which is allot faster.
I get a Cannot read or write or memory is corrupt error which i can't really explain.
public static void ToggleIcs(string connectionInterface, bool state)
{
string toggle;
string par1;
string par2;
if (state){
toggle = "EnableSharing";
par1 = "0";
par2 = "1";
}else{
toggle = "DisableSharing";
par1 = "";
par2 = "";
}
using (PowerShell powerShellInstance = PowerShell.Create())
{
// this script enables or disables internet sharing with the connectionInterface given.
powerShellInstance.AddScript("" +
"regsvr32 hnetcfg.dll /s;" +
"$m = New-Object -ComObject HNetCfg.HNetShare;" +
"$m.EnumEveryConnection |% { $m.NetConnectionProps.Invoke($_) };" +
"$c = $m.EnumEveryConnection |? { $m.NetConnectionProps.Invoke($_).Name -eq '" + connectionInterface + "' };" +
"$config = $m.INetSharingConfigurationForINetConnection.Invoke($c);" +
"Write-Output $config.SharingEnabled;" +
"Write-Output $config.SharingConnectionType;" +
"$config." + toggle + "(" + par1 + ");" +
"$m2 = New-Object -ComObject HNetCfg.HNetShare;" +
"$m2.EnumEveryConnection |% { $m2.NetConnectionProps.Invoke($_) };" +
"$c2 = $m2.EnumEveryConnection |? { $m2.NetConnectionProps.Invoke($_).DeviceName -Match 'Microsoft Hosted Network Virtual Adapter' };" +
"$config2 = $m2.INetSharingConfigurationForINetConnection.Invoke($c2);" +
"Write-Output $config2.SharingEnabled;" +
"Write-Output $config2.SharingConnectionType;" +
"$config." + toggle + "(" + par2 + ");");
PSDataCollection<PSObject> outputCollection = new PSDataCollection<PSObject>();
IAsyncResult result = powerShellInstance.BeginInvoke<PSObject, PSObject>(null, outputCollection);
Console.WriteLine(DateTime.Now + ">> Started Powershell script");
int i = 0;
while (!result.IsCompleted)
{
if (i < 60)
{
Console.WriteLine(DateTime.Now + ">> Running script");
}
else
{
ScriptFailed();
powerShellInstance.Stop();
break;
}
i++;
Thread.Sleep(1000);
}
Console.WriteLine(DateTime.Now + ">> Executed Internet Sharing script");
}
}
This is the error im getting:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I don't get a line that says where it crashes but it crashes after Thread.Sleep(1000);. Which i found out using breakpoints
As I said, the script runs fine on my laptop, and it does work on my faster computer, but it crashes as soon as it hits Thread.Sleep(1000).
After it crashed, I checked if ICS was enabled in the network and sharing center, and and it did so correctly.
I tried removing the Thread.Sleep(1000); but then it crashes anyway a line before.
What can I try or do differently?
Edit
i dont have the stack trace yet, as i am not on my faster PC where it crashes. but I will post it as soon as possible.
Edit
As mentioned by TheLethalCoder, it could be that i try to acces IsCompleted While it is being updated. If that is why it happens, How would I check if it is being altered or wait for it to be done.
Edit
As i dont really know what the call stack is for, or what a stack trace is, and how i can use it ill provide an image of what i saw one moment before the crash.
Edit
I did some snooping around and found a few things i tried.
first, in the application properties -> build, i ticked "Prefer 32bit" off
Because some people fixed their problems with this. And i did not get a crash but the script also failed to run and caused my internet connection to drop.
so i turned it back on.
I also tried the netsh winsock reset command and restarting my pc but it still crashed.
Im all out of clues now, but i posted these two things for people who come by looking for an answer and maybe this will work.
The MSDN article: Polling for the Status of an Asynchronous Operation states that the way you are polling the result is correct. However their example doesn't include a Thread.Sleep:
while (result.IsCompleted != true)
{
UpdateUserInterface();
}
So to eliminate this I would use the following snippet that keeps track of the variables without sleeping, note that printing to the Console on every loop is going to quickly pollute the window though:
Stopwatch sw = new Stopwatch();
sw.Start();
while (!result.IsCompleted)
{
if (sw.EllapsedMilliseconds >= 60000) //60 seconds
{
break;
}
Console.WriteLine(DateTime.Now + ">> Running script");
}
if (!result.IsCompleted)
{
ScriptFailed();
powerShellInstance.Stop();
}
This is more of a comment than an answer but it was getting too long to be used as a comment.
I have written the c# console application. when i lauch the application (not using cmd). i can see it is listed in process list in task manager ,now i need to write another application in which i need to find whether previous application is running or not ,i know the application name and path so i have written management object searcher query to get the list of process and also i am using the path to compare it with its executable path ,code is given below
var name="test.exe"
var path="D:\test"
var processCollection = new ManagementObjectSearcher("SELECT * " + "FROM Win32_Process " + "WHERE Name='" + name + "'").Get();
if (processCollection.Count > 0)
{
foreach(var process in processCollection)
{
var executablePath=process["ExecutablePath"];
if(executablePath.equals(path))
{
return true;
}
}
}
but executable path is always null.
how to get its executable path?.
I can not only use process name because i am using common name like startserver and stopserver to my application. so i need to ensure it executable path.
there is a easier way, import System.Diagnostics then write following code,
public bool ProcessIsRun()
{
Process[] proc = Process.GetProcesses();
Return proc.Any(m => m.ProcessName.Contains("Your process name") && m.Modules[0].FileName == "Your File Path" );
}
This is solution for your problem:
System.Reflection.Assembly.GetEntryAssembly()
This will return complete folder path for executable current application.
You can use System.Reflection.Assembly.GetEntryAssembly().Location to find exact application executable with full path.
I have a program that is a launcher for a mod for a game. The launcher works for most of the people who use it, including myself, but for some there is a strange bug that really has me struggling to fix it, and further more driving me absolutely mental!
The basic idea is that my mod files are contained in a folder, the launcher iterates through these files, reads a certain byte of the file and based on the result either moves the file, or moves the file and writes some text to a certain file, then launches the game. Seemingly simple.
The main launch function looks like this:
private void Launch()
{
using (StreamWriter writer = new StreamWriter(userScriptPath, false, Encoding.Unicode))
{
foreach (string file in Directory.GetFiles(modFolderPath + "\\Files\\", "*.pack"))
{
int p = GetPackType(file);
if (p == 3)
{
if (File.Exists(modFolderPath + "\\Files\\" + Path.GetFileName(file)))
{
File.Move(modFolderPath + "\\Files\\" + Path.GetFileName(file), dataPath + "\\" + Path.GetFileName(file));
}
writer.WriteLine("mod \"" + Path.GetFileName(file) + "\";");
}
else if (p == 4)
{
if (File.Exists(modFolderPath + "\\Files\\" + Path.GetFileName(file)))
{
File.Move(modFolderPath + "\\Files\\" + Path.GetFileName(file), dataPath + "\\" + Path.GetFileName(file));
}
}
}
}
Process game = Process.Start(gamePath);
// There is code here that waits for a minute until the game process is actually found, incase its slow starting up
game.WaitForExit();
RestorePacks(); // <- Method to put back the files after finishing
}
The problem some users are getting is that when launching the mod the game launches but it appears as though the launcher doesn't move the files as the game is still in its normal state, it was very hard to ascertain exactly why this was happening as I had no way of debugging it on their computers and the program was working fine for me and all of my test users.
To try and find out what was going on I added a number of checks and some logging to the launcher so that if the launcher didn't work, I'd at least have an idea why. (Note that no errors are thrown for the users even when it doesn't work)
The checks I added included using File.Exists() after attempting to move a file to make sure it was actually moved, the logging kept a note of move attempts and the result of this check to see if the file was actually moved.
I even added a specific if statement to the Process.Start function checking specifically that a certain file was indeed in the required location before launching the game.
Finally before launching all of the files in the folder where the mod files should now be are written to the log.
All of the logs from users who the launcher didn't work for shared one thing in common the program attempted to move the file, threw no error, and then when checking that the file was indeed moved, the file appeared to be there. But when reaching the point where all of the files in the required directory are written to the log, only one of the required 30+ mod files appear to be in the directory.
An example output log looked something like this:
File moving: modfile1.txt
Checking if file is where we tried to move it to: Yes
File moving: modfile2.txt
Checking if file is where we tried to move it to: Yes
File moving: modfile3.txt
Checking if file is where we tried to move it to: Yes
Writing out all files in directory:
normalgamefile1.txt
normalgamefile2.txt
normalgamefile3.txt
modfile1.txt
After seeing this and noticing it was always only a single file that had moved and no others, and also that the program did think the files were where they where supposed to be, the confusion really started to kick in.
This is the method that reads the file to ascertain what type of file it is:
private int GetPackType(string path)
{
FileStream fs = File.OpenRead(path);
BinaryReader reader = new BinaryReader(fs);
reader.ReadChars(4);
int packType = reader.ReadInt32();
fs.Close();
fs.Dispose();
return packType;
}
As you can probably see, and what I've just noticed is that I've failed to close/dispose of reader, and I'm guessing and somewhat hoping this might be the cause of my problem.
(Note I'm now using Using statements in this method but can't test this fix for quite a while)
SO, if you've read this far thank you, my question is..
Firstly do you have any idea what the problem is? Could it be that reader still might have the file open and has not closed and thus the file can't move, IF SO then why does it work perfectly for me and most others, but not for some? Surely a file still being used elsewhere would throw an error?
I've gone through all the simple stuff like making sure the program is run with administrator privileges, etc.
Thank you greatly for any help!
EDIT
As asked in the comments this is the version of the code with my checks and logging added. Simple stuff, which is why I omitted it, the log simply adds to a string, the string is then printed to file when all is done.
private void Launch()
{
using (StreamWriter writer = new StreamWriter(userScriptPath, false, Encoding.Unicode))
{
foreach (string file in Directory.GetFiles(modFolderPath + "\\Files\\", "*.pack"))
{
int p = GetPackType(file);
if (p == 3)
{
if (File.Exists(modFolderPath + "\\Files\\" + Path.GetFileName(file)))
{
File.Move(modFolderPath + "\\Files\\" + Path.GetFileName(file), dataPath + "\\" + Path.GetFileName(file));
}
log += "Move File: " + Path.GetFileName(file) + "\r\n";
writer.WriteLine("mod \"" + Path.GetFileName(file) + "\";");
log += "Write mod line: " + Path.GetFileName(file) + "\r\n";
}
else if (p == 4)
{
if (File.Exists(modFolderPath + "\\Files\\" + Path.GetFileName(file)))
{
File.Move(modFolderPath + "\\Files\\" + Path.GetFileName(file), dataPath + "\\" + Path.GetFileName(file));
}
log += "Move File: " + Path.GetFileName(file) + "\r\n";
}
// Check the file did actually move
if (File.Exists(dataPath + "\\" + Path.GetFileName(file)) == false)
{
MessageBox.Show("The mod could not launch successfully!\n\nError: Packs failed to move", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
else
{
log += "File Found\r\n";
}
}
}
if (File.Exists(dataPath + "\\_GreatWar5_DB.pack")) // This pack should always be there if things have worked
{
Process game = Process.Start(gamePath);
}
else
{
MessageBox.Show("The mod could not launch successfully!\n\nError: Data pack missing", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
// There is code here waits for a minute until the game process is actually found, incase its slow starting up
game.WaitForExit();
RestorePacks(); // <- Method to put back the files after finishing
}
First of all, sorry that I was unable to give a proper title.
I got stuck with an idea that's been with me today almost the whole day after searching and searching and searching, till it came to a point that I decided to ask it on Stackoverflow!
So here's where I am stuck:
(I am making an auto-installer currently coded in C# and it is Dutch. It works really awesome but I just need one thing to finish my base. For example:
You have 'multiple' objects selected in a checklistbox, those are read from the checklistbox itself, they get trimmed and they get launched after that.
Now that's all working, I wanted to add a waiting method, for example we got:
Malwarebytes & CCleaner as installation 'example'.
Now when both are checked, and I click start, it starts both of the programs.
What I want to do is: to tell the program to start one program, do your thing, once its finished (closed) it should go to the next.
But... There is a problem, my programs are started in an array, so it basically works if there are multiple objects checked, than it will start all of the checked objects. And I really have no idea how to reach the same thing which is basically :
If there are multiple objects selected, start the object(s), do your thing(auto-clicking etc.),once its closed and confirmed its closed, move on to the next object and do the same thing until its been completed. I would like to make it work with a progressbar, but never really looked into a progress bar as they seem confusing.
I have a piece of code that finds the Process ID so maybe I can do something with that, but the Process ID is never the same on the applications that I start, so when they start in an array I got kinda of an issue.
Could someone help me please figuring out what & how to code / do this?
here's the code i use to make this work :
string pad = Application.StartupPath;
foreach (string checkedItem in checkedListBox1.CheckedItems)
{
if (checkedItem.Contains("."))
{
string str = checkedItem;
if (str.Contains("."))
{
int index = str.IndexOf('.');
string folder = str.Substring(0, index);
try
{
bool started = false;
var process = new Process();
process.StartInfo.FileName = pad + "/data/" + folder + "/" + checkedItem;
started = process.Start();
var processID = process.Id;
var processNAAM = process.ProcessName;
textBox1.Text += "Gevonden - ID: " + processID + " NAAM: " + processNAAM + Environment.NewLine;
textBox1.Text += DateTime.Now.ToString("HH:mm:ss", System.Globalization.DateTimeFormatInfo.InvariantInfo) + " - " + "Installatie Keuze wordt opgestart." + Environment.NewLine;
process.WaitForExit();
}
catch (Exception)
{
}
}
}
}
First of all, you can make the code simpler and shorter by using the CheckedListBox's CheckedItems property. Secondly, there's no point to all your copying of strings from one to another. Strings are immutable in .NET - they never change. You can keep just one copy and cut from there.
Next, you can use the methods in System.IO.Path to cut the filename without the extension, or to build a full path without worrying about having too many or too few "/"'s.
Third, for your original question - just call WaitForExit on your Process object to make it wait before moving on with the list of processes.
Thirdly
foreach (string checkedItem in checkedListBox1.CheckedItems)
{
if (checkedItem.Contains("."))
{
string baseName = Path.GetFileNameWithoutExtension(checkedItem);
string processPath = Path.Combine(pad, "data", baseName, checkedItem);
Process process = Process.Start(processPath);
process.WaitForExit();
}
}
After the line where you start the process (process.Start()), simply add the following:
process.WaitForExit()
This will pause the containing thread until the target process has exited.