I have multiple processes that running at the same time of my C# program and all of this processes have the same name.
I am trying to give specific name to each process running of this program using a function.
You're looking to do some sort of lookup, a Dictionary is a good tool for that.
Dictionary<string, Process> processNames = new();
Add and remove entries just like any other Dictionary.
Process p = ...
processNames.Add("myprocess", p);
then look it up by it's name
Process p2 = processNames["myprocess"];
You can populate p with Process.Start, or any other "GetProcess*" static methods in the Process class (Process.GetProcessById, Process.GetProcessesByName, etc).
You will want to rename your project in order to change the process name. Process names are just the names of the executable file being run. Whenever you build, the main resulting file will be the same as the project name. Take a look:
One thing you could do is to track processes that you created using a hash set or dictionary if you are doing anything that involves requiring the Process object of that specific process.
Related
Directory.CreateDirectory creates a folder if it doesn't already exist, otherwise it just returns the DirectoryInfo for the already-existing folder.
But I want to make sure I create a new sub-folder every time a process is run (run1, run2, run3, etc). And multiple people may be running that process at once. So I can't do
if (!Directory.exists("run77"){CreateDirectory("run77");}
Because that has a race condition - someone else may create the folder in between those two calls.
Is there any way to ensure that I definitely get the next unused folder name?
The obvious answer: Don't use sequential IDs in this case. Use GUIDs instead. For things happening in multiple instances at once I rarely found sequential numbers helpful in that there isn't really an inherent sequence.
The other option would be to drop down to the Windows API where you can just try and re-try creating directories with increasing sequence numbers until the call succeeds, at which point you found your directory to work with.
This goes way beyond merely creating directories. You have multiple processes (on multiple machines even, maybe) that want to obtain a sequentially named resources, for themselves only.
If you definitely want to do this, you will have to synchronize it yourself. So either:
If the processes run on the same machine, use a machine-wide lock (e.g. Mutex) that synchronizes the directory creation code.
Create an out-of-process central authority (other than the filesystem itself) which provides the next number upon each successive, synchronized call.
Create a sentinel file / lock file containing a process-specific value, during the presence of which no other processes will try to create a directory, and remove it after creating the directory.
Apply filesystem permissions in such a way, that attempting to write into the given directory raises an error (if CreateDirectory() doesn't throw already). Then you'll have to assume that any permission error means a race condition occurred, and try to create the next directory.
All of those are brittle solutions.
One possible solution is to introduce a simple synchronization using exclusively opened file.
Here is possible implementation (as not fully thought code):
FileStream lock = null;
try
{
// someUniequeLockFileName - should be the same for all processes and unlikely to match real name in that folder
lock = File.Open(Path.Combine(currentFolder, someUniqueLockFileName), FileMode.Create, FileAccess.ReadWrite, FileShare.None);
... // you successfully obtain lock, can create subfolders
}
catch { }
finally
{
lock.Close();
}
One way is using a mutex which is an expensive call. However like most said if possible use sequential Ids instead. Here is an example using a mutex:
Mutex m = null
try
{
m = new Mutex(false, "CreateDirectoryMutex");
m.WaitOne();
if (!Directory.exists("run77"))
CreateDirectory("run77");
}
finally
{
if(m != null)
m.ReleaseMutex();
}
Ok, so let me take a simple example of what I'm trying to describe. This is probably a very "n00b" question, and yet I've ready plenty of programming books and they never have examples like this.
Let's say I have a program like
public class Program
{
private static List<string> _input = new List<string>();
public static void Main()
{
string line;
while((line = Console.ReadLine()) != null)
{
Program._input.Add(line);
}
return 0;
}
}
except want to modify it so that the next time I launch, the lines I added to input the previous time I ran the program are still there. Is there a way to do this (without writing the list to a text file or something like that)? If so, how?
Once your application is closed, everything stored in variables is lost when your application is destroyed.
The only way to persist data is to store it somewhere outside of your program. The most common are files or databases. In your case, you're just storing lines of text so I'd probably go with a file.
You can easily write to the file when the application is closing and then read from the file when the application starts.
If you want save all value of your class you can use a Serialization
you can have some example here : Examples of XML Serialization
But in all case you need to write in a file you can keep it in RAM.
Whenever you close your program, Windows frees memory. Only files are preserved.
Writing file is not evil but just one simple statement.
File.WriteAllLines("lines.txt", _input);
Reading file is also easy.
_input.AddRange(File.ReadAllLines("lines.txt"));
When application is closed on operating system, it is taken out from the computer memory...so you have to save its state to some kind of file or storage devices... as far as I concern that is the only way
I know Process class have many properties relative to memory like (Private)WorkingSet(64), PrivateMemorySize64 (byte unit),... I tried to get their value and divide to (1024*1024) to get the MB number of them. It seem like none of them have the value like the Task Manager memory column. Is there a property which has the TM's value?
No, there is no property on Process from which you can get the Task Manager Private Working Set but...
You can retrieve the same value from a performance counter from the original answer there:
using System;
using System.Diagnostics;
class Program {
static void Main(string[] args) {
string prcName = Process.GetCurrentProcess().ProcessName;
var counter = new PerformanceCounter("Process", "Working Set - Private", prcName);
Console.WriteLine("{0}K", counter.RawValue / 1024);
Console.ReadLine();
}
}
As you may not know that the values available in Process do not represent the same thing. The Private Working Set is related to only a subset of memory measured by the PrivateMemorySize64. See the answer there.
In fact, it really depends on what you're trying to achieve.
If you want to have the same value as in Task Manager, read the performance counter.
If you want to measure the memory used by your application, you should used the Process properties. For example, if you want to known the memory that cannot be shared with other processes, use PrivateMemorySize64.
As the side note, all "non-64" memory related properties on Process are obsolete. You should also definitely read the Process documentation.
For reference Private Working Set is related to what is shown in the column of the same for Task Manager or Process Explorer.
You can refer on Windows documentation or a related question to get the meaning of each task manager column.
We have a list of the complete paths where we want to copy some files to, sort of like this
C:\temp\sub1\file1A
C:\temp\sub1\file1B
C:\temp\sub2\file2A
C:\temp\sub3\file3A
C:\temp\sub3\file3B
C:\temp\sub3\file3C
etc....
There is some code that does this
for each file in the file list
if (!Directory.Exists(dirName)
{
Directory.CreateDirectory(dirName)
}
And we can see from the logs that all the sub folders get created, and only 1 attempt is made for each sub folder - so the Directory.Exists is returning true after the first file in each sub folder has been through the above loop.
Then the code does something like
var fileDownloadActions = new List<Action>();
// populated the list with GetFile(requiredInfo)
Parallel.Invoke(new ParallelOptions {MaxDegreeOfParallelism = 10},
fileDownloadActions.ToArray());
And now here is the odd bit - most of the time this works just fine, however sometimes it fails with multiple DirectoryNotFoundExceptions - claiming it can't find the directories that have just been created!
Sometime it can't find any of the created sub folders, sometimes it works for some but not others.
Current working theory is that although the thread that created the folders thinks they are created (and the checks for Directory.Exists are returning true as no matter how many files we have in the folder we only try to create each folder once) they haven't been actually properly fully created on the OS and when we try to access them from the other threads it goes Bang!
Ever seen / heard of something like this before?
Is our working theory correct and if so what is the best way to fix this? (I'd rather not just put in a sleep!)
Could this be explained by access to modified closure?
I guess it depends on what your loop looks like, but from what I've seen then if you're storing the delegates for execution later then there is the possibility that you're not getting the dirName value that you may be expecting.
Have a look at http://www.yoda.arachsys.com/csharp/csharp2/delegates.html under the Captured variables section.
I'm working with C#, I need to obtain a specific instance of excel by it's process ID; I get the Process ID of the instance that I need from another application but I don't know what else to do, I don't know how can I get a running instance of excel given his process ID.
I have researched a lot on the web, but I have only see examples of using Marshal.GetActiveObject(...) or Marshal.BindToMoniker(...), which I can't use since the first one returns the first Excel instance registered in the ROT and not precisely the one that I need, and the second one requires that you save the excel file before trying to get the instance.
Also, if I where able to get the CLSID of the excel instance that I need, using the process ID, then I may be able to call
GetActiveObject(ref _guid, _ptr, out objApp);
that ultimately will return the excel instance that I need.
Once you identify the process via the process id, you can get the Process.MainWindowHandle and then use that along with the AccessibleObjectFromWindow API to get access to the Excel object model for that process.
The article Getting the Application Object in a Shimmed Automation Add-in by Andrew Whitechapel describes this technique in detail, along with sample code.
The key code in that article for you begins at the line:
int hwnd = (int)Process.GetCurrentProcess().MainWindowHandle
Which in your case might look more like:
int excelId = 1234; // Change as appropriate!
int hwnd = (int)Process.GetProcessById(excelId).MainWindowHandle
where the 'excelId' is the process id number that you are looking for. Otherwise, the code should be essentially the same as given in the article. (Ignore the fact that his code is written for an add-in; that aspect won't affect your needs here, so just ignore it.)
If you do not have the process id, then you you would want to use Process.GetProcessesByName, whereby you could enumerate each one and grab control of each Excel instance with access to the object model, as needed.
Hope this helps,
Mike
The ROT entries are not tagged with a CLSID. The ROT returns a DWORD from Register, which is used as a identifier for Unregister.
I've run into this problem before and the only way I've solved it is to have some kind of add-in loaded into each Excel that you can communicate directly with.
using System.Diagnostics;
var eProcess = from p in Process.GetProcessesByName("EXCEL")
where p.Id == 3700 //whatever Id you have...
select p;
foreach (var process in eProcess)
process.Kill();
This gets all processes named "EXCEL" where the Process Id equals a specific value.