I'm researching on how to add a shortcut in the windows context menu to my application. I came across this article and I tried it out. This is the code it uses to create a key in the registry.
private void btnAddMenu_Click(object sender, System.EventArgs e)
{
RegistryKey regmenu = null;
RegistryKey regcmd = null;
try
{
regmenu = Registry.ClassesRoot.CreateSubKey(MenuName);
if(regmenu != null)
regmenu.SetValue("",this.txtName.Text);
regcmd = Registry.ClassesRoot.CreateSubKey(Command);
if(regcmd != null)
regcmd.SetValue("",this.txtPath.Text);
}
catch(Exception ex)
{
MessageBox.Show(this,ex.ToString());
}
finally
{
if(regmenu != null)
regmenu.Close();
if(regcmd != null)
regcmd.Close();
}
}
The problem is if I run it through my Administrator account, it works fine. But when I do it through a different account which doesn't have admin privileges, it throws this exception.
system.unauthorizedaccessexception access to the registry key is denied
Now if I were to use this code in one of my own applications to create a shortcut in the context menu, I can't be sure every user would run it as the Administrator, right?
Is there any way in C# to escalate the user privileges when creating the registry key?
If you know any other way to add an item to the windows context menu, I'd be interested in them too.
Thank you.
You cannot escalate permissions as such (at least I'd like to know about it, but doesn't seem possible as yet), but you need to run / start your app (embed into manifest) elevated.
Please take a look at these entries...
How do I force my .NET application to run as administrator?
Elevating process privilege programatically?
I'd suggest what comments said, running that from the setup. Or let your app run as admin from the start, or possibly jump start an elevated process from your app - when needed (e.g. running another exe of yours that has its manifest properly).
You could escalate your permissions much the same way installers do it. It will require user interaction, as that's the way the OS is designed (and rightly so) - you can't go around it.
Related
my installer run as administrator, but on complete i want the exe to run as current user.
i am using nsis and already tried UAC
!insertmacro UAC_AsUser_ExecShell "" "some.exe" "" "" ""
but still it run as administrator.
tried to use task scheduler
string path = System.Reflection.Assembly.GetExecutingAssembly().Location;
td.Actions.Add(new ExecAction("" + path + "", "", null));
td.Settings.DisallowStartIfOnBatteries = false;
td.Settings.AllowHardTerminate = false;
td.Settings.StopIfGoingOnBatteries = false;
td.Settings.ExecutionTimeLimit = System.TimeSpan.Zero;
td.Settings.IdleSettings.StopOnIdleEnd = false;
// Register the task in the root folder
ts.RootFolder.RegisterTaskDefinition("task", td);
but the task also goto administrator and i cant get it to current user.
any ideas ?
My personal recommendation is that you just remove the option to run your application at the end of your installer. The user can just start it from the start menu, it should be highlighted as new and everything.
As you probably know, UAC really changed how common it is for applications to run as a different user than the "logged in" user. You just have to deal with the fact that UAC exists and decide if you feel it is worth the amount of time required to work around it and possible bugs and issues that might arise.
There are at least 4 ways to run something as the "current user", all of them have issues and can fail or end up running as the "wrong" non-admin user:
Use the token of the (hopefully) non-elevated parent, this is what the NSIS UAC plugin does.
Use the Windows Task Scheduler. This was a recommended practice in the early Vista days but I believe Microsoft has moved away from this method.
Use a shell COM object in the Explorer process that hosts the taskbar to call ShellExecute for you. The StdUtils plugin provides a ExecShellAsUser method that does this.
Use a Windows NT service. Because it runs as SYSTEM it can get the token handle of a user in any session.
If you decide that you still want to attempt to do this then you need to decide on your definition of current user before you choose a method.
Is it the user that logged in on the welcome screen? Is it the user the Explorer shell (Taskbar etc) is running as? Is it the parent process of your setup process? You should also keep in mind that runas.exe exists and a user might try to run something as a particular user for a reason...
I am developing a C# windows service + UI application.
I have a problem that if during the uninstall process the user is trying to launch the UI then the uninstall gets corrupted and stuck (because the ui holds handles to some files and prevents them from getting deleted).
What is the best way to handle this situation? I thought that maybe I should strict the access to the .exe when I am starting the uninstall process, so the user won't be able to launch it.
But I was wondering if there is a BKM of how to do that
EDIT
The application is already installed on customers' machines, So I can't make any changes to the application itself.
I have an upgrade installer that can do stuff as part of the uninstallation process. The upgrade installer first uninstall the application and then reinstall it. I can add code only to the upgrade installer so I can't use a mutex for example.
Thanks!
You can use named mutex, it is windows core object and two processes can check if it is already registered or not.
While uninstalling just create a named mutex, and check if it exists on process start
Here is how to create named mutex
Here is how to check if it exists
How about killing the process in the Uninstall?
public static bool KillProcess(string yourProcessName)
{
foreach (Process clsProcess in Process.GetProcesses())
{
if (Process.GetCurrentProcess().Id == clsProcess.Id)
continue;
if (clsProcess.ProcessName.Contains(name))
{
clsProcess.Kill();
return true;
}
}
return false;
}
I have this code:
[PermissionSet(SecurityAction.Assert, Name = "FullTrust")]
public List<WinInfo> GetWindows()
{
try
{
var isFullTrust = Assembly.GetExecutingAssembly().IsFullyTrusted;
if (isFullTrust)
{
return Process.GetProcesses().Where(z => !string.IsNullOrEmpty(z.MainWindowTitle))
.Select(z => new WinInfo
{
ProcessID = z.Id,
ProcessName = z.ProcessName,
WinID = z.MainWindowHandle,
WindowTitle = z.MainWindowTitle
}).ToList();
}
else
return null;
}
catch (Exception ex)
{
Trace.Write(ex.Message);
return null;
}
}
When I test in on my local computer under my current user (with admin rights) it works ok, displaying all the processes, that have windows. But when I call this code from a windows service, run under "Local Service" account, then the list is empty. I attached to the process, and through debug I found that "Process.GetProcesses()" returns all the processes, but all of them have MainWindowHandle as 0 and MainWindowTitle as empty, even when they do have windows. So what is wrong with my code?
Edit I edited code, so that it checks the assembly for full trust and have PemmissionSet that should grant the code the neccessary rights. Still the result is the same. When I debug, I can see, that "isFullTrust" is "True" and code executes with no exceptions. Still the list is empty, because none of the processes contains not-empty MainWindowTitle
According to this thread :
The problem you're seeing is because by default service don't have access to any interactive desktops. I don't recommend interacting with the desktop from a service (#1, there may not be any desktop, #2 there may be multiple desktops, #3 interacting with the desktop from service in Vista is not implemented) but, you can check the "Interace with desktop" in your services properties.
maybe you can try to create an hidden form?
Surely you need to run that under the user account! Why would applications with open windows be running under the local system account? That's for windows services etc
It could also be related to your process requiring full trust
From MSDN: The Process class has a LinkDemand and an
InheritenceDemand for FullTrust on it. This means that if your
assembly is not fully trusted, it will be unable to kick off new
Processes or get information about running processes
Maybe this is a question of priviliges.
According to this link LocalService has minimum privileges on the local computer.
you should use Local system Account
I'm working on a project that will be "embedded" into a Windows 7 system, this is going to be achieved by disabling task manager and changing the windows shell to the application, as well as other things.
What I'm looking to do here is programmatically change the Windows shell between the application and explorer.exe, I would like to know if there's any way to do this in C#.
Currently I have a few lines of code that attempt to change the registry entry for the Windows Shell, but nothing appears to happen after refreshing the Registry Editor, the code looks like this:
regKey = Registry.LocalMachine.OpenSubKey("SOFTWARE", true).OpenSubKey("Microsoft", true).OpenSubKey("Windows NT", true).OpenSubKey("CurrentVersion", true).OpenSubKey("Winlogon", true);
regKey.DeleteValue("Shell");
regKey.SetValue("Shell", shell);
regKey.Close();
I've tried restarting windows to see if that allows the shell change to complete, but to no avail.
I'd greatly appreciate it if someone can tell me if it's even possible to do it programmatically, and where I'm going wrong with it.
Also, I'd be grateful to know if there's a way to code the program so that it's always running with admin privileges so that registry editing will work.
Many Thanks,
Richard
After much searching of other locations on the net, I have finally got the Shell to change to the executable file of the application that is being built.
The "Embedding" process is a three step process, in the case of the software I'm working on, we start by disabling Task Manager, We then set the shell executable in the Local Machine registry and then repeat the process in the Current User registry.
Below is the code that achieves this:
public void embedSoftware()
{
try
{
// Disable Task Manager
regKey = Registry.CurrentUser.OpenSubKey(subKey, true).CreateSubKey("System");
regKey.SetValue("DisableTaskMgr", 1);
regKey.Close();
// Change the Local Machine shell executable
regKey = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", true);
regKey.SetValue("Shell", shell, RegistryValueKind.String);
regKey.Close();
// Create the Shell executable Registry entry for Current User
regKey = Registry.CurrentUser.OpenSubKey(#"Software\Microsoft\Windows NT\CurrentVersion\Winlogon", true);
regKey.SetValue("Shell", shell);
regKey.Close();
MessageBox.Show("Embedding Complete");
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
In this example the variable "shell" is a string containing the path of the executable to use as the new Windows Shell.
Further to this there's a method to "un-embed" the software, this method simply deletes the "DisableTaskMgr" and "Shell" values from the Current User registries, it also resets the "Shell" value in the Local Machine registry to "explorer.exe".
I hope this helps others out there who're having trouble changing Windows Shells programmatically.
Regards,
Richard
I have a C# 2.0 (WinForms) project in which I try to activate word 2003 (word is installed on the system). By using the following code:
private void ActivateWord()
{
this.Activate();
if (m_WordDocument != null)
{
try
{
m_WordDocument.Activate();
if (m_WordDocument.Application != null)
{
m_WordDocument.Application.Visible = true;
m_WordDocument.Application.Activate();
}
}
catch (COMException comEx)
{
ShowError(this, comEx.Message, false);
}
}
}
When my application executes m_WordDocument.Application.Activate() I receive a COM Exception 0x800A11F9.
Stacktrace:
"System.Runtime.InteropServices.COMException (0x800A11F9): Cannot activate application
at Word.ApplicationClass.Activate()
at Roxit.SquitXO.GUI.DocumentCreatie.frmSelectVeld.ActivateWord()"
What could be the cause of this problem?
COM error 0x800A11F9 is a well-known permission problem that occurs when an underprivileged user (such as Network Service) tries to activate an Office application.
In your case, the problem can't come from IIS since you're developing a WinForms application. Rather, it looks like your app is started by a Windows service running under the Local Service or Network Service user account.
If that's indeed the case, you need to change the user account used by the service in the Log on tab of the service's properties dialog box.
EDIT: You might want to try putting the code that activates Word into a COM+ component and configuring the identity of the component so it runs under a user account that can launch Word.
Just a thought i've seen a similar error when doing word automation on the server (which we no longer do due to flakiness), however at that time it was caused by permission issues from the ASP.net account, I know you are running in winforms but could this possibly be related to permissions ?
If it is a permissions problem, and you can't get Sitecore to run as a user with sufficient permissions, perhaps you could write a different service ("WordService") for your Sitecore application to send requests to. Then WordService could run as a slightly more privileged user, do your stuff with Word, then e.g. write the filled-in Word file to a known location SiteCore can access, or whatever you want it to do.