I asked a question the other day regarding overlay icons. With help, I figured out how to get that working.
Here's how an icon overlay works (as far as I understand): Before the shell draws an icon it contacts all the icon overlay handlers in the system to determine whether it should draw an overlay on the that particular icon.
My setup:
I have a registered Shell Extension (Icon Overlay Handler) that I want to use to display icon overlays. Also, I have a .NET application (C#) that will write to a database (SQLite, most likely) with the names, etc. of all the files and folders I want to display an overlay on.
My problem is:
How do I get the Shell Extension (I think its basically a COM DLL) to call back into my .NET application? Or is that overkill and should I just have the Shell Extension read from the database directly?
Possible solutions?
Have the Shell Extension (icon overlay handler) read the database and determine whether to show overlay.
Have the Shell Extension call back into a .NET application to determine whether to show the overlay.
I hope this makes sense, if not, I'll try to elaborate.
A COM DLL cannot talk to .NET assembly directly. You might need to expose your .NET assembly as COM object and talk to this COM object instead. But this might in fact be an overkill in your scenario. Another option would be to expose the functionality that talks to the database in your .NET assembly as some interoperable service (WCF?) that might be called from the shell etension.
Yes, if you mark your assembly as COM visible and run regasm, then your COM dll can import the generated type library and call CoCreateInstance to get a reference to your .NET classes.
HOWEVER, it is a little scary to pull the .NET framework into a shell extension. So you might want to make sure that the .NET code is invoked out-of-process... ie CLSCTX_LOCAL _SERVER to CoCreateInstance.
Related
I've been asked to create a little tool to help automate a basic 3rd party WinForms application.
So far I've managed to overcome many hurdles but this one is by far one of the most frustrating of them all (And spending 8 hours researching only to find out LVM_GETITEMTEXT was returning an LVITEM struct with 64-bit pointers was very frustrating) - I can't seem to find any way at all to get any kind of reference to a ToolStrupStatusLabel in the third party application's StatusStrip.
The only indication I have that the application has finished it's assigned task is when the StatusStrip is updated to show it has been finished. I can't reliably automate it's operation if I can't find out when it finishes one job and proceeds to another.
Is there any message I can SendMessage() to the application? Any function I can call? Anything that will help me locate the text on this label so I can gain some insight into the application's status?
The automation tool is programmed in C#/Winforms with pInvoke for various Windows functions. I've also created my own DLL in C++ to assist with obtaining data from the LVITEM struct, so C++ workarounds are possible too.
This isn't going to work. The ToolStripItem derived classes are special, they do not derive from Control. They don't have their own window handle, they use the window of their host to draw themselves. Where the host is a Control, like ToolStrip or StatusStrip in your case.
This makes them unusable from traditional UI automation tools that require a window handle. The only way to commandeer them is by injecting a DLL that uses reflection to get a ToolStripItem reference. This exists, the Managed Spy++ tool uses this technique. Source code is provided so you can put your own together, you'll want to leverage the ManagedSpyLib which does the heavy lifting.
I've been futzing with this for a while now and am getting close to concluding that what I am trying to do isn't possible, but I wanted to give the folks at Stack Overflow a chance to hopefully prove me wrong before moving on to an alternate strategy.
What I am trying to do
My project is a .NET assembly that is exposed to COM as an ActiveX control (Control A) that is intended to run in the browser. It has a dependency on a third-party ActiveX control (Control B) that I am trying to use via Registration Free COM from Control A.
So the desired stack looks like this:
Internet Explorer
[COM]
Ax Control A (My Control)
[Reg-Free COM]
Ax Control B (third-party)
Why I am trying to do this
I want to use registration-free COM because of a versioning conflict with another application that uses Control B combined the fact that Control B didn't implement versioning correctly (two incompatibile versions exist with the same GUID). Registration-free COM seems like the only feasible way to isolate the two versions of Control B from each other.
I do not need for the browser to call my control (Control A) via registration-free COM, I just planned on using the normal mechanism for that.
What I've done so far
Given that the browser is the ultimate application that is running this whole stack, and that it isn't practical or advisable to have the users add a manifest file for Internet Explorer, my approach has been to embed the manifest into Control A to make it call Control B using registration-free COM.
I have managed to embed the manifest into Control A and used a third-party tool to verify that it is indeed embedded. To simplify things for my testing I took the browser out of the equation and have been testing the registration-free COM from a simple C# forms application. However, I can't seem to get the registration-free COM working in that environment.
For test purposes I created a manifest for the test forms application with the information I am embedding in Control A and in that configuration it works with or without Control B registered. Which is great, if my application was going to run in that test application instead of the browser. I did this test just to confirm the manifest I was embedding was correct, which I believe I have confirmed.
What Not Working Means
The test Windows Forms application runs perfectly and displays Control A and (nested) Control B, while Control B is registered. However, when I unregister Control B and try to rely on registration-free COM, the application immediately throws this error (UFV=Control A):
Description: The process was terminated due to an unhandled exception.
Exception Info: System.Runtime.InteropServices.COMException
Stack:
at System.Windows.Forms.AxHost.CreateInstance()
at System.Windows.Forms.AxHost.GetOcxCreate()
at System.Windows.Forms.AxHost.TransitionUpTo(Int32)
at System.Windows.Forms.AxHost.CreateHandle()
at System.Windows.Forms.Control.CreateControl(Boolean)
at System.Windows.Forms.Control.CreateControl(Boolean)
at System.Windows.Forms.AxHost.EndInit()
at UniversalFileViewer.UFV.InitializeComponent()
at UniversalFileViewer.UFV..ctor()
at TestFormsProject.TestForm.InitializeComponent()
at TestFormsProject.TestForm..ctor()
at TestFormsProject.Program.Main()
My Question(s)
(1) Am I barking up the wrong tree? That is, is it even possible for to use registration-free COM in the middle of the stack like I am attempting or does the manifest have to be embedded in the EXE file itself (or in a manifest file)?
(2) If it isn't possible to do this, why does the manifest merge tool (MT.EXE) even allow you to embed a manifest into a DLL file at all?
(3) If it is possible, am I missing a step somewhere? Is there a trick to doing this?
I have a managed application TestApplication.exe in C# and Application.EnableVisualStyles() is allready called.
I have a Class Library MySharedCode.dll also in C# which uses [DLLImport()] to import some External dialogs out of an unmanaged dll.
Well, now I am using (add reference) MySharedCode.dll in my TestApplication.exe and call a function MyTestConfigDlg() out of it. TestClass.MyTestConfigDlg();
OK, everything works fine and I get my dialog, but the dialog has NO XP style/themes?
I just wanted to see if it's general problem with managed/unmanged modules, so I used the [DLLImport()] to call the same MyTestConfigDlg() dialog but this time directly in my TestApplication.exe! WOW! Worked as I expected. The Dialog was in XP Style/Themes!
so, anybody here who can help me out?
FYI: I also tried (just for test) to call MessageBoxA() API call in my Class Library Dll which later called by my TestApplication.exe and the MessageBoxA() had also no Style/Themes!
Thanks in advance!
Usage of the Application.EnableVisualStyles() applies to certain windows controls such as ListBox, ListView, Menu, Buttons, to make it in line with the XP themes control from the start, if it was running on Vista and later, it would conform the controls to that style also. In short I do not know how do you mean the dialog has no XP/Themes support when invoked directly via the References, yet when you used DllImport keyword to import the function it worked, that is unusual. Usually the usage of DllImport is for unmanaged code API, but somehow it picked it up...I do recall that there was a bug with the .NET 1.1 framework in that if you called Application.EnableVisualStyles(), it failed to work, unless a call to Application.DoEvents() was invoked between enabling the Visual styles and instantiating a winforms, maybe in your case, when instantiating a dialog, perhaps that could solve it by calling Application.DoEvents(), other than that, I am out of ideas...
Hope this helps,
Best regards,
Tom.
Those two useful classes are both under the System.Windows.Forms reference....
I can't see much relation between those and winforms.. Does anybody know why they're there?
thanks.
They internally use Win32 platform APIs, on which WinForm was built.
Windows Forms was, when it was made, the ONLY (Microsoft) means of creating a graphical user interface on the desktop.
SendKeys and the Clipboard are both using the Windows API in order to manipulate GUI applications. When this was created, it was reasonable to assume that these would be used from within a GUI program, which (then) meant a Windows Forms application.
Neither of these would typically be used from a Console application, but if you were doing so, including the "windowing" assemblies (which, at the time, meant windows forms) was a reasonable thing to do, since you're working with the Windowing system.
I do agree, though, that now that WPF exists, it would be nicer to have these in a separate assembly. However, Microsoft is very good about maintaining backwards compatibility.
To this end, they left this in the Windows Forms namespaces, but also implemented System.Windows.Clipboard for WPF applications. (I believe they decided that SendKeys was not required in modern development, since it's kind of abused, and just left it out by design.)
Generally speaking, you would not use Clipboard or SendKeys with an ASP.Net application or a console application, so it makes total sense for them to be in System.Windows.Forms.
Where would you expect them to be? In System.ClipboardAndSendKeys?
SendKeys can be handy for highlighting of textboxes. SendKeys "{HOME}+{END}" is a typical technique carried over from Visual Basic once a textbox has focus.
The Clipboard class is useful because it allows you to get data stored on a machine's clipboard, especially useful if it's data that comes from another application running. The clipboard is expected behavior in almost all applications that have any copy/paste semantic.
What's the easiest/best way to register your program in explorers right-click menu using .NET and C#?
i.e. I would like to be able to right-click on an item in windows explorer and get a "Edit with MyProgram"
This is the closest thing to a tutorial I could find but it mostly just dips into Win32 from .NET and is also outdated. How should this be done now?
If you just want to add menu items, then a shell extension is overkill. You can register a command line in the registry which will run your exe with the selected file(s) as the parameter. Shell extensions are really only required if you want to change explorer's behavior, add custom icons, or hook shell based file operations.
http://www.codeproject.com/KB/shell/SimpleContextMenu.aspx
If a shell extension is what you need, you're best writing a thin wrapper in unmanaged code that calls out to another process that is your .NET application through some sort of cross process communication channel. Due to all the potential versioning issues, it's not recommended to load the .NET runtime into the explorer process.