Custom Uninstall not deleting file in .net Application - c#

I have a settings file created when user run the wpf application.
I have created a custom uninstaller to delete some registry keys related to my app and to delete this setting file.
But my file is not getting deleted.
Here is the code -
public override void Uninstall(IDictionary savedState)
{
base.Uninstall(savedState);
try
{
using (RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true))
{
if (registryKey.GetValue("TeachingManagementTool") != null)
{
registryKey.DeleteValue("TeachingManagementTool", true);
}
}
if (File.Exists("Setting.ini"))
File.Delete("Setting.ini");
}
catch (Exception ex)
{
MessageBox.Show("Registry Keys exception " + ex.Message);
}
}
I tried Directory.GetCurrentDirectory() to get file names and delte it, but it doesnt work. So I checked this line of code works file.Delete(filename). It delets the specified file. So it should delete the file during uninstall as its in the same folder.
At the end I should say- I tried 2-3 different ways to access that file and delete it during uninstallation. but Its not delteting and throwing error some times and sometimes no exception at all.
The exception was related to Access to SysWOW64\AdvanceInstaller is
denied
FYI - MY App has <requestedExecutionLevel level="highestAvailable" uiAccess="false" /> already.
I tried solutions available on StackOverflow but its not working So I needed to ask a new question. So please let me know where I am mistaking. I am sure it is something very minor that I might be missing here

Advanced Installer: So you are using Advanced Installer? In the Files and Folders view, select the destination folder in question. In the right pane, right click inside the folder where the file to remove resides. Do you see "New File Operation"? Select "File Removal" and configure options.
Remember to set the options properly. In particular "Remove On". Select on "Component Uninstall".

Related

Registry Startup not working windows application

I created windows application ,I want to start my application on windows startup
for that i written following code in installer class. but when i am checking registry using regedit i didnt get registry value. and my application not working.
public override void Commit(IDictionary savedState)
{
base.Commit(savedState);
try
{
RegistryKey add = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
add.SetValue("ToposcreenServer", "\"" + Application.ExecutablePath.ToString() + "\"");
RegistryKey key = Registry.LocalMachine.CreateSubKey(#"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{70E25B31-99A9-474C-8990-CE28FBCEAAD1}", RegistryKeyPermissionCheck.Default);
if (key != null)
{
key.SetValue("SystemComponent", 1, RegistryValueKind.DWord);
key.Close();
}
Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
Process.Start(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\ToposcreenServer.exe");
GLobalclass.WriteLog("Installer Executed");
}
catch (Exception ex)
{
GLobalclass.WriteLog("Installer Error :" + ex.Message);
}
}
If this is an Everyone install then that code won't write to HKCU of the installing user because the code is running with the System account credentials, not the installing user's.
Anyway, you don't need code to set the Run key. Go to the registry view in the IDE and add registry folders to get to that Run key in HKCU. Then add an item with the Nama ToposcreenSaver and the value [TARGETDIR]my.exe assuming your executable is in the Application Folder in the File System view. It's possible that it won't run anyway if it requires elevation on a UAC system.
(If this code is really in an installer class, it's also not clear why you're using Application and ExecuteablePath because an installer class is a Dll being called from an msiexec.exe process, and is nothing at all to do with whatever executable you want to run. Surely it's the name of an executable you are installing?)
You don't need to set SystemComponent in the registry key. That registry key may not be there at the time your custom action runs, and what you should really do is open your MSI file with Orca and add ARPSYSTEMCOMPONENT to the Property table, give it a value of 1.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa367750(v=vs.85).aspx
If the app really is a conventional screensave this might be the best way to do it:
http://www.advancedinstaller.com/user-guide/qa-install-screensaver.html
You need to check that add is not null, as per https://msdn.microsoft.com/en-us/library/xthy8s8d(v=vs.110).aspx .

Trying to get an Eventlog file to be copied to another folder for backup purpose

I try to copy the EventLog "Application" to another folder on my PC but always get the error that
"....Could not find a part of the path
'C:\Windows\System32\winevt\Logs\Application.evtx..."
I use the code:
public void collectEventLogsFromSystem(string RequestedlogName,string newFolderPath)
{
string combinedLogToFind = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Eventlog\\" + RequestedlogName;
string LogEventsPath = (string)Registry.GetValue(combinedLogToFind, "File", null);
if (LogEventsPath != null)
{
System.IO.File.Copy(LogEventsPath, newFolderPath +"\\"+ RequestedlogName, true);
}
}//collectEventLogsFromSystem method
Even if i use explicit folder path it won't work:
System.IO.File.Copy(#"C:\Windows\System32\winevt\Logs\Application.evtx", "c:\\ttt\\Application.evtx", true);
any idea?
I found this answer on StackOverflow which will probably solve your problem. I have a 64 bit machine which exhibited the same behavior. This post by John Rasch solved the issue and explains why it failed.
If you are trying to get the log file while the program is running, the way above will not work. This post Export Event Log (.evtx) without "run as administrator" will allow you to backup the event log, even if you are currently using the event log in your application.

"ClickOnce does not support the request execution level 'requireAdministrator.'"

So I was writing an application that requires access to the registry.
I had not touched any build settings, wanting to get the thing working before I added the other touches, such as a description or name.
Out of the blue, I get an error that will not go away. ClickOnce does not support the request execution level 'requireAdministrator'. Now, I hadn't touched ClickOnce in this application. All I had done was include a manifest file requesting these permissions.
My problem now is that this error will not go away, and I cannot compile my program. Any advice on what to do? (Side note: I am about to go to bed, so I will check this tomorrow afternoon).
Edit: This comment gives a good answer, too.
Click once appears to get enabled whenever you click "Publish", whether you want it to or not! If you are using "requireAdministrator" then it appears that you cannot use ClickOnce, and therefore cannot "Publish" your project.
Original:
Turns out that under the Security tab, "Enable ClickOnce security settings" was checked. Even though I didn't check it.
Anyway, unchecking that stopped ClickOnce giving me errors. That took a while to find...
I know this an old question but I came here two years later so:
You can disable the ClicKOnce from the Security tab on project properites to help the issue; see below:
If you ever use the publishing wizard, or 'Publish Now', the click-once checkbox gets automatically selected...
I know this is old but I stumbled across it looking for answers. In my case, I AM using the publish function and I need to keep using it. I also need access to admin capabilities. So for that reason, none of the above answers worked for me.
I ended up adding a method to the very start of my application that checks if it's being run as an administrator and if it isn't, relaunch itself as an admin. To do this, you need the following references added.
using System;
using System.Diagnostics;
using System.Reflection;
using System.Security.Principal;
Then you will need to put this somewhere that your main method has handy access to. I'm using WPF so I added it to MainWindow.xaml.cs but you can add it anywhere early on in your code. Just remember to add "static" to these methods should you need it.
private void AdminRelauncher()
{
if (!IsRunAsAdmin())
{
ProcessStartInfo proc = new ProcessStartInfo();
proc.UseShellExecute = true;
proc.WorkingDirectory = Environment.CurrentDirectory;
proc.FileName = Assembly.GetEntryAssembly().CodeBase;
proc.Verb = "runas";
try
{
Process.Start(proc);
Application.Current.Shutdown();
}
catch(Exception ex)
{
Console.WriteLine("This program must be run as an administrator! \n\n" + ex.ToString());
}
}
}
private bool IsRunAsAdmin()
{
try
{
WindowsIdentity id = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(id);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
catch (Exception)
{
return false;
}
}
Lastly, at the start of your program, add a reference to the method. In my case, I added it to MainWindow but adding it to Main works too.
public MainWindow()
{
InitializeComponent();
AdminRelauncher(); //This is the only important line here, add it to a place it gets run early on.
}
Hope this helps!
For .NET Core and .NET 5+
If you're stumbling upon this in the 20s, this is how you would change the above to work with .NET Core and .NET 5+
The only function that needs changing is the AdminRelauncher and it should look like this instead.
private static void AdminRelauncher()
{
if (!IsRunAsAdmin())
{
ProcessStartInfo proc = new ProcessStartInfo();
proc.UseShellExecute = true;
proc.WorkingDirectory = Environment.CurrentDirectory;
proc.FileName = Assembly.GetEntryAssembly().Location.Replace(".dll", ".exe");
proc.Verb = "runas";
try
{
Process.Start(proc);
Environment.Exit(0);
}
catch (Exception ex)
{
Console.WriteLine("This program must be run as an administrator! \n\n" + ex.ToString());
}
}
}
The only big changes is as someone pointed out Application isn't always available. So Environment.Exit(0) can replace it and the filename needs to replace .exe with .dll. This has been tested as of .NET 6
For those who use uncheck "Enable ClickOnce security settings" can't work, to try the method I find.
First, leave your app.manifest requestedExecutionLevel item as is:
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
And then you edit your Program.cs file like this:
using System;
using System.Diagnostics;
using System.Reflection;
using System.Security.Principal;
using System.Windows.Forms;
restruct main method like:
static void Main()
{
var wi = WindowsIdentity.GetCurrent();
var wp = new WindowsPrincipal(wi);
bool runAsAdmin = wp.IsInRole(WindowsBuiltInRole.Administrator);
if (!runAsAdmin)
{
// It is not possible to launch a ClickOnce app as administrator directly,
// so instead we launch the app as administrator in a new process.
var processInfo = new ProcessStartInfo(Assembly.GetExecutingAssembly().CodeBase);
// The following properties run the new process as administrator
processInfo.UseShellExecute = true;
processInfo.Verb = "runas";
// Start the new process
try
{
Process.Start(processInfo);
}
catch (Exception)
{
// The user did not allow the application to run as administrator
MessageBox.Show("Sorry, but I don't seem to be able to start " +
"this program with administrator rights!");
}
// Shut down the current process
Application.Exit();
}
else
{
// We are running as administrator
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
It works on Windows 10 and Visual Studio 2019!
This action can be achieved by selecting "Enable ClickOnce security settings" (since it cannot be "unchecked" during a Publish, as stated) and then by selecting "This is a partial trust application". "Local Intranet" will be automatically selected in the drop-down menu which is perfectly fine.
Save your changes, Publish the application, done-skis. :-)
I have the same problem s I resolve it by unchecking the "Enable ClickOnce security settings"
To Find this option in Visual Studio Right Click on your Project ==>properties==>Select Security==> Enable ClickOnce security settings (This option was already checked so I unchecked it and my problem get resolved).
Here is the code snippet for VB.NET
If Not New WindowsPrincipal(WindowsIdentity.GetCurrent).IsInRole(WindowsBuiltInRole.Administrator) Then
Process.Start(New ProcessStartInfo With { _
.UseShellExecute = True, _
.WorkingDirectory = Environment.CurrentDirectory, _
.FileName = Assembly.GetEntryAssembly.CodeBase, _
.Verb = "runas"})
EDIT: But if you deploy in this way, some AV-Software blocks your code.
For anyone who's run into this, I thought I'd contribute what ended up working for me.
Yep, the 'Enable ClickOnce security settings' option automatically gets re-checked, if you un-check it, when you do Build > Publish .
For me, I don't need to 'Publish' -- it's a simple, portable .exe that creates Scheduled Tasks for my users and I needed to make sure it elevated, even when logged-in as an Administrator.
So I just grabbed my latest .exe from \bin\Release and that's what gets deployed on my clients' systems.
Worked just as expected -- i.e. when I put it on a system w/ UAC enabled/at its highest setting, the .exe has the 'shield' on it, and when I run it, even when logged-in as an Administrator, it elevates and I get the UAC prompt.
My little task scheduler app is now able to create the task without getting an 'Access Denied' error (which previously, could only be worked-around by right-clicking the .exe and clicking Run as Administrator).
Take a look in your app.Manifest file and you'll see this:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
There's instructions there in the comments, but just deleting the "requireAdministrator" and insert this in is place solved the problem for me:
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
just
Imports System.security
and
U will get no error and your application will be run as admin

How to get the (.lnk) shortcut filepath in a program which started by the shortcut?

I have a c# program which open *.postfix file.
If a user runs a (.lnk)shortcut which points to my type of file, my program will open the target.
So, how could my program know it is started by a (.lnk)shortcut (and get it's file path)?
In some circumstances,i need to replace the .lnk file.
Thanks!
Edited
First, thanks to guys who answered my question.
By following #Anders answer, i find out my problem lays here.
I made some changes to windows registry, so browser knows to throw customized protocol string to certain program.
some thing like this..
[InternetShortcut]
URL=myProtocol://abcdefg.....
That's maybe why i lost lpTitle. :(
I'm going to try this way:
Whenever my program invoked, of course fed with %1, program checks current opened explorer(Window), and try to get it's current path with IWebBrowserApp. With that path and desktop of course, scan and analyze *.lnk to determine which one to replace.
I think this will probably work, but not be sure. I will try.
continued
In native code you can call GetStartupInfo, if the STARTF_TITLEISLINKNAME bit is set in STARTUPINFO.dwFlags then the path to the .lnk is in STARTUPINFO.lpTitle. I don't know if there is a .NET way to get this info, you probably have to P/Invoke...
You don't. There's no way to do it. End of story.
So this has been brought to my attention due to a recent downvote. There's an accepted answer showing an idea that gets the path to the launching shortcut most of the time. However my answer is to the whole. OP wants the link to the shortcut so he can change it. That is what can't be done most of the time.
Most likely case is the shortcut file exists in the start menu but is unwritable. However other cases involve the shortcut coming from another launching application that didn't even read it from a disk but from a database (I've seen a lot of corporate level restricted application launch tools). I also have a program that launches programs from shortcuts not via IShellLink but by parsing the .lnk file (because it must not start COM for reasons) and launching the program contained. It doesn't pass STARTF_TITLEISLINKNAME because it's passing an actual title.
If you're using Visual Studio Setup Project to build an installer and do the file type association, you should follow these instructions http://www.dreamincode.net/forums/topic/58005-file-associations-in-visual-studio/
Open up your solution in Visual studio.
Add a Setup Project to your solution by file , add project,New project, Setup & Deployment projects,Setup project
Right-click on your setup project in the "Solution Explorer" window,Select view,then select file types.
you'll see the "file types" window displayed in Visual studio.At the top of the window will be "File types on target machine"
Right-click on "File types on target machine".the menu will pop up with Add "file type" Click on this.
you'll see "New document Type#1" added,and "&open"underneath it.
The "new document type#1" can be anything you want - change it to something descriptive.although the user never sees this,never use something common- be as unique as possible,Because you can overlay current file associations without even realizing it.For example,you might think"pngfile" might be a useful name- but using that will now send all"*.png" files to your application,instead of to an image viewer.A good practice maybe "YourCompantName.Filetype",where your company name is your name of your company's name, and "Filetype" is a descriptive text of your file.
In the "properties" window for your new type,you will need to change a few properties.:
Command:Change to the application that you want to run.If you click on the "..." and you will proberly want to locate and use the "primary Output..." File
Description: This is the description of the file type(if it doesn't describe it's self"
Extensions:This your list of extensions for you chosen Program.Separate each one with a ","
Icon:This will associate the icon with your file type,This shows up in the window explorer.
Now we move to that "&open ".This is an action that is available if your right-click on the file.The default action("&Open" is currently set as the default) is what happens when you double click on the file.Right click on your "New document type#1" to add actions,but for the moment,lets define our "&open" action
Click on "&Open".You will see in the properties window "Name","Arguments","Verbs". Verb is hidden from the user,but is the key that is stored in the registry.Leave it same as the name,But without the "&".The default for"Arguments" is "%1",Which means to pass the full path and filename to your application.You can add other stuff here as well,if you need to pass flags to your application to do special stuff.All this infomaton is getting passed to your application on the command line,so you'll need to be familiar with the "Environment.CommandLine" object.
If you need to set a different action as your default,just right click on the action and "set as default"
Basically, you'll pass the file path as an argument to your program. Then if it's a console application or Windows Forms , you should check the arguments in Program.Main
static void Main(string[] args)
{
//if file association done with Arguments %1 as per forum post above
//you file path should be in args[0]
string filePath = null;
if(args != null && args.Length > 0)
filePath = args[0];
}
For a WPF application you'll need to handle that in the StartUp event for your Application
void App_Startup(object sender, StartupEventArgs e)
{
string filePath = null;
if ((e.Args != null) && (e.Args.Length > 0))
{
filePath = e.Args[0];
}
}

Valid path not so valid in Vista using ParseDisplayName. Why?

In the following code example... where filePath is: E:\[D]\My Collection (a folder generated by picasa when it archives media) works okay on XP (32-bit). I recent ran this on vista 64-bit... and ParseDisplayName errors with "Value does not fall within the expected range." All other folders (without the '[D]') work okay. Any help would be appreciated.
try
{
int cParsed = 0;
int pdwAttrib = 0;
string filePath = Path.GetDirectoryName(file);
pidlMain = IntPtr.Zero;
folder.ParseDisplayName(IntPtr.Zero,IntPtr.Zero,filePath,out cParsed,out pidlMain,out pdwAttrib);
}
catch (Exception ex)
{
Marshal.ReleaseComObject(folder);
throw ex;
}
This happens (irrespective of the code pack; you can repro it by using the shell API directly and getting the parsing name) on Vista when you select the folders in the Common File Dialog (or any type of Open dialog) from the left side tree view.
For e.g - using the example you mention - Code pack's sample. Run the sample, select browse, from the CFD, select your folder from the left side tree view. You will also get the same problem if you go inside the folder and then click on "Open". The parsing name that you get is:
c:\folder\folder (notice the duplicate folder).
This is a known issue in Vista... I am afraid there is no patch for it (or atleast that I am aware of - unless you switch to Win7 :-) )

Categories

Resources