在Windows 7中,当我打开WindowsExplorer(不是Internet Explorer)来查看和管理我的文件,在打开一个新的窗口,它会记住上次关闭的窗口的大小,它通常是在屏幕上的位置重叠打开其他的资源管理器窗口:
我想始终打开资源管理器窗口大小相同,从不部分/全部隐藏其他的资源管理器窗口:
搜索(没有运气)的一些Windows7的选项来启用这些功能后,在一个雨夜,周六,我开始开发这个。(顺便说一句:如果你碰巧知道该怎么做同样的事情在一个更好的/更快的方式(即一些窗口设置或一些现有的实用程序),我想知道,谢谢。)
背景
它是使用一个简单的程序:
- user32.dll中的功能来管理桌面窗口
-
形式重写
的WndProc
来管理窗口消息并设置窗口的创建/激活/销毁壳钩(虽然只有创建活动将在这里使用;另一个是“未来用途”) - 一个互斥只允许一个运行的应用程序实例
- 中的XML序列化配置对象,将写入和读取硬盘(在应用程序的同一个文件夹)
使用代码
代码的结构分为4个文件中,本文下面所述,从最不重要的开始:
-
WindowsApi.cs仅包含
DllImports
到Windows API的,尤其是:user32.dll中 ; 这其中并不需要任何进一步的解释 -
XmlHelper.cs是一个非常简单的裸骨
抽象
的XML序列化类。通过继承这一块,一个类可以保存为一个XML文件,而无需进一步的努力 - Config.cs包含读取/写入磁盘配置
-
WindowsHookForm.cs ]是从未示出给用户的形式; 它只是提供给用从公司
的WndProc
,即可以轻松地勾到Windows外壳程序的事件,因此在打开窗口时做一些事情。它提供了三个事件:
WindowCreatedEvent
,WindowActivatedEvent
和WindowDestroyedEvent
,但在节目只有第一个被实际使用。在构造函数中,一个钩子注册:
隐藏 复制代码private readonly int windowMessage_ShellHook; public WindowsHookForm() { windowMessage_ShellHook = WindowsApi.RegisterWindowMessage("SHELLHOOK"); WindowsApi.RegisterShellHookWindow(this.Handle); }
然后,在
WndProc中
,消息被拦截,并且如果邮件ID
是我们shellhook,则事件被上升(但仅限于上面提到的三个种):隐藏 缩小复制代码
public event Action<IntPtr> WindowCreatedEvent; public event Action<IntPtr> WindowActivatedEvent; public event Action<IntPtr> WindowDestroyedEvent; protected override void WndProc(ref Message message) { if(message.Msg == windowMessage_ShellHook) { WindowsApi.ShellEvents shellEvent = (WindowsApi.ShellEvents)message.WParam.ToInt32(); IntPtr windowHandle = message.LParam; switch(shellEvent) { case WindowsApi.ShellEvents.HSHELL_WINDOWCREATED: if(WindowCreatedEvent != null) WindowCreatedEvent(windowHandle); break; case WindowsApi.ShellEvents.HSHELL_WINDOWACTIVATED: if(WindowActivatedEvent != null) WindowActivatedEvent(windowHandle); break; case WindowsApi.ShellEvents.HSHELL_WINDOWDESTROYED: if(WindowDestroyedEvent != null) WindowDestroyedEvent(windowHandle); break; } } base.WndProc(ref message); }
- Program.cs中包含的程序的主要逻辑:
一旦启动,互斥允许只运行一个程序的实例,如果一个实例已经在运行,它亲切地询问是否要终止它(在这种情况下,它会调用RemoveAllInstancesFromMemory
方法,即获取正在运行的进程与“ WindowsMover
”的名称,并杀死'时间)。
一旦启动,执行三个动作:首先是配置文件(如果存在的话)被读取(如果它不存在,那么它是书面使用默认值,这样你可能会发现它容易编辑)然后,在ArrangeExplorerWindows
方法,在桌面上每一个现有的浏览器窗口被布置(即调整大小和移动); 最后驻留部分开始时,在那里WindowsHookForm
和WindowCreatedEvent
在它定义被使用:
WindowsHookForm whf = new WindowsHookForm();
whf.WindowCreatedEvent += (data) => { ArrangeOneWindow(data); };
每当我们打开一个新窗口时,ArrangeOneWindow
方法接收手柄刚刚创建的新窗口; 然后它会检查它是否是一个资源管理器窗口:
private static void ArrangeOneWindow(IntPtr newhandle)
{
List<windowInfo> wlist = GetActiveExplorerWindowsInfo();
windowInfo newWindow = (from windowInfo wi in wlist
where wi.handle == newhandle
select wi).FirstOrDefault();
if (newWindow != null)
并调整其大小和(可选)移动该窗口,使用WindowsAPI的
功能做的工作,并配置数据来了解如何进行。
基本上,打开资源管理器窗口的任何时间,程序搜索的位置把它,开始在桌面的左上角,然后(在一排等)向右移动,直到一个合适的地方被发现; 一旦达到桌面的右侧,将相同的搜索被重复下面的一行。如果有太多的资源管理器窗口在桌面上打开,并没有空地方放新开一个,那么不采取任何措施,并会留在新窗口,在Windows7中决定把它。
配置文件
<width>346</width>
<height>460</height>
<startLeft>0</startLeft>
<startTop>0</startTop>
<left>0</left>
<top>0</top>
<horizontalGap>0</horizontalGap>
<verticalGap>0</verticalGap>
<doResizeOnly>false</doResizeOnly>
<canArrangeFixedPositions>true</canArrangeFixedPositions>
<canAppendToNext>false</canAppendToNext>
<ExcludedWindowsTitles>
<string>Control Panel\All Control Panel Items\Personalization</string>
<string>Shut Down Windows</string>
</ExcludedWindowsTitles>
<logFileName>WindowsMover.log</logFileName>
<doLogFile>false</doLogFile>
-
宽度
和高度
是默认的调整对调整窗口大小的尺寸。你知道,Explorer始终使用上次关闭的窗口大小作为默认为新的,所以在这些价值观的配置文件来覆盖由探险家设置的。 -
两个
间隙
值应该是设置窗口之间的距离。 -
doResizeOnly
如果真
不动的窗口。 -
canArrangeFixedPositions
允许搜索即使有酒店旁边现有的窗口中没有自由的地方合适的位置(它的窗口映射,如果它被做开始砖startLeft
和家园理财
,与defaut宽度
和高度
在第一行设置该的配置文件,然后搜索,如果这图块之一是免费的) -
canAppendToNext
如果真的
是第一次尝试新的窗口附加到现有的浏览器窗口的右侧。 -
ExcludedWindowsTitles
是 浏览器窗口标题的列表,我们不希望被安排 -
doLogFile
如果属实
,一个LOGFILENAME
为每个窗口安排书面(主要用于调试)
就是这样。从结构上看,它是非常简单,它可以给一些有趣的见解新手程序员。
更新
收到一对夫妇的请求后,我已经改变了计划,以便它可以调整大小和移动各种窗口,不仅资源管理器窗口(所以我也改变了文章的标题)。为了让这个功能,我已经添加在配置文件中的一个新领域:
<ProcessesToWatch>
<string>explorer</string>
</ProcessesToWatch>
这是一个字符串列表,你可以用别的东西代替“资源管理器”,或者只是添加到被监视新进程的名称。
例如,在配置文件中的以下XML:
<ProcessesToWatch>
<string>explorer</string>
<string>notepad</string>
</ProcessesToWatch>
将使双方探险家和记事本打开的窗口程序的手表,它会调整大小/移动它们。
如果不确定进程名称列表中的使用,即暂时更改配置文件中的以下行:
<doLogFile>false</doLogFile>
到真,并且,在启动时,在日志文件中会有所有活动的进 程的名称,其中,所需要的人可以被拾取的列表。