Icon.FromHandle: should I Dispose it, or call DestroyIcon? - c#

I use Win32 SHGetFileInfo to get a handle to the icon belonging to a certain file. There are a lot of descriptions how to do this, also on stackoverflow, for instance: Get icons used by shell
After calling the function you have a struct with the handle to the Icon. Using the static method Icon.FromHandle I can convert it to an object of class System.Drawing.Icon. This class implements System.IDisposable. Proper usage would be like:
using (Icon icon = Icon.FromHandle(shFileInfo.hIcon))
{
// do what you need to do with the icon
}
Upon leaving the using statement the icon object is disposed.
MSDN warns in the description of Icon.FromHandle (click to view):
When using this method, you must dispose of the original icon by using the DestroyIcon method in the Win32 API to ensure that the resources are released.
And in Icon.Dispose (click to view)
Releases all resources used by this Icon.
Question:
Is it enough to Dispose() the object, or should I call both Dispose() and DestroyIcon, or maybe call DestroyIcon instead of Disposing the object?

The .NET Icon class is remarkably clumsy, taking care of this yourself is required. The MSDN article for SHFILEICON makes no bones about it, you must call DestroyIcon(). And so does the MSDN article for Icon.FromHandle(). The exact moment in time you call DestroyIcon matters a great deal as well, it must be delayed until some code either has made a copy of the icon or until you no longer need the icon and would normally call its Dispose() method.
Beware of the code snippet in the MSDN article, it shows a scenario where DestroyIcon() is called early. Okay in that specific case since it is assigned to the Form.Icon property. A corner case and surely not what you want to do.
The only really decent way to deal with this is to override the behavior of Icon.FromHandle() and force the object to take ownership of the native icon handle. So that it will automatically call DestroyIcon() when you dispose it. That requires a hack, the Icon constructor that lets you do this is internal. Reflection to the rescue, you can use the code from this post, note the GetConstructor() call. Start feeling good about it by writing a little unit test that does this a million times. If you hate it then write your own IDisposable wrapper so you can both dispose the icon and pinvoke DestroyIcon().

Addition by OP. There is an error in this answer. Because of all the comments it became harsh to see the forest through the trees. Hence I decided to edit this answer. (Sorry if I offended someone)
The .net source code is online: http://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/Icon.cs,81a28d20524554ae
Take a look at Icon.FromHandle:
public static Icon FromHandle(IntPtr handle)
{
IntSecurity.ObjectFromWin32Handle.Demand();
return new Icon(handle);
}
internal Icon(IntPtr handle) : this(handle, false)
{
}
internal Icon(IntPtr handle, bool takeOwnership)
{
if (handle == IntPtr.Zero)
{
throw new ArgumentException(SR.GetString(SR.InvalidGDIHandle,
(typeof(Icon)).Name));
}
this.handle = handle;
this.ownHandle = takeOwnership;
}
Note that after Icon.FromHandle ownHandle is false.
Let's look at Dispose:
void Dispose(bool disposing)
{
if (handle != IntPtr.Zero)
{
DestroyHandle();
}
}
internal void DestroyHandle()
{
if (ownHandle)
{
SafeNativeMethods.DestroyIcon(new HandleRef(this, handle));
handle = IntPtr.Zero;
}
}
Conclusion: After Icon.FromHandle, the field ownHandle is false, and thus Dispose / FromHandle won't call DestroyIcon
Therefore: if you create an Icon using Icon.FromHandle you'll have to Dispose() the Icon as well as call DestroyIcon, just as the remarks section says

I have had NO END of grief in this area - I've been trying to animate a form's icon (and consequently the one in the task bar) without it leaking resources.
When I disposed of the icon (as suggested on MSDN) resources leaked, when I used "DestroyIcon" all subsequent updates failed. This code below shows everything in the correct order.
API Declaration:
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = CharSet.Auto)]
extern static bool DestroyIcon(IntPtr handle);
FINALLY the solution:
IntPtr iconHandle = dynamicBitmap.GetHicon();
Icon tempManagedRes = Icon.FromHandle(iconHandle);
this.Icon = (Icon)tempManagedRes.Clone();
tempManagedRes.Dispose();
DestroyIcon(iconHandle);
Also posted in this question:
Win32.DestroyIcon vs. Icon.Dispose

Related

What's the point of OpenClipboard API?

After reading quite a bit on the clipboard being blocked when trying to use it, I tried using OpenClipboard() directly, to capture the clipboard and be able to use it from my window.
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
[DllImport("user32.dll", SetLastError=true)]
private static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("user32.dll", SetLastError=true)]
private static extern bool CloseClipboard();
private int idx = 0;
private void refresh_Tick(object sender, EventArgs e) {
switch (idx++) {
case 0:
OpenClipboard(Handle);
break;
default:
Clipboard.SetText(" ");
break;
}
}
}
When using SetText, I will get the infamous error:
A first chance exception of type 'System.Runtime.InteropServices.ExternalException' occurred in System.Windows.Forms.dll
Additional information: Requested Clipboard operation did not succeed.
So, the questions:
Does OpenClipboard() actually work?
What is the argument for OpenClipboard() for? The rest of the API does not need a handle to any window, so why does OpenClipboard()? In other words, the Clipboard is supposed to be shared between PROCESSES, not WINDOWS - but I don't see a way to lock it for my current process.
I can call OpenClipboard(IntPtr.Zero), which MSDN says:
If this parameter is NULL, the open clipboard is associated with the current task.
What is 'task' supposed to mean?
Does OpenClipboard() actually work?
OpenClipboard() works, but definitely not in the way you showed. It is a raw Win32 API. Here is an example of using it to copy string to clipboard (C/C++).
What is the argument for OpenClipboard() for?
To be honest, I'm not sure about this. Usually we just pass NULL aka IntPtr.Zero and let it associate with the current task. I guess it retrieves the thread that created the specified window, and then associates it with the clipboard.
What is task? Well here is my understanding. Back in Win16 days, instead of 'Thread' or 'Process', they used the terminology 'Task'. There was a function to GetCurrentTask().
Then the function is replaced by GetCurrentProcess() and GetCurrentThread().
Since it makes more sense that only one thread can access a shared resource at one time, I would say that 'Task' actually means 'Thread'.
The rest of the API does not need a handle to any window, so why does OpenClipboard()?
If my assumption above is correct, that is, only one thread can access Clipboard at a time, then chances are, Windows will use the thread/window you specified with OpenClipboard() previously, until you call CloseClipboard() or the thread/window becomes invalid. That's why you don't need to specify the HWND all the time.
In other words, the Clipboard is supposed to be shared between PROCESSES, not WINDOWS - but I don't see a way to lock it for my current process.
It locks, though I'm not sure about C# P/Invoke. If you have access to Win32/C development toolkit, compile and run the following code:
#include <conio.h>
#include <Windows.h>
int main()
{
OpenClipboard(GetForegroundWindow());
_getch();
return 0;
}
And see what happen if you use Clipboard in other program. :) Close the console window to restore.

C# dispose unmanaged resource outside "using" and "try/finalize" block

I want a method to return an unmanaged resource and later in the program dispose of that resource. Does the following implementation do what I intend ?
class DocxManager
{
// DocX is the unmanaged resource
public Docx createDocX(string pathToFile)
{
return new DocX(pathToFile);
}
public void makeChangesAndSaveDocX(DocX wordDoc)
{
wordDoc.Save();
// IS THIS WAY THE UNMANAGED RESOURCE FREED CORRECTLY AND NO MEMORY LEAK ?
((IDisposable)wordDoc).Dispose();
}
}
First off all, you seem to be misunderstanding the concept of managed and unmanaged resources. wordDoc is not an unmanaged resource, its a managed resource which happens to either directly hold an unmanaged resource or acts as a wrapper around some other IDisposable object (you don't care wich of the two is true). Its important you are clear on this because otherwise you will not implement correctly the IDisposable pattern when you need to. Read this for a very instructive answer on the subject and a few chuckles courtesy of Eric Lippert.
Does the following implementation do what I intend ?
No, it does not and to make things worse, the contract of DocXManager is simply horrible (more on that later).
What hapens if wordDoc.Save() throws and exception because the file is being used by another process, or maybe you've run out of space in the hard drive, or you've lost connection, etc.?
If the thrown exception is not recoverable (it's not handled anywhere in your code or it is but you will terminate it ASAP) then it's not really an issue and the runtime will clean up everything behind you when the process is terminated. On the other hand, if the exception is handled (warn the user the file is in use, the directory is not available, etc.) and the process keeps running then you've just maybe leaked a resource.
How to avoid this? Use a try-finally block:
public void makeChangesAndSaveDocX(DocX wordDoc)
{
try
{
wordDoc.Save();
}
finally
{
((IDisposable)wordDoc).Dispose();
}
}
Now you are sure that Dispose() will be called in any recoverable scenario.
So, is this good enough? Well....not exactly. The problem here is that makeChangesAndSaveDocX's (that should be MakeChangesAndSaveDocX by the way) contract is unclear. Who is responsible of disposing wordDoc? MakeChangesAndSaveDocX or the caller? Why one or the other? How does the consumer know that he doesn't need to worry about wordDoc once he's called MakeChangesAndSaveDocX? Or how is he supposed to know he can't use wordDoc after calling the public method MakeChangesAndSaveDocX? Why does DocXManager assume that the consumer will not need to use wordDoc after calling MakeChangesAndSaveDocX? Yuck...this is a mess.
I'd recommend you reconsider your approach and do one of the following:
If the method signature MakeChangesAndSaveDocX(DocX wordDoc) makes sense (somebody else can own wordDoc), then do not dispose wordDoc in MakeChangesAndSaveDocX. Let the caller carry that burden, he should be responsible because the object belongs to him not to MakeChangesAndSaveDocX.
If on the other hand, it makes no sense that somebody else who is not DocXManager owns wordDoc then wordDoc should be part of the state of DocXManager and you should reconsider the implementation of DocXManager to something allong the following lines:
public class DocXManager: IDisposable
{
private readonly DocX docX;
private bool disposed;
public DocXManager(string filePath)
{
docX = new DocX(filePath);
}
public void MakeChangesAndSaveDocX()
{
if (disposed)
throw new ObjectDisposedException();
docX.Save();
}
public void FrobDocX(Frobber frobber)
{
if (disposed)
throw new ObjectDisposedException();
frobber.Frob(docX);
}
public void Dispose()
{
if (disposed)
return;
Dispose(true);
disposed = true;
GC.SupressFinalize(this);
}
public void Dispose(bool disposing)
{
if (disposing)
{
//we can sefely dispose managed resources here
((IDisposable)docX).Dispose();
}
//unsafe to clean up managed resources here, only clean up unmanaged resources if any.
}
~DocXManager()
{
Dispose(false);
}
}
Now you've got a clear contract; DocManagerX is responsible of disposing correctly of DocX and the consumer is responsible of disposing correctly of any instance of DocManagerX he might use. Once responsibilities are clear, its easier to reason about code correctness and who should do what.
You'd use the manager in the following way:
using (var manager = new DocXManager(path))
{
manager.FrobDoxX(frobber);
manager.MakeChangesAndSaveDocX();
} //manager is guaranteed to be disposed at this point (ignoring scenarios where finally blocks are not executed; StackOverflowException, OutOfMemoryException, etc.)

Win32.DestroyIcon vs. Icon.Dispose

I have this line of code:
System.Drawing.Icon icon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
A few lines later, after icon is used I have the line:
Win32.DestroyIcon(shinfo.hIcon);
However when running a static analysis on my code it says there is a potential for Resource_Leak from icon. I am wondering will it make any difference if I call the dispose method:
icon.Dispose();
rather than the Win32.DestroyIcon() that is being used right now. Is there any difference between them? I am just maintaining this code so I am not sure if there was any special intnetion by the original developer to use Win32.DestroyIcon.
The static analysis is triggering because you aren't disposing the "IDisposable resource".
I would recommend sticking to the managed version throughout, and using icon.Dispose(). This will (internally) take care of calling DestroyIcon for you, but stick to the pure managed API throughout.
Win32.DestroyIcon is really intended more for use with icons you're receiving as an IntPtr, not for use with an Icon instance that is managed by the framework entirely.
I have had NO END of grief in this area - I've been trying to animate a form's icon (and consequently the one in the task bar) without it leaking resources.
When I disposed of the icon (as suggested on MSDN) resources leaked, when I used "DestroyIcon" all subsequent updates failed. This code below shows everything in the correct order.
API Declaration:
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = CharSet.Auto)]
extern static bool DestroyIcon(IntPtr handle);
FINALLY the solution:
IntPtr iconHandle = dynamicBitmap.GetHicon();
Icon tempManagedRes = Icon.FromHandle(iconHandle);
this.Icon = (Icon)tempManagedRes.Clone();
tempManagedRes.Dispose();
DestroyIcon(iconHandle);
Also posted in this question:
Icon.FromHandle: should I Dispose it, or call DestroyIcon?

CallbackOnCollectedDelegate was detected on Walther MFS100 Check Scanner

i am trying to programming an interface for Walther Mfs100 Check scanner but after the scan i get "CallbackOnCollectedDelegate was detected" error. How can i fix this. I use .net 2.0 with c#
[DllImport("mflib.dll.stdcall")]
public static extern int mfScanFeeder(int mode, int font, int timeout);
retval = modMFS100.mfScanFeeder(0, 2,5000);
It isn't this particular API call that's the source of the problem. The API is too obscure and too poorly documented to give a straight answer, but look for an initialization style function that let's you set a callback. That callback is the cause of the exception. You must create a delegate object and store it in a field of your class. That way the garbage collector sees a reference to it and won't garbage collect it.
Thus, instead of:
void SetupScanner() {
mfInitialize(something, myCallback);
}
Do it like this:
SomeDelegateType callback;
void SetupScanner() {
callback = new SomeDelegateType(myCallback);
mfInitialize(something, callback);
}
Contact the vendor for support if this doesn't help.
Here is some info about this error:
http://social.msdn.microsoft.com/forums/en-US/Vsexpressvb/thread/665b876d-9070-41de-9a3a-d2093895d0c2
You can try to use static variable for your delegate, this will prevent the delegate from being garbage collected.

How do I get a System.Windows.Form instance from its Win32 handle?

The following code implements a simple singleton that ensures only 1 instance of my application can be run. However, if another instance is started, I need to be able to grab that instance's command-line arguments, pass them to the initial instance, then terminate the second instance.
The issue comes in when I'm attempting to get hold of the first instance of the application. Once I've found the handle of that instance's main form, I pass it to the Control.FromHandle() method, expecting to get back a MainForm. Instead, the return value is always null. (Control.FromChildHandle() gives the same result.)
Therefore, my question is simply: what am I doing wrong? And is this even possible in .NET?
public class MainForm : Form
{
[DllImport("user32")]
extern static int ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32")]
extern static bool SetForegroundWindow(IntPtr hWnd);
private Mutex singletonMutex;
private void MainForm_Load(object sender, EventArgs e)
{
bool wasCreated;
singletonMutex = new Mutex(false, Application.ProductName + "Mutex", out wasCreated);
// returns false for every instance except the first
if (!wasCreated)
{
Process thisProcess = Process.GetCurrentProcess();
Process[] peerProcesses = Process.GetProcessesByName(thisProcess.ProcessName.Replace(".vshost", string.Empty));
foreach (Process currentProcess in peerProcesses)
{
if (currentProcess.Handle != thisProcess.Handle)
{
ShowWindowAsync(currentProcess.MainWindowHandle, 1); // SW_NORMAL
SetForegroundWindow(currentProcess.MainWindowHandle);
// always returns null !!!
MainForm runningForm = (MainForm) Control.FromHandle(currentProcess.MainWindowHandle);
if (runningForm != null)
{
runningForm.Arguments = this.Arguments;
runningForm.ProcessArguments();
}
break;
}
}
Application.Exit();
return;
}
}
Single-instance apps are well supported by the .NET framework. Check this thread for an example that does exactly what you need.
Control.FromHandle isn't going to work because the control you're looking for is in another process (and therefore in another appdomain).
You already have the WindowHandle but it's use is limited to the Win32 API. Nothing from WinForms is going to work.
You can send (WM_) messages but it's hard to get data across.
Options
use something low-level with a
temp-file.
use remoting (WCF)
Try the following
var form = (Form)(Control.FromHandle(myHandle));
EDIT
Re-read your question and realized you are looking at a handle in another process. There is no way to convert a handle in another process to a Form instance in the current process. My solution will only work for handles in the same process.
The only way to get ahold of the Form instance is to use Remoting. But that will require cooperation on the part of both processes which does not appear to be what you are looking for.
You are really trying to implement a singleton application. There are a few examples in the Internet (sorry, haven't really tried myself), e.g.
http://www.codeproject.com/KB/cs/SingletonApplication.aspx
http://www.nathanm.com/csharp-wpf-singleton-application/
You can't call code in another process directly, you need to use some form of inter-process communication
If you are communication only between processes started by the same user on the same computer you can use window messages (using WinAPI PostMessage and overriding WndProc), otherwise I think remoting is the easiest to use in .net
I use the Microsoft.VisualBasic.dll library described in the thread that nobugz pointed to. Yes, you can use it in C#. You just override the OnStartupNextInstance and pass the command line into your program in whatever way works best for you.
This is a whole lot easier than messing around with the threads manually.

Categories

Resources