I want to obtain the current number of window handles and the system-wide window handle limit in C#. How do I go about this?
问题:
回答1:
If you read Raymond Chen's post, you'll probably find it as annoying as I did. You're only "probably doing something wrong" because you're doing something Windows isn't capable of.
In my application, the first time a user visits a tab page, I create and lay out all the controls on that page. This takes a noticeable amount of time - there can easily be 50 controls on a page. So I don't discard the controls on a tab page after populating it, if it's at all possible, and leave closing sets of tab pages up to the user.
As it happens, some users never want to close any sets of tab pages. Why should I be forcing them to? With my UI, they can navigate very quickly to any one of the 300+ sets of transactions that they're responsible for managing. Their machines are fast enough, and have enough memory, to make this all very responsive. The only problem is that Windows can't support it.
Why am I using controls, and not some other UI technology? Because they work. I need to support focus events, tab order, validation events, dynamic layout, and data binding - the users are actually managing thousands of records, in dozens of tables, in an in-memory DataSet. The amount of development I'd have to do to - say - implement something using windowless controls is astronomical.
I'm only "doing it wrong" because Windows has a hard limit on the number of window handles that it can support. That hard limit is based on a bunch of decade-old assumptions about how a computer's UI might be built. It's not me who's "doing something wrong."
At any rate, my solution to this is in two parts.
First, a class that can tell you how many window handles your process is using:
using System;
using System.Runtime.InteropServices;
namespace StreamWrite.Proceedings.Client
{
public class HWndCounter
{
[DllImport("kernel32.dll")]
private static extern IntPtr GetCurrentProcess();
[DllImport("user32.dll")]
private static extern uint GetGuiResources(IntPtr hProcess, uint uiFlags);
private enum ResourceType
{
Gdi = 0,
User = 1
}
public static int GetWindowHandlesForCurrentProcess(IntPtr hWnd)
{
IntPtr processHandle = GetCurrentProcess();
uint gdiObjects = GetGuiResources(processHandle, (uint)ResourceType.Gdi);
uint userObjects = GetGuiResources(processHandle, (uint)ResourceType.User);
return Convert.ToInt32(gdiObjects + userObjects);
}
}
}
Second, I maintain a least-recently-used cache of my tab page objects. The .NET framework doesn't provide a generic LRU cache class, so I built one, which you can get here if you need one. Every time the user visits a tab page, I add it to the LRU Cache. Then I check to see if I'm running low on window handles. If I am, I throw away the controls on the least-recently-used tab page, and keep doing that until I have enough window handles again.
回答2:
As Raymond Chen put it some time ago, if you're thinking about window handle limits, you're probably doing something wrong :)
Anyway, I bet there's no special C# way to do it, because it's very system-specific. You can use the same functions that you would use in a C++ application. Call the functions using P/Invoke. To learn how to write the imports, go to pinvoke.net.
Edit: As I understand your question, I assume you already know how to do that in a Win32 application.
回答3:
The full quote OregonGhost refers to is
If you have to ask, you're probably doing something wrong.
It's from Why is the limit of window handles per process 10,000? You should read this.