I am trying to restrict my application from having multiple instances at machine level, i.e. A computer will have multiple users logging into it and this application is required to have only one instance for performance reasons. So if User A starts the application, User B should simply get a message that this application is already running on User A's account. Now before you start schooling me on processes, I already tried that, and it doesn't work because for my application to check if a similar process is running, it needs to start the process(the application), in this case, the application will never start.
I am using this to restrict multiple instances, and it works great but it only works at user level.
Microsoft.VisualBasic.ApplicationServices
public class SingleInstanceApplication : WindowsFormsApplicationBase
{
private SingleInstanceApplication()
{
base.IsSingleInstance = true;
}
public static void Run(Form f, StartupNextInstanceEventHandler startupHandler)
{
SingleInstanceApplication app = new SingleInstanceApplication();
app.MainForm = f;
app.StartupNextInstance += startupHandler;
app.Run(Environment.GetCommandLineArgs());
}
}
Any help or advice will be much appreciated...
How are users accessing the application? You could create batch script that checks the process, if one is running then the script simply won't start the application. Not sure if you want to solve this programatically inside your application or through other means. But if you don't want a second instance of said application running your best bet would be outside of your application such as a batch script.
There is also this: cross-user C# mutex.
Where I work we have flags set to specific SQL tables that prevent multiple users from editing records at the same time. Or you could create a hidden lock file when a user logs in and than remove said file once the user logs out.
Related
I am not able to detect this Logon event in Windows.
Here is my code:
namespace ConsoleApplication2
{
public class MyService: ServiceBase
{
public MyService()
{
CanPauseAndContinue = true;
CanHandleSessionChangeEvent = true;
}
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
base.OnSessionChange(changeDescription);
}
}
class Program
{
static void Main(string[] args)
{
MyService tpl = new MyService();
Thread t = new Thread(delegate()
{
while (true) { }
});
t.Start();
}
}
}
How do I test run this app and then remote desktop into my laptop? I can see the event generated in Windows EventViewer, but my OnSessionChange is never called (I added a breakpoint inside).
Is my code wrong or is the way I am testing wrong?
Normally multiple concurrent remote desktop sessions are not allowed on any of Windows desktop systems. So to use RDP to login as a different user then I assume that you have hacked this, or are using windows server (which rules out XP!).
Regardless, each user logged into the system will therefore have their own applications running and each set of applications are unique to that user. So App1 could be run independently by each user.
That means that your console application cannot detect the other user that is logged on.
To do this you must use a Windows Service. This runs in the background and can detect and work for multiple users and also detect login and logout. See this SO link
This is the purpose of inheriting MyService from ServiceBase. If you are not running the application as a service, then you are not running it correctly!
You need to first install your application as a service and then run it like a service.
You say that you don't think your application can run as a service. I'm not sure why, but if this is the case then you would have to instead look at creating some kind of script to run your application upon start-up/login.
This way, every time somebody logs in then your application would run. This might anyway be simpler for you.
I am trying to launch a process from a web page's back-end code/app pool. This process will launch an App that i built myself.
For some reason, the process only works / runs when i start it from VS2013... it never works when i launch it from IIS(7.5) itself.
I am on a Windows 7 machine (both IIS host, and App location), and I've setup my web site to only be accessible via internal network.
Here's the code, followed by the config / attempts to fix the issue:
protected void btn_DoIt_Click(object sender, EventArgs e)
{
string file_text = this.txt_Urls.Text;
if (!String.IsNullOrWhiteSpace(file_text))
File.WriteAllText(ConfigurationManager.AppSettings["filePath"], file_text);
ProcessStartInfo inf = new ProcessStartInfo();
SecureString ss = GetSecureString("SomePassword");
inf.FileName = #"........\bin\Release\SomeExecutable.exe";
inf.Arguments = ConfigurationManager.AppSettings["filePath"];
inf.UserName = "SomeUserName";
inf.Password = ss;
inf.UseShellExecute = false;
//launch desktop app, but don't close it in case we want to see the results!
try
{
Process.Start(inf);
}
catch(Exception ex)
{
this.txt_Urls.Text = ex.Message;
}
this.txt_Urls.Enabled = false;
this.btn_DoIt.Enabled = false;
this.txt_Urls.Text = "Entries received and process started. Check local machine for status update, or use refresh below.";
}
Here are the things I've tried to resolve the issue:
Made sure the executing assembly was built with AnyCPU instead of
x86
Ensured that the AppPool that runs the app, also runs under the same account (SomeUsername) as the ProcessStartInfo specified.
Ensured that the specific user account has full access to the executable's folder.
Ensured that IIS_USR has full access to the executable's folder.
Restarted both the app pool and IIS itself many times over implementing these fixes
I am now at a loss as to why this simply will not launch the app... when i first looked into the event log, i saw that the app would die immediately with code 1000:KERNELBASE.dll, which got me on the AnyCPU config instead of X86 fix... that fixed the event log entries but the app still doesn't start (nothing comes up in task manager), and i get no errors in the event log...
if someone could help me fix this problem i would really appreciate it. This would allow me to perform specific tasks on my main computer from any device on my network (phone, tablet, laptop, etc etc) without having to be in front of my main PC...
UPDATE
The comment to my OP, and ultimate answer from #Bradley Uffner actually nailed the problem on the head: My "app" is actually a desktop application with a UI, and in order to run that application, IIS would need to be able to get access to the desktop and the UI, just like if it were a person sitting down in front of the PC. This of course is not the case since IIS is running only as a service account and it makes sense that it shouldn't be launching UI programs in the background. Also see his answer for one way of getting around this.
Your best bet might be to try writing this as 2 parts. A web site that posts commands to a text file (or database, or some other persistent storage), and a desktop application that periodically polls that file (database, etc) for changes and executes those commands. You could write out the entire command line, including exe path command arguments, and switches.
This is the only way I can really think of to allow a service application like IIS to execute applications that require a desktop context with a logged in user.
You should assign a technical user with enough high priviliges to the running application pool. By default the application pool is running with ApplicationPoolIdentity identy which has a very low priviliges.
The steps of my application are:
Go to the setting page first, and the setting page will register the Registry Log (as 'regedit' in command line) in the background (people may seldom go to the setting page).
When users clicks the URL in a web page, it will trigger the registry and open my application.
The appplication reads the parameter that it gets and does things depending on the parameter value.
User may click on different links to send different parameters to my application
That is, if the application is not opened, it should be launched it and reads the parameter. If the application is already opened, it should just read the parameter.
The problem is: how could find out the different situations of my application - whether it is opened or not - and then use the parameter correctly?
The part of registry( in setting page):
Registry.ClassesRoot.CreateSubKey("MyApp").SetValue("", "URL:MyApp Protocol");
Registry.ClassesRoot.CreateSubKey("MyApp").SetValue("URL Protocol", "");
Registry.ClassesRoot.CreateSubKey("MyApp\\DefaultIcon").SetValue("", "\"" + Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + "\\" + "MyApp.exe" + ",1\"");
Registry.ClassesRoot.CreateSubKey("MyApp\\shell\\open\\command").SetValue("", "\"" + Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + "\\" + "MyApp.exe" + "\" \"%1\"");
%1 is the parameter I will get( from url to my application).
And the web link may be:
Call for Function 1
Call for Function 2
So there are many links in the web page to call same application.
But I cannot let my application be opened every time (that is, there should be only one application opened, and other clicks on links will only send parameters to the app).
I know how to find out whether the application is opened or not by the code:
Mutex mul = null;
bool is_createdNew;
try
{
string mutexName = Process.GetCurrentProcess().MainModule.FileName.Replace(Path.DirectorySeparatorChar, '_');
mul = new Mutex(true, "Global\\" + mutexName, out is_createdNew);
if (!is_createdNew)
{
// application be opened already, I close the application originally
Environment.Exit(Environment.ExitCode);
}
else
{
// the application is first run, open my MainWindow
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
}
Is it possible to send the parameter as a method of registry when the application is opened?
I even think about reading registry by Registry.GetValue, when my application starts up,
to use timer to read registry value per second......
This is my first time face this situation of user's request,
hope someone can give me any direction!
Thanks in advance.
When you find out that another instance of your application is already running (which you do in your code above using Mutex), you can programatically pass the parameter (of the second app instance) to the first, already running app instance and then just close the second app instance. This code for passing parameter to the first app instance would then be just before Environment.Exit(Environment.ExitCode);
(Presuming that your app is relatively small and does not loads lots of libraries on startup - in that case it would be better to create a separate small launcher app)
The problem is, how to pass the parameter between two independent processes - two instances of your app.exe. There are of course several options, look here:
Send/Receive message To/From two running application
I would use FileWatcher or Memory mapped file as it is specified in that answer.
The solution with timer and changing registry values is not good (registry operations require admin access, registry operations are not so fast etc.).
Here is a nice library that shows, how to pass parameters between 2 processes using Memory mapped file.
http://code.msdn.microsoft.com/windowsdesktop/Inter-process-communication-e96e94e7
I found another way to solve my problem,
just simply add 'static' before Mutex.
See the detail: C# static
I am working with an ASP.NET 2.0 application (created by my predecessor). Users log into it with AD credentials, and everything done within the app uses those credentials. I modified a page in the application that has nothing to do with event logging, and now my users get this error:
Here is the relevant code from the global.asax file:
public void LogException(Exception e)
{
string exceptionXml = RenderException(e, true);
_EventLog.WriteEntry("Exception of type " + e.GetType().FullName + " occurred.\n\n" + exceptionXml, EventLogEntryType.Error);
}
RenderException() just puts the exception XML into a flat string, removing white spaces.
I am at a loss on how to get rid of this error. I have tried re-publishing the website with an iisreset. I have tried restarting the web server (2k3 w/ iis 6.0), flushing the app pool. I have also tried modifying the permissions in the registry for the top-level event log key. Can anyone tell me how to get rid of this error? It does not happen on my computer, so it is very hard to replicate. Also, the browser used does not seem to matter. The previous version will work for the same persons getting this error.
By default the ASPNET user cannot access the existing event logs categories.
If you do want to write messages to the event log you must create your own category
Launch RegEdit
Navigate to HKEY_LOCAL_MACHINE\SYSTEM\
CurrentControlSet\Services\EventLog\
From the menu, select Edit->Permissions
Click the Add button and write ASPNET. (if ASP.NET is running under a different user id, use that id instead)
Click OK.
Select the newly added user from the list (ASP.NET Machine User by default).
Click on Full Control in the Allow column.
Click OK.
You can also check that the user, under which the applications is running, belongs to the correct group, for example IIS_WPG
http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/3648346f-e4f5-474b-86c7-5a86e85fa1ff.mspx?mfr=true
You appear to be calling an instance method of the EventLog class on the _EventLog instance:
_EvengLog.WriteEvent(message, ...);
But according to MSDN documentation for the EventLog class:
Any instance members are not guaranteed to be thread safe.
I suspect this is a likely source of your problem, and would recommend you use one of the static methods (which are guaranteed to be thread safe):
System.Diagnostics.EventLog.WriteEvent(source, message, ...);
Alternatively you could implement your own synchronization, but I wouldn't recommend this.
I have a simple application written in C# and .Net 2.0 that displays several PowerPoint 2003 files in a loop. (It is going to be used for a information board in our cafeteria) The application works fine on my development machine but when I deploy it to another machine the events I have registered for SlideShowNextSlide and PresentationClose are never fired. I have tried registering the events with this method.
private void InitPPT()
{
app.SlideShowNextSlide += new Microsoft.Office.Interop.PowerPoint.EApplication_SlideShowNextSlideEventHandler(app_SlideShowNextSlide);
app.PresentationClose += new Microsoft.Office.Interop.PowerPoint.EApplication_PresentationCloseEventHandler(app_PresentationClose);
app.SlideShowEnd += new Microsoft.Office.Interop.PowerPoint.EApplication_SlideShowEndEventHandler(app_PresentationClose);
}
And with this method that I found here:
private void InitPPT()
{
IConnectionPointContainer oConnPointContainer = (IConnectionPointContainer)app;
Guid guid = typeof(Microsoft.Office.Interop.PowerPoint.EApplication).GUID;
oConnPointContainer.FindConnectionPoint(ref guid, out m_oConnectionPoint);
m_oConnectionPoint.Advise(this, out m_Cookie);
}
Do I need to register some dll's on the client machine or am I missing something.
I think this was due to the fact that I was trying to run my application from a local user account but impersonate a domain account so I could access network drives. I have changed my application so it only impersonates the domain account while preforming network operations and not at application startup.