MS Paint shortcut exist on desktop or not? - c#

i want to find out that mspaint shortcut exist in desktop or no? if its exist, user score is 7 else its 0. i use this code:
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
if (Directory.Exist (path + #"\mspaint.exe"))
{
Controller.ExamController.AddExam(1, n, 7, time, Session.currentUserId);
}
else
{
Controller.ExamController.AddExam(1, n, 0, time, Session.currentUserId);
}
but anyway the result is "0".but this code works for directory and folders and return 7.
also i try "File.Exist" but it has same problem.
How can i check a shortcut of specific program exist in desktop or no?
if (questionNumber == 2)
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
var list = Directory.EnumerateFiles(path);
foreach (var v in list)
{
var extension = Path.GetExtension(v);
if (extension.Equals(".lnk", StringComparison.InvariantCultureIgnoreCase))
{
WshShell shell = new WshShell();
IWshShortcut link = (IWshShortcut)shell.CreateShortcut(v);
if (Path.GetFileName(link.TargetPath).Equals("mspaint.exe", StringComparison.InvariantCultureIgnoreCase))
{
Controller.ExamController.AddExam(1, n, 7, time, Session.currentUserId);
}
else
{
Controller.ExamController.AddExam(1, n, 0, time, Session.currentUserId);
}
}
}
}
when i use this, its ok, but it returns 0 for not exist and return both of 0 and 7 for exist

Shortcut is just another type of files, as MSDN says:
When the user creates a shortcut to an object by choosing the Create
Shortcut command from the object's shortcut menu, Windows stores the
information it needs to access the object in a link file—a binary file
that has the .lnk file name extension.
It mean that you should refer exactly to shortcut: with exact name and .lnk extension.
You need to check shortcut for example like this:
File.Exist(Path.Combine(path, "Paint.lnk"))
But in my opinion right solution is to get all shortcuts from desktop and examine target path for each one for mspaint.exe path.
For reading shortcut information read this SO post: Get target of shortcut folder

This needs explicit coding and you cannot look for names of the file in deskTop since it can be changed to anything because its just a short cut,
Include the COM addin reference Windows Script Host Object Model - Interop.IWshRuntimeLibrary
using IWshRuntimeLibrary;
public string test()
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
var list = Directory.EnumerateFiles(path);
foreach(var v in list)
{
var extension = Path.GetExtension(v);
if (extension.Equals(".lnk", StringComparison.InvariantCultureIgnoreCase))
{
WshShell shell = new WshShell();
IWshShortcut link = (IWshShortcut) shell.CreateShortcut(v);
if (Path.GetFileName(link.TargetPath).Equals("mspaint.exe", StringComparison.InvariantCultureIgnoreCase))
{
return link.TargetPath;
}
}
}
return null;
}

A Shortcut is a special kind of file
A shortcut is a special kind of file. It contains data which points to a location (for example mspaint.exe), but that doesn't mean it needs to be named the same as the exe it's pointing to. For example, it can have a name of "HappyPaint.lnk" and point to "mspaint.exe".
Reading Shortcut Destination
Therefore you need to look for all "*.lnk" files on the desktop and read their destination paths. Here's how you can go about it:
First, add a reference to Microsoft Shell Controls And Automation:
Second, add some code along the lines of:
string desktopDirectoryPath = Environment.GetFolderPath(
Environment.SpecialFolder.DesktopDirectory);
string msPaintPath = Environment.ExpandEnvironmentVariables(
#"%windir%\system32\mspaint.exe");
// add reference to COM --> Microsoft Shell controls and Automation
Shell shell = new Shell();
Folder folder = shell.NameSpace(desktopDirectoryPath);
var shortcutFilePaths = Directory.GetFiles(desktopDirectoryPath, "*.lnk");
bool msPaintShortcutExists = false;
foreach (string shortcutFilePath in shortcutFilePaths)
{
FolderItem folderItem = folder.ParseName(Path.GetFileName(shortcutFilePath));
Shell32.ShellLinkObject link = (Shell32.ShellLinkObject) folderItem.GetLink;
var shortcutDestination = Environment.ExpandEnvironmentVariables(link.Path);
if (string.Compare(
msPaintPath, shortcutDestination, StringComparison.OrdinalIgnoreCase) == 0)
{
msPaintShortcutExists = true;
break;
}
}
if (msPaintShortcutExists)
{
Controller.ExamController.AddExam(1, n, 7, time, Session.currentUserId);
}
else
{
Controller.ExamController.AddExam(1, n, 0, time, Session.currentUserId);
}
Needs to be run in an STAThread
Note: In case an InvalidCastException with a message
Unable to cast COM object of type 'System.__ComObject' to interface type 'Shell32.Shell'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{286E6F1B-7113-4355-9562-96B7E9D64C54}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
occurs on new Shell(); you're not running the code in an STAThread but it needs to be run in an STAThread. An easy work around is to add the following method:
private static void ExecuteInStaThread(Action a)
{
var thread = new Thread(() => a());
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
if (!thread.Join(TimeSpan.FromSeconds(30)))
{
thread.Abort();
}
}
and wrap the code in a call to it:
ExecuteInStaThread(() =>
{
string desktopDirectoryPath = ...
...
});

Related

How can I retrieve items and their details from the shell:AppsFolder virtual folder using c#?

I am trying to get all the items from the FOLDERID_AppsFolder, which you can access by running explorer.exe shell:appsFolder command, and their details, specifically the AppUserModelID.
I can get the name of the items using the code below but I am not sure how to get the AppUserModelID. Can I get this value somehow?
IShellItem appsFolder;
string str;
var res = ShellItemUtilities.SHGetKnownFolderItem(ShellItemUtilities.FOLDERID_AppsFolder,
0, IntPtr.Zero, typeof(IShellItem).GUID, out appsFolder);
if (res < 0) return;
try
{
var pidl = default(PIDLIST_ABSOLUTE);
foreach (var app in appsFolder.Enumerate())
{
try
{
recyleBin.GetDisplayName(2, out ptr);
// Get the actual name of the item
str = Marshal.PtrToStringUni(ptr);
}
finally
{
if (ptr != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(ptr);
ptr = IntPtr.Zero;
}
}
}
}
...
Perhaps the IShellItem::GetAttributes method is what I need but it can only retrieve the attribute that I specify through the sfgaoMask parameter and the documentation regarding the values for this parameter does not include anything related to the AppUserModelID.
And for reference, this is what the apps folder looks like:
Can you hear the crickets chirping?
I was eventually able to find a solution to this problem when I stumbled upon the Microsoft.WindowsAPICodePack-Shell nuget package which wraps all the shell commands I needed so that I don't have to P/Ivoke them. The code now becomes:
// GUID taken from https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid
var FODLERID_AppsFolder = new Guid("{1e87508d-89c2-42f0-8a7e-645a0f50ca58}");
ShellObject appsFolder = (ShellObject)KnownFolderHelper.FromKnownFolderId(FODLERID_AppsFolder);
foreach (var app in (IKnownFolder)appsFolder)
{
string name = app.Name;
// The ParsingName property is the AppUserModelID
string appUserModelID = app.ParsingName; // or app.Properties.System.AppUserModel.ID
ImageSource icon = app.Thumbnail.MediumBitmapSource;
}
The ShellObject object actually contains a whole lot more proeprties available through it's Properties.System props.
In case you are wondering why I am casting the appsFolder to a ShellObject at instantiation only to cast it back to an IKnownFolder when enumerating, that's because the API code pack actually comes with a ShellObjectWatcher which takes a ShellObject and monitors it for changes. If a new app is installed and it is listed in this virtual folder, the watcher can be used to monitor for this:
ShellObjectWatcher sow = new ShellObjectWatcher(appFolder, false);
sow.AllEvents += (s, e) => DoWhatever();
sow.Start();

How to skip the code which produces error when dll is Missing in C#?

I have a Console Application in C# and a Class Library named AppManager.cs. The Method of this class is used in the console Application as given below.
try
{
AppManager mgr = new AppManager(); //Want to skip this line when dll is missing.
mgr.Method_Name(this, true); //Want to skip this line when dll is missing.
}
catch (Exception)
{
}
When I have published the Code and extracted only exe then application fails to run [I know as the exe try to find that dll and method present in dll won't available].
Now my Question is That Is there any way to skip the code which will produce error when it will not find the reference of dll.
I also tried this but it didn't worked:
String file = null;
String filePath = Path.GetDirectoryName(Application.ExecutablePath);
file = Directory.GetFiles(filePath, "myLibrary.dll", SearchOption.AllDirectories)
.FirstOrDefault();
if (file != null)
{
AppManager mgr = new AppManager();
mgr.Method_Name(this, true);
}
If you do that, it won't give the desired output too. Why don't you integrate the dll with your exe? You can do it by using this tool
Can you not simply check if the dll exists or not?
string filePath = #"SOME_PATH";
var exists = File.Exists(filePath);
if(exists)
{
AppManager mgr = new AppManager();
mgr.Method_Name(this, true);
}

Get path to executable from command (as cmd does)

Given a command-line style path to a command such as bin/server.exe or ping, how can I get the full path to this executable (as cmd or Process.Start would resolve it)?
I tried Path.GetFullPath, but it always expands relative to the working directory. It expands bin/server.exe correctly, however given ping it returns c:\users\matt\ping (non-existent). I want c:\Windows\system32\ping.exe.
Edit: I would like the same behaviour as cmd. Some considerations:
When there is a local executable with the same name as one in the path, cmd prefers the local one
cmd can expand the command server to server.bat or server.exe (adding the file extension)
I also tried Windows' command-line tool called where . It does almost I want:
Displays the location of files that match the search pattern. By default, the search is done along the current directory and in the paths specified by the PATH environment variable.
>where ping
C:\Windows\System32\PING.EXE
>where bin\server
INFO: Could not find files for the given pattern(s).
(This question is hard to search around because of the two different meanings of the word 'path')
Considering PATHEXT too, stealing from Serj-Tm's answer (sorry! +1 to him):
public static string WhereSearch(string filename)
{
var paths = new[]{ Environment.CurrentDirectory }
.Concat(Environment.GetEnvironmentVariable("PATH").Split(';'));
var extensions = new[]{ String.Empty }
.Concat(Environment.GetEnvironmentVariable("PATHEXT").Split(';')
.Where(e => e.StartsWith(".")));
var combinations = paths.SelectMany(x => extensions,
(path, extension) => Path.Combine(path, filename + extension));
return combinations.FirstOrDefault(File.Exists);
}
Sorry the indentation's a bit all-over-the-place - I was trying to make it not scroll. I don't know if the StartsWith check is really necessary - I'm not sure how CMD copes with pathext entries without a leading dot.
public static string GetFullPath(string filename)
{
return new[]{Environment.CurrentDirectory}
.Concat(Environment.GetEnvironmentVariable("PATH").Split(';'))
.Select(dir => Path.Combine(dir, filename))
.FirstOrDefault(path => File.Exists(path));
}
If you're only interested in searching the current directory and the paths specified in the PATH environment variable, you can use this snippet:
public static string GetFullPath(string fileName)
{
if (File.Exists(fileName))
return Path.GetFullPath(fileName);
var values = Environment.GetEnvironmentVariable("PATH");
foreach (var path in values.Split(';'))
{
var fullPath = Path.Combine(path, fileName);
if (File.Exists(fullPath))
return fullPath;
}
return null;
}
You have to search the entire disk.
Windows can respond to things like, iexplore, ping, cmd, etc, because they are in the registry under this key:
HKEY_LOCAL_MACHINE
SOFTWARE
Microsoft
Windows
CurrentVersion
App Paths
The only other way is to search the entire disk for the application.
EDIT: My understanding was, that you want to search for any random executable name, not the ones that are already known to Windows..
internal class Program
{
static void Main(string[] args)
{
string fullPath = GetExactPathFromEnvironmentVar("ping.exe");
if (!string.IsNullOrWhiteSpace(fullPath))
Console.WriteLine(fullPath);
else
Console.WriteLine("Not found");
}
static string GetExactPathFromEnvironmentVar(string program)
{
var pathVar = System.Environment.GetEnvironmentVariable("PATH");
string[] folders = pathVar.Split(';');
foreach (var folder in folders)
{
string path = Path.Combine(folder, program);
if (File.Exists(path))
{
return path;
}
}
return null;
}
}
HTH

creating notify icon in system tray and adding shortcut to startup using .net setup creation wizard

I have searched a lot but still not able to find the right solution.
I want to create a setup using .net setup wizard and add 2 checkbox in the setup wizard.
1st checkbox will ask user to "add program in startup". If it is checked then it will add software to startup.
2nd checkbox will ask for "create system tray notify icon". If checked then it will create a notify icon in system tray. The notify icon must be displayed permanently not only when application runs).
I know it had to do with custom actions but still not able to figure it out. Please provide me some article or code for this with proper explanation.
Actually, the custom actions is the right place to do this. Here's the code I use to create two custom checkboxes during the installation process.
[RunInstaller(true)]
public class DeploymentManager : Installer{
public override void Install(IDictionary stateSaver) {
base.Install (stateSaver);
const string DESKTOP_SHORTCUT_PARAM = "DESKTOP_SHORTCUT";
const string QUICKLAUNCH_SHORTCUT_PARAM = "QUICKLAUNCH_SHORTCUT";
const string ALLUSERS_PARAM = "ALLUSERS";
// The installer will pass the ALLUSERS, DESKTOP_SHORTCUT and QUICKLAUNCH_SHORTCUT
// parameters. These have been set to the values of radio buttons and checkboxes from the
// MSI user interface.
// ALLUSERS is set according to whether the user chooses to install for all users (="1")
// or just for themselves (="").
// If the user checked the checkbox to install one of the shortcuts, then the corresponding
// parameter value is "1". If the user did not check the checkbox to install one of the
// desktop shortcut, then the corresponding parameter value is an empty string.
bool allusers = true; // Context.Parameters[ALLUSERS_PARAM] != string.Empty;
bool installDesktopShortcut = true; //Context.Parameters[DESKTOP_SHORTCUT_PARAM] != string.Empty;
bool installQuickLaunchShortcut = true;// Context.Parameters[QUICKLAUNCH_SHORTCUT_PARAM] != string.Empty;
if (installDesktopShortcut){
// If this is an All Users install then we need to install the desktop shortcut for
// all users. .Net does not give us access to the All Users Desktop special folder,
// but we can get this using the Windows Scripting Host.
string desktopFolder = null;
if (allusers){
try{
// This is in a Try block in case AllUsersDesktop is not supported
object allUsersDesktop = "AllUsersDesktop";
WshShell shell = new WshShellClass();
desktopFolder = shell.SpecialFolders.Item(ref allUsersDesktop).ToString();
}
catch {}
}
if (desktopFolder == null)
desktopFolder = Environment.GetFolderPathEnvironment.SpecialFolder.DesktopDirectory);
CreateShortcut(desktopFolder, ShortcutName, Path.Combine(TargetAssemblyFolder, TargetAssembly), ShortcutDescription, Path.Combine(TargetAssemblyFolder, "your.ico"));
}
if (installQuickLaunchShortcut){
CreateShortcut(QuickLaunchFolder, ShortcutName, ShortcutFullName, ShortcutDescription, Path.Combine(TargetAssemblyFolder, "your.ico"));
}
}
private void CreateShortcut(string folder, string name, string target, string description, string targetIcon){
string shortcutFullName = Path.Combine(folder, name + ".lnk");
try{
WshShell shell = new WshShellClass();
IWshShortcut link = (IWshShortcut)shell.CreateShortcut(shortcutFullName);
link.TargetPath = target;
link.Description = description;
FileInfo fi = new FileInfo(targetIcon);
link.IconLocation = Path.Combine(fi.Directory.FullName, fi.Name);
link.Save();
}catch (Exception ex){
MessageBox.Show(string.Format("The shortcut \"{0}\" could not be created.\n\n{1}", shortcutFullName, ex.ToString()),
"Create Shortcut", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
After you have this code, you can add the Custom Action to the installer to the Install Custom Actions area.
The notification code would be similar for the install process but needs to be added to the registry.

Outlook 2k7 Integration (via P/Invoke) - Blocking unsafe attachments

We're currently developing a plug-in for a piece of software in C#. This plug-in extracts the contents of a PST file and stores all items in it as text files (with the exception of attachments, which are stored as their type in the same folder as the email).
It has been working without issue until we tested it on Windows 7 w/ Outlook 2K7. After running the same previous job on a machine with Outlook 2000 on it, we noticed that there were over 12,000 files missing. These files turned out to be attachments (mostly URLs)
We found that the issue is that Outlook 2K7 blocks attachments with specific extensions. If you open the email in Outlook itself, you see a blue bar at the top stating "Outlook blocked access to the following potentially unsafe attachments" and all the attachments in the emails.
Is there a way to programmatically get these attachments without Outlook blocking them?
The code we use to save the attachments is:
private void saveAttachment(ref object oEmail, StoreInfo currentStoreInfo, string sEmailID, string sExportPath)
{
int iAttachCount = 0;
object oAttach = null;
oAttach = getNextAttachment(oEmail, ref iAttachCount);
while (oAttach != null)
{
saveAttachment(sEmailID, sExportPath, oAttach);
oAttach = getNextAttachment(oEmail, ref iAttachCount);
}
}
private object getNextAttachment(object oEmail, ref int iAttachCount)
{
object oAttach = null;
try
{
iAttachCount++;
oAttach = GetProperty(oEmail, "Attachments", new object[] { iAttachCount });
}
catch //(Exception ex)
{
// There was no attachment to be gotten
oAttach = null;
}
return oAttach;
}
Just putting this on here in case anybody else runs into the same issue. Outlook 2K7 has a Level1 file type feature that blocks access to attachments with specific extensions.
However, you can change the registry to allow access to these files. Just remember to set it back to the way it was prior to you modifying it for security's sake.
private void SetLevel1RemoveValues()
{
// Get the base key for the current user HKEY_CURRENT_USER
Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.RegistryKey.OpenRemoteBaseKey(Microsoft.Win32.RegistryHive.CurrentUser, "");
// Get the security key from the registry
Microsoft.Win32.RegistryKey subKey = regKey.OpenSubKey("Software\\Microsoft\\Office\\" + sCurrentOutlookVersion + ".0\\Outlook\\Security", true);
// If the Outlook\Security key doesn't exit, create one
if (subKey == null)
subKey = regKey.CreateSubKey("Software\\Microsoft\\Office\\" + sCurrentOutlookVersion + ".0\\Outlook\\Security");
// Loop through each Value in the registry to see if the Level1Remove key already exists.
string[] sValues = subKey.GetValueNames();
bool bHasLevel1RemoveKey = false;
foreach (string sValue in sValues)
if (sValue == "Level1Remove")
bHasLevel1RemoveKey = true;
// If the key already exists, store the data so we can reset it later
if (bHasLevel1RemoveKey)
sPrevLevel1RemoveValues = subKey.GetValue("Level1Remove").ToString();
else
sPrevLevel1RemoveValues = "";
// Create an array of all Level 1 Extensions
string[] level1Extensions = new string[] { ".ade", ".adp", ".app", ".asp", ".bas", ".bat",
".cer", ".chm", ".cmd", ".com", ".cpl", ".crt", ".csh", ".exe", ".fxp", ".gadget",
".hlp", ".hta", ".inf", ".ins", ".isp", ".its", ".js", ".jse", ".ksh", ".lnk",
".mad", ".maf", ".mag", ".mam", ".maq", ".mar", ".mas", ".mat", ".mau", ".mav", ".maw",
".mda", ".mdb", ".mde", ".mdt", ".mdw", ".mdz", ".msc", ".msi", ".msp", ".mst", ".ops",
".pcd", ".pif", ".pfr", ".prg", ".pst", ".reg", ".scf", ".scr", ".sct", ".shb", ".shs",
".tmp", ".url", ".vb", ".vbe", ".vbs", ".vsmacros", ".vss", ".vst", ".vsw",
".ws", ".wsc", ".wsf", ".wsh" };
// Set the value in the registry to the list of all Level 1 extensions so we can extract them
subKey.SetValue("Level1Remove", string.Join(";", level1Extensions));
// Close (and save) the values
subKey.Close();
regKey.Close();
}

Categories