I am testing a C# WPF program that requires elevated privileges, that loads without any delay if I am logged on as an admin, but if I am logged on as a standard user (99% of time) then there is a delay of about 30 seconds before the UI appears.
Using the same elevation code in a C# console app and in a c# Winforms app, there is no delay in loading, so I know that the code works.
So, can anyone explain to me why is there a delay associated with WPF; and is there a workaround?
Here is the code from app.xaml.cs ( the remainder of the project is as genereated by VS2010)
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;
using System.Security.Principal;
using System.Diagnostics;
using System.Reflection;
using System.ComponentModel;
using MyNewServiceLib;
using System.Runtime.InteropServices;
namespace WhySoSlow
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
if (!IsAdmin())
{
StartAsAdmin(e);
Application.Current.Shutdown();
}
else
{
MainWindow = new MainWindow();
MainWindow.SizeToContent = SizeToContent.WidthAndHeight;
MainWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen;
MainWindow.Show();
}
}
bool IsAdmin()
{
WindowsIdentity id = WindowsIdentity.GetCurrent();
WindowsPrincipal p = new WindowsPrincipal(id);
return p.IsInRole(WindowsBuiltInRole.Administrator);
}
private void StartAsAdmin(StartupEventArgs e)
{
string[] args = e.Args;
try
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = true;
startInfo.WorkingDirectory = Environment.CurrentDirectory;
Uri uri = new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase);
startInfo.FileName = uri.LocalPath;
startInfo.Arguments = String.Join(" ", args);
startInfo.Verb = "runas";
Process p = Process.Start(startInfo);
}
catch (Win32Exception exception)
{
MessageBox.Show(exception.Message);
}
}
}
}
Further info
Weirdly, if I start the program from a cmd prompt running under NT Authority\System, there is no delay starting up the UI. After that one successful start, every further start, from whatever prompt, be it standard user prompt, run as administrator, the program starts without delay; UNTIL that is, I log off from the session.
After logging on again to a new (standard user) session, all attempts to start the program result in the 30 second delay before showing the UI.
I can only think that this is some kind of UAC bodge by Microsoft, that is hindering the startup of wpf.
Instead of using this code, have you tried utilizing a manifest file? Running an application as admin is one of the things you can do with it.
this might help https://msdn.microsoft.com/en-us/library/ms742884.aspx
Related
i have two WPF Application say WPFApplication1 and WPFApplication2 , WPFApplication1 has reference of WPFApplication2 , now i am calling one class of WPFApplication2 in WPFApplication1 using reference, and from WPFApplication2 class creating App class instance of WPFApplication2 , so i am facing issue like below
Error
Please help me out with this, THanks in Advance
Look at Process.Start and ProcessStartInfo
Here is an example for Console application. But there are not different how to start other application.
By ProcessStartInfo you can specify many things like Are you has to wait it? Or run without waiting. Is you want to redirect output? And so one.
using System.Diagnostics;
class Program
{
static void Main()
{
LaunchCommandLineApp();
}
/// <summary>
/// Launch the application with some options set.
/// </summary>
static void LaunchCommandLineApp()
{
// For the example
const string ex1 = "C:\\";
const string ex2 = "C:\\Dir";
// Use ProcessStartInfo class
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.FileName = "dcm2jpg.exe";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = "-f j -o \"" + ex1 + "\" -z 1.0 -s y " + ex2;
try
{
// Start the process with the info we specified.
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(startInfo))
{
exeProcess.WaitForExit();
}
}
catch
{
// Log error.
}
}
}
I want to make an updating exe that when i click on it either it will download or uploads data. The problem is that whenever i execute git pull origin master i have to enter the password.
This is what i tried:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace GitUpdate
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("GIT updating");
Process cmd = new Process();
cmd.StartInfo.FileName = "git";
cmd.StartInfo.Arguments = "git pull origin master";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.UseShellExecute = false;
cmd.Start();
cmd.StandardInput.WriteLine("MY_PASSWORD_HERE");
cmd.StandardInput.Flush();
cmd.StandardInput.Close();
cmd.WaitForExit();
Console.WriteLine(cmd.StandardOutput.ReadToEnd());
Console.WriteLine("GIT updated ...");
Console.Read();
}
}
}
What am i doing wrong?
Also i know that there are git libraries for C# and options to remember the password, but i want to make it exe style, really need this.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
namespace WindowsFormsApplication
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var newProcessInfo = new System.Diagnostics.ProcessStartInfo();
newProcessInfo.FileName = #"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe";
newProcessInfo.Verb = "runas";
System.Diagnostics.Process.Start(newProcessInfo);
newProcessInfo.Arguments = #"sfc /scannow";
}
}
}
So my code works up to a point. you click the windows form application button and it will run windows Powershell in 64bit as an administrator but won't run a .ps1 script "c:\path\script.ps1" or the command directly written out like the "sfc /scannow" above.
I was reading that the powershell commands won't work sometimes if the "Set-ExecutionPolicy Unrestricted" isn't loaded somewhere in the beginning of the code.
Please help! I have been looking everywhere for an answer.
First of all, you need to specify the Arguments property before you start the process:
var newProcessInfo = new System.Diagnostics.ProcessStartInfo();
newProcessInfo.FileName = #"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe";
newProcessInfo.Verb = "runas";
newProcessInfo.Arguments = #"sfc /scannow";
System.Diagnostics.Process.Start(newProcessInfo);
Second, you'll need to tell PowerShell that sfc /scannow is a command, and not command line switches.
On the command line you would do powershell.exe -Command "sfc /scannow", so the correct Arguments value in your case would be
newProcessInfo.Arguments = #"-Command ""sfc /scannow""";
("" is the escape sequence for " in verbatim string literals)
For .ps1 files, use the -File switch:
newProcessInfo.Arguments = #"-File ""C:\my\script.ps1""";
If you don't know the execution policy on the target system, you can bypass it without affecting the machine-wide policy with -ExecutionPolicy Bypass:
newProcessInfo.Arguments = #"–ExecutionPolicy Bypass -File ""C:\my\script.ps1""";
Greetings SO Community
I'm writing a c# program to manage the uwfmgr registry exclusions.
I execute the following command.
uwfmgr registry get-exclusions.
Afterwards, when I want to read the registry, I get an exception with the message:
No more data is available.
This problem persists until the next reboot.
I suspect, that uwfmgr does not release the registry key properly.
I've made a minimal example to demonstrate the error.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;
namespace WindowsFormsApplication2
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
try
{
Process proc = new Process();
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.FileName = "C:\\Windows\\Sysnative\\uwfmgr.exe";
proc.StartInfo.Arguments = "registry get-exclusions";
proc.Start();
proc.WaitForExit();
string output = proc.StandardOutput.ReadToEnd();
string[] subkeys = Registry.LocalMachine.GetSubKeyNames();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n" + ex.StackTrace);
}
}
}
}
Info:
CLR is ".Net Framework 4.5".
Target is "Any CPU".
The executing system is "Windows Embedded 8.1 Industry Pro".
The architecture is 64bit.
Now, is there any possible way to force uwfmgr to release the registry?
PS: This is my first post. I tried to post according to the rules, but if I forgot something, please kindly remind me. Thanks.
Below is the scenario.
Logged in to windows using user name "JOHN"
Run the Windows application writtern in c# . This tool name is BootStrapper.exe. But this tool I executed using different user called "ALEX" using Run As feature.
Boot strapper will show some button called "Launch Application". On clicking Launch executing Application.exe using Process class of c#. Note that i am not passing any user name and password. So Application.exe is also running under "ALEX" User.
How do I run the Application.exe under "JOHN" from Bootstrapper.exe even though it is started by "ALEX".
Note that the password of the "JOHN" will not be known to Application.exe to impersonate JOHN user.
Host a WCF service in a process started by JOHN (maybe by putting it in the startup folder).
Call the WCF service from the ALEX process with a command telling what process to start.
Start the process from the WCF service and it will be running as JOHN.
I apologize for my bad English. Maybe I wrong understand you... Compile it, and copy result to "C:\test" directory. Now run it.
using System;
using System.Text;
using System.Diagnostics;
using System.Security;
using System.Reflection;
using System.IO;
namespace ConsoleApplication6 {
class Program {
unsafe static void Main(string[] args) {
Process process = new Process();
String dir = Path.GetDirectoryName(typeof(Program).Assembly.Location);
String txtFile = Path.Combine(dir, "example.txt");
if (!File.Exists(txtFile)) {
StreamWriter sw = File.CreateText(txtFile);
sw.Close();
sw.Dispose();
}
ProcessStartInfo info = new ProcessStartInfo();
info.Domain = "myDomainName";
info.UserName = "userName";
String pass = "userPassword";
fixed (char* password = pass) {
info.Password = new SecureString(password, pass.Length);
}
// Will be run notepad.exe
info.FileName = Environment.ExpandEnvironmentVariables(#"%winDir%\NOTEPAD.EXE");
// in notepad.exe will be open example.txt file.
info.Arguments = txtFile;
info.LoadUserProfile = false;
info.UseShellExecute = false;
info.WorkingDirectory = dir;
process.StartInfo = info;
process.Start();
}
}
}
Regards