Stop SetVolumeMountPoint from opening file explorer - c#

I am using SetVolumeMountPoint to mount a vhd to a drive letter of my choosing. The problem is that when the vhd is mounted file explorer automatically opens at the new drive directory. This is a problem for me as I need my programs to remain on the foreground and sometimes the spawned file explorer becomes part of the foreground.
https://learn.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-setvolumemountpointa
Thoughts?
UPDATE:
I programmatically set the noautorun registry key using these two methods before mounting my vhd:
/// <summary>
/// Removing file explorer auto run for the given DriveLetter so that when a vhd is mounted file explorer doesn't open
/// </summary>
/// <param name="DriveLetter"></param>
private void RemoveFileExplorerAutoRun(char DriveLetter)
{
var KeyPath = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer";
RegistryKey AutoRunKey = Registry.CurrentUser.OpenSubKey(KeyPath, true);
var DriveLetterValue = DriveLetter - 'A';
if (AutoRunKey != null)
{
RemoveFileExplorerAutoRun(AutoRunKey, DriveLetterValue);
}
else // create key as it does not exist
{
AutoRunKey = Registry.CurrentUser.CreateSubKey(KeyPath);
RemoveFileExplorerAutoRun(AutoRunKey, DriveLetterValue);
}
}
private void RemoveFileExplorerAutoRun(RegistryKey AutoRunKey, int DriveLetterValue)
{
if (AutoRunKey != null)
{
AutoRunKey.SetValue("NoDriveTypeAutoRun", DriveLetterValue);
AutoRunKey.Close();
}
}

Cleanest way seem to be to catch RegisterWindowMessage("QueryCancelAutoPlay") message by your foreground window and return TRUE from your window procedure.
https://learn.microsoft.com/en-us/windows/desktop/shell/autoplay-reg
EDIT:
If foreground window is not your application window, then I would recommend against editing registry, since it is global state, whereas you need just temporary autorun bypass.
Besides windows hook, mentioned in other answer, I would suggest registering your implementation of IQueryCancelAutoPlay interface in running object table

Another way is using Registry.
Please reference "Using the Registry to Disable AutoRun" "How to disable the Autorun functionality in Windows"
Note
The NoDriveAutoRun and NoDriveTypeAutoRun values should only be
modified by system administrators to change the value for the entire
system for testing or administrative purposes. Applications should not
modify these values, as there is no way to reliably restore them to
their original values.
The third way is based on #Alexander Gutenev have pointed out that register a "QueryCancelAutoPlay" window message and then install a global hook from your application to monitor this message.
Note
You should use global hooks only for debugging purposes; otherwise,
you should avoid them. Global hooks hurt system performance and cause
conflicts with other applications that implement the same type of
global hook.
Hooks tend to slow down the system because they increase the amount of
processing the system must perform for each message. You should
install a hook only when necessary, and remove it as soon as possible.

Related

How to self-register a standalone desktop C# WPF app (distributed as an exe) for local toast notifications?

We have a desktop Windows app (written in WFP/C#) that we distribute as a single .exe file with no installer (it bundles all its dependencies via a Fody/Costura plugin).
We would like to integrate a local Action Center toast functionality where the app can display a toast and respond to it when it's clicked.
Displaying the toast is straightforward and can be done by using the Microsoft.Toolkit.Uwp.Notifications nuget package. However, in order to actually receive proper notifications when the toast is clicked in the Action Center (as opposed to the balloon tip) we need to register with notification platform.
The guide on how to do this seems to be focused on apps with an installer (e.g. Wix): https://learn.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/send-local-toast-desktop?fbclid=IwAR2AoHRKI88VNGRG-pTUytwhkMuovWT4bEr0RoXEayWpWsoGlghtZeq4Mo4#step-4-register-with-notification-platform
The specific task we're trying to achieve is, from the documentation:
If you're using classic Win32 (or if you support both), you have to declare your Application User Model ID (AUMID) and toast activator CLSID (the GUID from step #3) on your app's shortcut in Start.
How can we do it without writing an installer? We would like our app to do this registration on first run.
Note: the app already has provisions for elevating itself through UAC if needed by restarting itself in Administrator context.
Additional references: WPF native windows 10 toasts
[Update]
I managed to follow the instructions in https://learn.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/send-local-toast-desktop
and https://learn.microsoft.com/en-us/windows/win32/shell/enable-desktop-toast-with-appusermodelid to put together what should have been a working solution, but in the end, clicking on toasts in the Action Center does not trigger OnActivated() in my NotificationActivatior.
Salient points:
Sending notification
var toast = new ToastNotification(toastXml);
DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
Registration:
string shortcutPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Programs),
"Toasty.lnk");
DesktopNotificationManagerCompat.RegisterAumidAndComServer
<MyNotificationActivator>(AppName);
DesktopNotificationManagerCompat.RegisterActivator
<MyNotificationActivator>();
if (!File.Exists(shortcutPath))
{
ShortcutManager.RegisterAppForNotifications(
shortcutPath,
Assembly.GetExecutingAssembly().Location,
null,
AppName,
ActivationId);
}
Creating a shortcut
public static void RegisterAppForNotifications(
string shortcutPath,
string appExecutablePath,
string arguments,
string appName,
string activatorId)
{
var shellLinkClass = new ShellLinkCoClass();
IShellLinkW shellLink = (IShellLinkW)shellLinkClass;
shellLink.SetPath(appExecutablePath);
IPropertyStore propertyStore = (IPropertyStore)shellLinkClass;
IPersistFile persistFile = (IPersistFile)shellLinkClass;
if (arguments != null)
{
shellLink.SetArguments(arguments);
}
// https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-id
propertyStore.SetValue(
new PropertyKey("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3", 5),
new PROPVARIANT(appName));
// https://learn.microsoft.com/en-us/windows/win32/properties/props-system-appusermodel-toastactivatorclsid
propertyStore.SetValue(
new PropertyKey("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3", 26),
new PROPVARIANT(new Guid(activatorId)));
propertyStore.Commit();
persistFile.Save(shortcutPath, true);
}
[Update]
Finally got it to work - not sure what was wrong before, but the final version seems to be okay. Full code: https://gist.github.com/davidair/c4ea207bf6eece4ef08b97ab29a3036f
I have the same problem with my project now.
Managed to find this repository - https://github.com/felixrieseberg/electron-windows-interactive-notifications
Here's C++ implementation for installing shortcut (InteractiveNotifications file, InstallShortcut method). I guess the problem is how we set the value to PropertyStore, string GUID is not suitable for some reason. Still, I wasn't able to solve the problem for now.
UPDATED: Finally, was able to install shortcut from code! Check my example at Github. https://github.com/romayavorskyi/WpfNotificationTest (still a lot of hardcode, but it should give you the general idea). And you were right, shortcut path matters. It seems shortcut should be in the ProgramData folder for correct work.

Intercept MS Windows 'SendTo' menu calls?

SCENARIO
I manage and organize many files during the day, the SendTo is the most used feature that I use on Windows.
PROBLEM
By default, when the user clicks an item/link of the contextmenu to send the files, the O.S does not show any kind of advise/notifier indicating that the files are copying to the selected destination.
I consider it a very wrong design issue because for big files its OK ...a progressbar will be shown, but if the files are to small it will not show any progressbar/visual indicator so is not possible to ensure that the files are copied (without manual effort) because I'm human and I could click outside the SendTo contextmenu by error.
So, I would like to develop a personal mini-tool that will help me to optimize my time showing me a notifier window wherever on the screen when I send/copy files using the SendTo feature from the contextmenu, and only the SendTo feature.
QUESTION
In just simple words, I want to detect a copy/send operation from SendTo menu to ensure that the click was done properly on the menu item (and not outside the menu), by also providing additional basic info such as the source folder, the destination folder, and the amount of files or the filepaths.
Any ideas to start developing this tool in the right direction?.
I will be grateful for a code example in C# or else VB.Net, preferably this last.
APPROACH
Since I don't know how to start doing this I mean which could be the easiest or the efficient way to intercept those SendTo calls, firstly I thought to hook the CopyFile or CopyFileEx API functions, but they do not provide the information that I need because that function will be called in any kind of copy operation and not only when I use the SendTo Feature, so I'm lost.
I'm not sure if I should investigate more about internal calls, or maybe investigate more about the windows contextmenu itself instead of messing with function hooks and ugly things that I could avoid.
My main idea is to develop a hidden WinForms (or else a windows service) that stays in background waiting for when I use the SendTo feature (when I click on an item of the SendTo menu) and then show any kind of visual indicator on the screen to ensure that I properly clicked that menu-item and maybe inform about the amount of files that I'm moving and where I'm moving them.
RESEARCH
Here is a code example that I think it demostrates how to instantiate the SendTo com object to create your own?, but its written in c++ and I'm not sure if the example is helpful because my intention is not to replace the SendTo menu but I'll keep this useful info here it it serves for something else:
How to add(enable) standard "Send To" context menu option in a namespace extension
The KNOWNFOLDERID constants docs gives some useful info about the SendTo folder, again I'm not sure if this could help maybe for a read/access monitoring approach?, I just keep the info here:
GUID: {8983036C-27C0-404B-8F08-102D10DCFD74}
Default Path: %APPDATA%\Microsoft\Windows\SendTo
Legacy Default Path: %USERPROFILE%\SendTo
In the Shell Extension Handlers docs there is a Copy hook handler which I don't know if it has relation with the SendTo's COM component and if that could help me in some way,
the same ignorance for IContextMenu::InvokeCommand method reference which maybe I could intercept it to identify a SendTo invocation?
By the moment I feel like flying blind.
I recently found this A managed "Send To" menu class but again its a example written in C/C++ (I think is the same source before) which I don't understand at all and again I'm not sure if that could help me because I repeat that replacing SendTo is not what I have in mind (just because I don't know how to properly do it avoiding all possible risks, I prefer to still let Windows logic copy/send the files, I just want to detect the copy operation to retrieve info)
EXPECTED RESULTS AND USAGE
Step 1:
Select a random file and use the SendTo menu (in my language, Spanish, the command name is 'Enviar a')
Step 2:
Let the .net application's logic (working in background) intercept the SendTo operation to retrieve info.
(I only need help with this step)
Step 3:
Display the info somewhere over the screen to ensure that the SendTo operation was performed, to ensure that I properly clicked the SendTo item (My Link).
(That popup is just a simulation, I don't know any way to retrieve all that info)
It's really simple to do once you understand what SendTo really does, and it doesn't involves COM or shell extensions at all. Basically, the send to menu is populated with the content of the SendTo folder of the user profile (C:\Users\\AppData\Roaming\Microsoft\Windows\SendTo by default in Windows 6.x).
When clicked, if the option is a shortcut to a folder it will copy the files there, but if there is a shortcut to a program (or a program executable itself) it will run that program, passing the paths of the selected files as command-line arguments.
From there, it's really trivial to make some program that simply takes paths as arguments, present some kind of notification and then copies the files or do whatever you want with them.
A quick and dirty example could be as follow (in C#, but could be done with anything else really):
private static void Main(string[] args)
{
if(MessageBox.Show("Are you sure you want to copy files?", "Copy files", MessageBoxButtons.YesNo) == DialogResult.No) return;
foreach (string file in args)
File.Copy(file, Path.Combine("c:\\temp", Path.GetFileName(file));
}
This just ask for confirmation for copying a bunch of files. Note that this really doesn't "intercepts" the send to menu, but rather handles it completely, so it's the program responsability to do any meaningful action. A more serious implementation could use the built-in Windows copy dialog and display some screen with progress or anything else, that's up to your needs.
It could also take some more parameters on the command line. When you place a shortcut in the SendTo folder, the destination could add some more parameters that will be passed as the first ones (before the file names). For example the destination of the shortcut can read c:\program files\copyfiles.exe c:\temp to pass the destination folder instead of hardcoding. The called program must then interpret the first parameter as the destination path and subsequent ones as the source files.
I've had to do something like this before. You don't even have to intercept the SendTo() function, you only need to make sure the the file has arrived. How about FileSystemWatcher if it's on the same computer?
You could use a watcher to watch before you send it, then, if the file successfully arrives at it's destination, you can display a successful message, and then kill the watcher.
Code Example
// Create a FileSystemWatcher property.
FileSystemWatcher fsw { get; set; }
// So we can set the FileToWatch within WatchFilesBeforeTransfer().
private string FileToWatch { get; set; }
private void WatchFilesBeforeTransfer(string FileName, string DestinationFolder)
{
fsw = new FileSystemWatcher();
fsw.Path = DestinationFolder;
FileToWatch = FileName;
// Only if you need support for multiple directories. Code example note included.
fsw.InclueSubdirectories = true;
// We'll be searching for the file name and directory.
fsw.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName
// If it's simply moving the file to another location on the computer.
fsw.Renamed += new RenamedEventHandler(FileRenamed);
// If it was copied, not moved or renamed.
fsw.Created += new FileSystemEventHandler(FileCreated);
fsw.EnableRaisingEvents = true;
}
// If the file is just renamed. (Move/Rename)
private void FileRenamed(Object source, RenamedEventArgs e)
{
// Do something.
// Note that the full filename is accessed by e.FullPath.
if (e.Name == FileToWatch)
{
DisplaySuccessfulMessage(e.Name);
KillFileWatcher();
}
}
// If creating a new file. (Copied)
private void FileCreated(Object source, FileSystemEventArgs e)
{
// Do something.
// Note that the full filename is accessed by e.FullPath.
if (e.Name == FileToWatch)
{
DisplaySuccessfulMessage(e.Name);
KillFileWatcher();
}
}
private void KillFileWatcher()
{
fsw.Dispose();
}
You can access the desired property information (like in your popup gif) in this way:
Folder name: Path.GetDirectory(e.FullPath); (like "C:\yo\")
Full file name: e.FullPath (like "C:\yo\hey.exe")
File name: e.Name (like "hey.exe")
Non-code execution process:
Before you initiate SendTo(), create an instance of the FileSystemWatcher property, and have it watch for a specific Folder/File name combination, which should show up in the watched folder: WatchFilesBeforeTransfer(FileName, DestinationFolder).
Initiate SendTo().
File received? DisplaySuccessfulSendToMessage(), KillFileWatcher();
???
Profit.
UPDATE:
I just realized that's just for one file. If you want to check for multiple files, you could either create multiple FileWatcher instances (not recommended), or use a List<string> object, like this:
private void SendTo(List<string> FileCollection)
{
// Clear your previous FileList.
FileList.Clear();
foreach (string file in FileCollection)
{
FileList.Add(file);
}
// Rest of the code.
}
List<string> FileList { get; set; }
private void WatchFilesBeforeTransfer(string DestinationFolder)
{
// Same code as before, but delete FileToWatch.
}
private void FileRenamed(Object source, RenamedEventArgs e)
{
foreach (string file in FileList)
{
if (e.Name == file)
{
// Do stuff.
}
}
}
private void FileCreated(Object source, FileSystemEventArgs e)
{
foreach (string file in FileList)
{
if (e.Name == file)
{
// Do stuff.
}
}
}
Hope this helps!
I'm afraid this ain't that easy.
I was playing around with the FileSystemWatcher on this, but with only partly success.
Something that should definitely work are File system drivers but this looks like just too, well, look at it...
In the end it might be the easiest way to write your own shell extension to access the SendTo folder, and use this instead of the SentTo command which would give you full control.
These might be some starters:
Windows shell extensions
Shell Context Menus
Maybe I come a little bit late to answer my own question, which was published on year 2015, but it wasn't until few days ago that I became interested in this matter again, with much more experience and knowledge gained in .NET after these years to start from scratch and try to understand everything that I did not understood in the past.
I just discovered that, as #Ňɏssa Pøngjǣrdenlarp already commented in the comments box, apparently the most viable way to accomplish this would be to implement my own SendTo context menu and use IFileOperationProgressSink interface to report progress, which for this firstly I need to depend on the usage of IFileOperation interface.
The reason to use the IFileOperation interface is because it seems the only way offered in the Windows API to let the developer perform multiple file operations (copy, move, rename, create or delete) all at once within the same progress dialog UI. This is probably the interface used by the system when the user selects multiple files or directories (via the SendTo menu or just CTRL+C and CTRL+V) to move or copy them at once, because it only shows one progress dialog with all the copy operations queued in it...
So clearly IFileOperation and IFileOperationProgressSink interfaces were what I need. But from what I know there is no managed implementation of these interfaces in the .NET framework namespaces (neither in the Microsoft's WindowsAPICodePack library), which seems somewhat inexcusable to me considering that these interfaces exists since the era of Windows VISTA or even earlier, and it is an indisputable improvement being the totally opposite of any built-in members that you can think of to perform copy, move, rename, create or delete operations, like for example System.IO.File.Copy or Microsoft.VisualBasic.FileIO.FileSystem.CopyFile method. All of them only supports a single operation and only on a single progress dialog at once.
So I focused to investigate on that suggested solution, and I ended up finding a good implementation of IFileOperation and IFileOperationProgressSink interfaces in this repository:
https://github.com/misterhaan/au.Shared/tree/master/IO/Files.FileOperation
And this one which is the original implementation that I found on a old Microsoft's article which also comes with a good PDF reading to learn some things:
https://github.com/mlaily/MSDNMagazine2007-.NET-Matters-IFileOperation-in-Windows-Vista
https://learn.microsoft.com/en-us/archive/msdn-magazine/2007/december/net-matters-ifileoperation-in-windows-vista
Actually, for what I've discussed in this thread to do since year 2015, delving into the use of the IFileOperationProgressSink interface to report progress would not be necessary (only if I really want a deep progress information), since it is enough to determine that the copy was started / the call to IFileOperation.PerformOperations function was performed, and if any problems occur during the copy then it will appear in the progress dialog UI.
But of course what is still necessary is to develop a shell-extension of a custom SendTo menu to replace the one built into Windows. Shell-extensions could be developed with SharpShell library.
I develop in VB.NET language. I managed to extend and document their IFileOperation implementation and the wrapper, and updated the enums adding the newer, missing values added for Windows 7 and Windows 8.
If it can be helpful for someone, I'm going to attach the IFIleOperation and the wrapper in Vb.NET all in a new answer (because it exceeds the maximum character limit allowed for a post).
Note that in my implementation of IFileOperation interface and the wrapper class with name FileSystemOperation you will find some return types and missing classes or methods (like HRESULT return type or NativeMethods class), I just can't share all in one place, but these missing things are things that any experienced programmer will know how to resolve (eg. change HRESULT to UInteger type, and go to Pinvoke.net to find any missing method from my NativeMethods class).
UPDATE
It seems that StackOverflow doesn't allow me to add another answer, so I'll upload my implementation on PasteBin instead:
Class FileSystemOperation
https://pastebin.com/nvgLWEXu
Interface IFileOperation
https://pastebin.com/GzammHtu
Interface IFileOperationProgressSink
https://pastebin.com/jf9JjzyH
Class ComObjectDisposer(Of T As Class)
https://pastebin.com/7mPeawWr
Enum TransferSourceFlags
https://pastebin.com/V7wSSEvv
Enum FileOperationFlags
https://pastebin.com/A223w9XY
That's all.

Count the number of times the Program has been launched

How can I get the number of times a program has previously run in c# without keeping a file and tallying. Is there a Application class or something in c# to check the count.
Please give a detailed explantion as i know nothing about it.This is A windows console application not windows forms.
You can do that my creating an Entry in the Registry. And another way is by using an Application Settings.
But I prefer Application Settings because it has less task to do.
See HERE: Creating an Application Settings.
Tutorial From Youtube
Recent versions of Windows automatically maintain this information in the registry under HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist.
The data is obfuscated with ROT13, but that's easy to "decrypt". A free utility (with source code) is available and can serve as your starting point.
You could send a message to a database or webservice every time the program starts up (assuming there's a network connection).
You could keep a count on some form of hardware thet's not a standard storage device (therefore not technically being a file).
You could make a registry entry that you keep the count in (if you ignore the fact that the registry entry is, at some level, persisted into a file somewhere).
You could just have a file somewhere that keeps track of the count. Not sure why you're so opposed to this one in the first place....
If you are running a Winforms application, the you can easily use the Application Settings. Right click on your Solution Name --> Properties --> Settings Tab. More info and tutorial here.
Then, every time your program starts, increment this setting and save it.
Ref: Count the number of times the Program has been launched
In my knowledge Windows does not keep this information for you. You would have to tally the value somewhere (file, database, registry setting).
Better way is Application Settings as:
Create setting in app.config and then use it as:
Properties.Settings.Default.FirstUserSetting = "abc";
then, you usually do this in the Closing event handler of the main form. The following statement to Save settings method.
Properties.Settings.Default.Save();
Implementation using Registry:
static string AppRegyPath = "Software\\Cheeso\\ApplicationName";
static string rvn_Runs = "Runs";
private Microsoft.Win32.RegistryKey _appCuKey;
public Microsoft.Win32.RegistryKey AppCuKey
{
get
{
if (_appCuKey == null)
{
_appCuKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(AppRegyPath, true);
if (_appCuKey == null)
_appCuKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(AppRegyPath);
}
return _appCuKey;
}
set { _appCuKey = null; }
}
public int UpdateRunCount()
{
int x = (Int32)AppCuKey.GetValue(rvn_Runs, 0);
x++;
AppCuKey.SetValue(rvn_Runs, x);
return x;
}
If it's a WinForms app, you can hook the Form's OnClosing event to run UpdateCount.
Then Check tutorial to Read, write and delete from registry with C#

How to get selected text from an active application, without using a clipboard

What am I doing:
My main intent is to enable user friendly text to speech for personal use on Win 7. Approach should work in Google Chrome, VS and Eclipse.
Code example:
Following code creates global keyboard hook for ctrl + alt + space, called hookEvent. If event fires, it starts/stops speaking clipboard contents ( that can be updated with ctrl + c ).
/// <summary>
/// KeyboardHook from: http://www.liensberger.it/web/blog/?p=207
/// </summary>
private readonly KeyboardHook hook = new KeyboardHook();
private readonly SpeechSynthesizer speaker = //
new SpeechSynthesizer { Rate = 3, Volume = 100 };
private void doSpeaking(string text)
{
// starts / stops speaking, while not blocking UI
if (speaker.State != SynthesizerState.Speaking)
speaker.SpeakAsync(text);
else
speaker.SpeakAsyncCancelAll();
}
private void hookEvent(object sender, KeyPressedEventArgs e)
{
this.doSpeaking(Convert.ToString(Clipboard.GetText()));
}
public Form1()
{
InitializeComponent();
hook.KeyPressed += new EventHandler<KeyPressedEventArgs>(hookEvent);
hook.RegisterHotKey(ModifierKeysx.Control|ModifierKeysx.Alt, Keys.Space);
}
Question:
I would prefer not using the clipboard. Or at least, restoring the value after, something like:
[MethodImpl(MethodImplOptions.Synchronized)]
private string getSelectedTextHACK()
{
object restorePoint = Clipboard.GetData(DataFormats.UnicodeText);
SendKeys.SendWait("^c");
string result = Convert.ToString(Clipboard.GetText());
Clipboard.SetData(DataFormats.UnicodeText, restorePoint);
return result;
}
What are my options?
Edit:
To my surprise, I found that my clipboard reader is the best way to go. I created a notification area app, that responds to left click (speaking clipboard) and right click (menu opens up). In menu the user can chance speed, speak or create a audio file.
MS provide accessibility tools that do cover what you're trying to do. If you take a look at documents about screen scraping. In short, every component is accessible in some manner, if you use some of the windows debugging tools you can get to see the component names/structures within. You can then use that, however, its complicated as most times you would need to be very specific for each application you intend to scrape from.
If you manage to scrape you dont need to use the clipboard, as you can access the text property of the apps direct. Its not something I've had to do, hence, Ive no code to offer off the top of my head, but the term "screen scraping" should point you in the right direction.
If to expand a little on what Bugfinder said, Microsoft provider a UI Automation Framework to solve problems like the one you mentioned:
In particular you can use the TextSelectionChangedEvent of TextPattern:
The problem with this solution is that it only works on supported operating systems and applications - and not all support this.
Your clipboard solution is acceptable for applications that do not provide a good automation interface.
But for many applications the UI Automation Framework will work well and will provide you with a far better solution.

Monitor file selection in explorer (like clipboard monitoring) in C#

I am trying to create a little helper application, one scenario is "file duplication finder". What I want to do is this:
I start my C# .NET app, it gives me an empty list.
Start the normal windows explorer, select a file in some folder
The C# app tells me stuff about this file (e.g. duplicates)
How can I monitor the currently selected file in the "normal" windows explorer instance. Do I have to start the instance using .NET to have a handle of the process. Do I need a handle, or is there some "global hook" I can monitor inside C#. Its a little bit like monitoring the clipboard, but not exactly the same...
Any help is appreciated (if you don't have code, just point me to the right interops, dlls or help pages :-) Thanks, Chris
EDIT 1 (current source, thanks to Mattias)
using SHDocVw;
using Shell32;
public static void ListExplorerWindows()
{
foreach (InternetExplorer ie in new ShellWindowsClass())
DebugExplorerInstance(ie);
}
public static void DebugExplorerInstance(InternetExplorer instance)
{
Debug.WriteLine("DebugExplorerInstance ".PadRight(30, '='));
Debug.WriteLine("FullName " + instance.FullName);
Debug.WriteLine("AdressBar " + instance.AddressBar);
var doc = instance.Document as IShellFolderViewDual ;
if (doc != null)
{
Debug.WriteLine(doc.Folder.Title);
foreach (FolderItem item in doc.SelectedItems())
{
Debug.WriteLine(item.Path);
}
}
}
You can do this with the shell automation interfaces. The basic process is to
Run Tlbimp on Shdocwv.dll and
Shell32.dll (or directly add a
reference from VS).
Create an
instance of the ShellWindows
collection and iterate. This will
contain both Windows Explorer and
Internet Explorer windows.
For
Windows Explorer windows, the
IWebBrowser2.Document property will
return a IShellFolderViewDual
reference.
The IShellFolderViewDual
has a SelectedItems method you can
query and an event for changes you
can handle.

Categories