I am using a global named mutex for file access synchronization between an ASP.NET application and a console application.
While running the ASP.NET application, the console application fails to acquire mutex - as expected. While running the console application, the ASP.NET application throws UnauthorizedAccessException: Access to the path 'Global\TheNameOfTheMutex' is denied.
I will try to catch the exception and treat it like it failed to acquire the mutex, but I want to know why is it behaving like this? The ASP.NET application runs as expected if it is accessed from two different browsers and the console applications also runs as expected when running multiple instances.
Update: on Windows XP the exception is also thrown when the ASP.NET application is running and I try to start the console application.
The code used for synchronization is in a common assembly:
using (Mutex m = new Mutex(false, "Global\\TheNameOfTheMutex")) // exception thrown
{
try
{
lock = m.WaitOne(0, false);
}
catch (AbandonedMutexException)
{
// ...
}
if(lock)
{
// ...
m.ReleaseMutex();
}
}
Environment: Windows Server 2008, IIS 7, ASP.NET 2.0
do you have the right user set up to access to the resources? using
MutexSecurity and MutexAccessRule ?
try looking at this on MSDN http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.mutexsecurity.aspx
and http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.mutexaccessrule.aspx
p.s. I am awaiting a Jon Skeet answer to show my ignorance in the matter...=>
Here the sample from How to determine if a previous instance of my application is running? (see the romkyns' answer)
var sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
var mutexsecurity = new MutexSecurity();
mutexsecurity.AddAccessRule(new MutexAccessRule(sid, MutexRights.FullControl, AccessControlType.Allow));
mutexsecurity.AddAccessRule(new MutexAccessRule(sid, MutexRights.ChangePermissions, AccessControlType.Deny));
mutexsecurity.AddAccessRule(new MutexAccessRule(sid, MutexRights.Delete, AccessControlType.Deny));
_mutex = new Mutex(false, "Global\\YourAppName-{add-your-random-chars}", out created, mutexsecurity);
Related
I have an application that runs a background thread that opens a WinSCP session which is used to do stuff, like this:
new Thread(() => {
//do stuff
SessionOptions options = new SessionOptions
{
//options
};
using(Session session = new Session())
{
bool success = false;
foreach (var ip in IPs)
{
options.HostName = ip.Value;
try
{
session.Open(options);
success = true;
break;
}
catch (Exception)
{
}
}
if(success)
{
CommandExecutionResult result = session.ExecuteCommand(*some command*);
result.Check();
someVariable = result.Output;
}
}
//do stuff
})
{
IsBackground = true
}.Start();
Now I noticed that if I close the app while in using, the thread does indeed stop but the WinSCP session remains opened (maybe because the thread is aborted?) and if I repeat the process I end up, of course, with more WinSCP sessions. How can I close the specific session I am opening in the application?
Edited: Added more of what happens in the using block.
You can use Session.Dispose method which kills the underlying process.
Refer this documentation of WinSCP : https://winscp.net/eng/docs/library_session_dispose
Also note the text from this article:
If session was opened, closes it, terminates underlying WinSCP process, deletes XML log file and disposes object.
As opposed to Session.Close, it’s not possible to reuse the object afterwards.
I've put your code to a C# console application and added Thread.Sleep to both main and background thread. If I run the application (tested on Windows 7 and 10), and close it, or even if I abruptly kill it from a task manager, WinSCP subprocess is cleanly gone.
This was expected, as the subprocess runs in the same Windows job as the .NET code. So it's an operating system that takes care of cleaning WinSCP subprocess, no matter what the .NET code does. So there's something weird going on in your application.
Anyway, if you want to make sure that WinSCP session is aborted, just call Session.Abort from the main thread, when you are closing the application.
My Solution, on the Form_FormClosing event handler, just put these lines:
foreach (var process in Process.GetProcessesByName("WinSCP"))
{
process.Kill();
}
(Process.GetCurrentProcess()).Kill();
My C# program needs to launch Office Outlook and get the current "running outlook application".
In order to do that I've implemented the following simple program (so if you want you can test it simply):
using Outlook = Microsoft.Office.Interop.Outlook;
using System.Runtime.InteropServices;
static void Main(string[] args)
{
Outlook.Application outlookObj = null;
if (Process.GetProcessesByName("OUTLOOK").Count().Equals(0))
{
Process.Start("outlook.exe"); // MY PROGRAM STOPS HERE
}
var process = Process.GetProcessesByName("OUTLOOK").First();
while (!process.HasExited)
{
try
{
outlookObj = (Outlook.Application)Marshal.GetActiveObject("Outlook.Application");
break;
}
catch
{
outlookObj = null;
}
System.Threading.Thread.Sleep(10);
}
string result = (outlookObj== null)? "DOES NOT WORK" : "OK";
Console.WriteLine(result);
Console.ReadLine();
}
My problem is that once Office Outlook starts running then my C# console application does not continue its job. After the Process.Start("outlook.exe"); instruction is executed then I must click on Visual Studio GUI in order to restart the console application and finally read "OK" on my console application.
How can I solve my problem?
Microsoft wrote a example about how to log into a outlook instance. Although this is directly what you asked for in your question, the example contains how to start a new outlook application in the intended way
application = new Outlook.Application();
as a side note: in your example you use the following code:
while (!process.HasExited)
{
try
{
outlookObj = (Outlook.Application)Marshal.GetActiveObject("Outlook.Application");
break;
}
catch
{
outlookObj = null;
}
System.Threading.Thread.Sleep(10);
}
This is bad practice in your main thread as your applying 'busy waiting' by using the thread.sleep. This means you will 1. use CPU power while your application is doing nothing. 2. make your GUI completely unresponsive and if the thread.sleep is called to many times Windows will suggest to shut the process down (the whole screen gets white and eventually you get a popup asking you if you want to wait or just shut it down). There are plenty of ways in the .net framework to prevent both of these issues (for example using a waithandle, background worker or locking)
There is no need to run the a new process using the Process.Start method. Instead, you can add the Outlook reference to your C# project and create a new instance of the Application class. See C# app automates Outlook (CSAutomateOutlook) sample project for more information.
Also you may find the following articles helpful:
How to automate Outlook and Word by using Visual C# .NET to create a pre-populated e-mail message that can be edited
How to use Visual C# to automate a running instance of an Office program
This works:
public static void StartOutlookIfNotRunning()
{
string OutlookFilepath = #"C:\Program Files (x86)\Microsoft Office\Office12\OUTLOOK.EXE";
if (Process.GetProcessesByName("OUTLOOK").Count() > 0) return;
Process process = new Process();
process.StartInfo = new ProcessStartInfo(OutlookFilepath);
process.Start();
}
Use the Process.Start overload that takes a ProcessStartInfo instead so you can set UseShellExecute
var startInfo = new ProcessStartInfo()
{
FileName = "Outlook.exe",
UseShellExecute = true
};
Process.Start(startInfo);
MAYBE the process need some time to start.
Try this:
if (Process.GetProcessesByName("OUTLOOK").Count().Equals(0))
{
Process.Start("outlook.exe"); // MY PROGRAM STOPS HERE
}
while ((Process.GetProcessesByName("OUTLOOK").Count().Equals(0));
var process = Process.GetProcessesByName("OUTLOOK").First();
This should cause starting process and waiting until it is avaible before trying to catch it...
In my asp.net application, iam using windows forms.dll to use some of the windows controls by creating a thread.This works fine in my system but is giving a session timeout when hosted on IIS.
Creating a thread gives me session time out on IIS.
How do i create threads that can work fine on IIS?
Below is the code where iam created the thread.
public string[] DisplayFileDialog()
{
string[] result = null;
try
{
Thread objThread = new Thread(state =>{
result = FnOpenFileDialog();
// TODO: do something with the returned result
});
objThread.IsBackground = false;
objThread.SetApartmentState(ApartmentState.STA);
objThread.Start();
objThread.Join();
return result;
}
catch (Exception ex)
{
return result;
}
protected string[] FnOpenFileDialog()
{
IntPtr hdlr = GetForegroundWindow();
WindowWrapper Mockwindow = new WindowWrapper(hdlr);
OpenFileDialog fDialog = new OpenFileDialog();
fDialog.Title = "Select Files";
fDialog.Multiselect = true;
fDialog.CheckFileExists = true;
fDialog.CheckPathExists = true;
System.Windows.Forms.DialogResult dr = fDialog.ShowDialog(Mockwindow);
string[] filenames = fDialog.FileNames;
return filenames;
}
Thanks in advance.
Your code is executed server side, which is why your stalled by a time out response. Your main thread waits (objThread.Join) for the response of a dialog box opened on the server as you can't see it on the client side you never get a response.
If you want to open the dialog file on the client side you can do it in a similar way as was ActiveX objects.
You can find a msdn tutorial of how to do it at the following address but it only work in IE:
http://msdn.microsoft.com/fr-fr/magazine/cc301932(en-us).aspx
If I'm understanding your question correctly, the answer is simply: You can't do that.
Windows forms controls don't work in a browser. It works on your machine because the browser window is local, so the thread can attach to it and use it as a parent.
The IIS process doesn't have a window, it only serves up text, images, and video files. You're essentially asking an IIS thread, running on some machine in a server room somewhere else, to connect to a browser's window on someone else's machine, and then start displaying Windows Forms controls on it.
What if they are on a Linux box, or a Mac?
ASP.NET was created to solve this problem of creating interactive forms for IIS.
Hope this helps.
I have a webservice with a couple of methods that attempt to run or message another .EXE on the system to do a specific task.
Either we can start the .EXE process with certain parameters or send it a WndProc message to make it do the desired operation. This works fine locally on my system calling the exe with parameters in cmd or sending a WndProc message from the webservice when debugging it in Visual Studio.
None of this works over a real environment however. I had the run .Exe with parameters method (DoSomething) write the exception to a file:
System.ComponentModel.Win32Exception (0x80004005): No Access
at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at Someprogram.ProgramService.DoSomething(String text)
The other method for wndproc sendmessage I wrapped in a try/catch as well but no exception thrown. It actually locates the process though as I had it print a file:
public static void SendMessageToSomeProgram(string message) {
Process[] processes = Process.GetProcessesByName("SomeProgram");
if (processes.Length >= 1) {
//iterate through all running target applications
foreach (Process p in processes) {
//test write if process found
TextWriter tw = new StreamWriter(#"c:\wndprocfile.txt"); //this file is printed
tw.WriteLine(DateTime.Now.ToString());
tw.Close();
//do stuff
try {
byte[] sarr = System.Text.Encoding.Default.GetBytes(message);
int len = sarr.Length;
COPYDATASTRUCT cds;
cds.dwData = (IntPtr)100;
cds.lpData = message;
cds.cbData = len + 1;
SendMessage(p.MainWindowHandle, WM_COPYDATA, 0, ref cds);
} catch (Exception ex) {
TextWriter tw2 = new StreamWriter(#"c:\wndProc_errorfile.txt"); //not printed
tw2.WriteLine(DateTime.Now.ToString() + "Exception: " + ex.ToString());
tw2.Close();
}
}
}
Now I see why it's nice to have security like this in place but is there an easy way around this? Maybe just some settings in IIS?
UPDATED INFO: The server is running IIS 5.1 so no Application Pool feature.
The service inside IIS runs as the user connected to the app pool it's running as. So try to change the user of the app pool to a user that have access to start the application you want to start up.
To do this, check the applications app pool and then go to the app pool and change the user. To change the user you have to turn pass-through authentication off.
I have two windows application, one is a windows service which create EventWaitHandle and wait for it. Second application is a windows gui which open it by calling EventWaitHandle.OpenExisting() and try to Set the event. But I am getting an exception in OpenExisting. The Exception is "Access to the path is denied".
windows Service code
EventWaitHandle wh = new EventWaitHandle(false, EventResetMode.AutoReset, "MyEventName");
wh.WaitOne();
Windows GUI code
try
{
EventWaitHandle wh = EventWaitHandle.OpenExisting("MyEventName");
wh.Set();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
I tried the same code with two sample console application, it was working fine.
You need to use the version of the EventWaitHandle constructor that takes an EventWaitHandleSecurity instance. For example, the following code should work (it's not tested, but hopefully will get you started):
// create a rule that allows anybody in the "Users" group to synchronise with us
var users = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null);
var rule = new EventWaitHandleAccessRule(users, EventWaitHandleRights.Synchronize | EventWaitHandleRights.Modify,
AccessControlType.Allow);
var security = new EventWaitHandleSecurity();
security.AddAccessRule(rule);
bool created;
var wh = new EventWaitHandle(false, EventResetMode.AutoReset, "MyEventName", out created, security);
...
Also, if you're running on Vista or later, you need to create the event in the global namespace (that is, prefix the name with "Global\"). You'd also have to do this on Windows XP if you use the "Fast User Switching" feature.
This might be caused by the service process running at an elevated privilege level, but the GUI process is not. If you put the same code into two console apps, they'll both be running at user level and won't have any trouble accessing each other's named shared objects.
Try running the GUI app with the "Run as administrator" flag from the Windows start menu. If that solves the issue, you need to read up on how to request elevation within your code. (I haven't done that)