欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C# 强行锁定 第三方 外部 应用程序窗体窗口的分辨率尺寸大小 禁止鼠标拖拽改变窗口大小

程序员文章站 2022-05-18 14:28:09
我们也许会有一些奇怪的需求,比如说禁止一个外部程序的窗口大小更改。 如果我们没法修改外部程序的代码,那要怎么做呢? 当然,我们可以通过DLL注入目标程序的方式去Hook或registry一个事件来检测,但这也太麻烦了吧。 如果想做非侵入式的,那就需要用到Windows下的系统函数去完成工作。 查来查 ......

我们也许会有一些奇怪的需求,比如说禁止一个外部程序的窗口大小更改。

如果我们没法修改外部程序的代码,那要怎么做呢?

当然,我们可以通过dll注入目标程序的方式去hook或registry一个事件来检测,但这也太麻烦了吧。

如果想做非侵入式的,那就需要用到windows下的系统函数去完成工作。

查来查去,最好用的是movewindow函数

1 movewindow(intptr hwnd, int x, int y, int nwidth, int nheight, bool brepaint)

可以看到,这个函数要求传入一个intptr类型的句柄、一组int类型的坐标、以及int类型的窗口的宽度和高度和最后的bool类型的是否刷新显示。

句柄大家应该都知道是什么,相当于是id身份证一样的存在,坐标就是指你把窗口移动到屏幕上的那个坐标。高宽不必说,这就是我们要改的。至于刷新显示我们也无需过多理解,一个性能问题罢了。

 

首先我们要获取坐标,先写一个窗口枚举器

    /*窗口句柄枚举器*/
    public static class windowsenumerator
    {
        private delegate bool enumwindowsproc(intptr windowhandle, intptr lparam);
        [dllimport("user32.dll", setlasterror = true)]
        private static extern bool enumwindows(enumwindowsproc callback, intptr lparam);
        [dllimport("user32.dll", setlasterror = true)]
        private static extern bool enumchildwindows(intptr hwndstart, enumwindowsproc callback, intptr lparam);
        [dllimport("user32.dll", setlasterror = true)]
        static extern int getwindowtext(intptr hwnd, stringbuilder lpstring, int nmaxcount);
        [dllimport("user32.dll", setlasterror = true)]
        static extern int getwindowtextlength(intptr hwnd);
        private static list<intptr> handles = new list<intptr>();
        private static string targetname;
        public static list<intptr> getwindowhandles(string target)
        {
            targetname = target;
            enumwindows(enumwindowscallback, intptr.zero);
            return handles;
        }
        private static bool enumwindowscallback(intptr hwnd, intptr includechildren)
        {
            stringbuilder name = new stringbuilder(getwindowtextlength(hwnd) + 1);
            getwindowtext(hwnd, name, name.capacity);
            if (name.tostring() == targetname)
                handles.add(hwnd);
            enumchildwindows(hwnd, enumwindowscallback, intptr.zero);
            return true;
        }
    }

调用方法是

windowsenumerator.getwindowhandles("窗口名字")

然后这个方法返回的是一个数组,我们需要用到foreach去遍历里面的东西

foreach (var item in windowsenumerator.getwindowhandles("窗口名字"))

这个item的数据类型是intptr,也就是movewindow函数所需的第一个参数hwnd——句柄

 

我们接着看第二组参数,需要传入x和y,也就是窗口移动到屏幕上的位置。

如果把这个写死,你的窗口就无法移动了,只会固定在一个地方。

所以我们需要动态的去获取窗口当前位置,然后把位置传入给movewindow方法所需的x和y参数。

 

我们需要用到getwindowrect函数,需要传入hwnd和rect

        [dllimport("user32.dll")]
        [return: marshalas(unmanagedtype.bool)]
        static extern bool getwindowrect(intptr hwnd, ref rect lprect);

        [structlayout(layoutkind.sequential)]
        public struct rect //定位当前窗口位置
        {
            public int x;                             //最左坐标
            public int y;                             //最上坐标

        }

然后我们需要在执行movewindow函数之前执行getwindowrect函数,放到上面写的foreach里就好了。

记得new一个rect结构体出来。

rect rect = new rect();
getwindowrect(item, ref rect);

 

因为我们禁止窗口修改不是一次性的,需要循环去检测,我们把检测方法写个死循环while(true)就好了,然后开辟新的线程去执行这个死循环。

因为c# 是有垃圾回收策略的,我们无需担心性能开支过大所造成的的问题,毕竟就是写着玩,学习学习(难道这有人有这个需求吗不会把不会把?)

总结一下就是如下代码:

rect rect = new rect();


 //禁止修改窗口
public void pck(){
 while (true){
        foreach (var item in windowsenumerator.getwindowhandles("minecraft 1.12.2")){
             getwindowrect(item, ref rect);//获取窗口在屏幕上的坐标
             movewindow(item, rect.x, rect.y, 1024, 768, true); //锁定为1024*768分辨率
          }
             thread.sleep(2000); //2秒检测一次
   }
}

 

然后调用的时候直接:

 

thread thread = new thread(new threadstart(pck));
 thread.start();

 

 

随笔到此结束