[高分,再发布]改变其他应用程序的控件字体的问题

时间:2023-02-11 19:24:54
我要做一个改变其他进程(其他应用程序)的窗口中控件(BUTTON,EDIT等)字体的程序,我先得到控件的句柄,然后向这个句柄发送WM_SETFONT消息,但仍无法改变目标窗口的字体,请问为什么?是不是因为WM_SETFONT消息送走的HFONT句柄指向的内存目标窗体无法访问导致的?我所要求的功能又如何实现呢?
P.s.操作系统是win2K

16 个解决方案

#1


up一下,帮忙up者同样给分.

#2


子类化

#3



我个人分析认为:
1 你用WM_SETFONT的方法应该是行不通的,因为你发的这个消息虽然应该是起作用的,但是窗口处理过程中它会获得它的缺省字体,你不能改变这个取得字体的消息处理过程
2 所以我赞成用子类化,设置字体的处理过程你自己重写
3 如果你想改变其它应用程序的字体,我想还必须用钩子,把代码注入到别的进程当中

#4


WM_SETFONT用来设置窗口自己的控件字体绝对是可以用的,没必要用控件子类化的技术,我已经试过了。
但是,把设置自己控件字体的代码应用到其他应用程序窗体中的控件上之后就起不了作用,只是把其他控件变成了Window缺省字体(即使原来不是也会变成这样),我向就是因为WM_SETFONT送走的字体句柄其他进程无法访问导致的,但我不知道解决办法。
至于钩子,我只是大概知道有键盘钩子和鼠标钩子用来截取输入,将代码注入到别的进程中的钩子如何设计呢?

#5


上次帮你up怎么没给分?
up

#6


再up,今天弄这个都要疯掉了……另外我本来是想贴子结了再给分的……
P.s.我不会做hook啊,哪里有比较简单的教学?(我要全局钩子的……)

#7


up

#8


用钩子截获WM_SETFONT消息,在自已程序处理这个消息

#9


根据我的经验你在本地创建的HFONT的资源在本地进程空间有效果,其他的进程无法访问.可以尝试把HFONT资源创建在全局地址空间,比如从DLL中创建.因为DLL的资源加载的地址空间对所有进程都可见.从你本地进程初始话DLL,再把HFONT传给其他进程.

不过我还是怀疑WM_SETFONT不接受外部进程发送.我没有时间来验证.要解决你的问题最标准的做法是用

SetWindowsHookEx(...)

用全局Hook的话一定要把HOOKPROC用DLL加载在全局地址空间.不然有麻烦.具体用法可以查MSN.

#10


在经过无数次导致死机的hook试验后,我终于成功了……
loyee所说的在DLL中创建HFONT再传给其他窗口的方法行不通,因为DLL中的对象(这是指Windows Programing里的对象,不是OOL)仍然只能被调用DLL的线程所访问(每次调用DLL都会创建一个DLL的Module,它们之间其实仍是独立的)。所以DLL创建的HFONT其他进程仍然无法访问。
现在的做法是创建WH_CALLWNDPROCRET类型的hook来截获目标窗口消息,在hook的DLL里向目标窗口发送WM_SETFONT消息,当然HFONT是在hook的DLL里创建的……由于被设置hook的线程会自动地通过LoadLibrary来调入Hook的DLL, 所以这个DLL里的HFONT能被目标窗口访问……当然,为了在这个DLL里创建适当的字体,还是费了不少劲(另:这个DLL和设置hook时调用的DLL是相互独立的)……
感觉好象是走了一大条弯路来达到目的,不知道有没有其他简单的办法……
P.s.我会在三天后结贴,有人想讨论一下吗?

#11


alexanderyu(alex),

DLL中有方法定义全局可见的变量.印象中好象是变量应该声明在一个不同的段里面.我几年前实现过,现在反而忘了代码在哪里.有兴趣可以查MSN中的一些KB文档资料.

#12


to baiyucsdn(西瓜太郎) :
我做这个东西完全是为了做实验,所以源代码很混乱(而且我是用WINAPI而不是MFC来设计的,可读性比较弱),我不推荐你去看我的源代码。不过我可以把源代码利用到hook里的那部分解释一下:
特别注意:由于我做hook是为了实现修改其他窗体的控件字体这个目的,所以有一些特殊的做法,如果想学hook最好还是去看一下别人比较正常的源代码好一点……

这里是DLL的代码:

#include <windows.h>

#define DllExport extern "C" __declspec(dllexport)

//导出函数MessageProc,这个函数就是用于WH_CALLWNDPROCRET钩子的函数
DllExport BOOL MessageProc(int nCode,WPARAM wParam,LPARAM lParam);


//设置共享内存段,只有在共享内存段中的变量才能被所有线程共同访问。
//共享内存段中的变量必须初始化。
#pragma data_seg("shared")
DllExport LOGFONT logfont={0,0,0,0,0,
0,0,0,0,0,0,0,0,
"Arial"};
DllExport HHOOK hhook=NULL;
#pragma data_seg()
#pragma comment(linker,"/SECTION:shared,RWS")


HFONT hf;

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
 )
{
    //在DLL附到进程上的时候创建字体,在DLL离开进程时销毁字体
    //创建字体是由logfont决定的,该共享变量在设置hook的程序中修改
    if (ul_reason_for_call==DLL_PROCESS_ATTACH)
hf=CreateFontIndirect(&logfont);
    else if (ul_reason_for_call==DLL_PROCESS_DETACH&&hf!=NULL)
DeleteObject(hf);
    return TRUE;
}



BOOL MessageProc(int nCode,WPARAM wParam,LPARAM lParam)
{
    //判断如果是WM_SETFONT消息则再发送一个由DLL创建的字体到窗口
if (((LPCWPRETSTRUCT)lParam)->message==WM_SETFONT)
{
if (((LPCWPRETSTRUCT)lParam)->wParam!=(WPARAM)hf)
SendMessage(((LPCWPRETSTRUCT)lParam)->hwnd,
WM_SETFONT,(WPARAM)hf,TRUE);
}
  //调用下一个hook
      return CallNextHookEx(hhook,nCode,wParam,lParam);
}




以下是调用DLL来设置hook的代码,当然,不使用LoadLibrary动态载如也是可行的,只是我一开始就这么干了……

//各变量定义
Static HOOKPROC hkprcMsg; 
static HINSTANCE hinstDLL; 
static LPLOGFONT lplogfont;
static HHOOK *phhook=NULL;

///////
//以下是安装hook的代码
///////

//装入DLL
hinstDLL = LoadLibrary((LPCTSTR)"FontChangerDLL.dll"); 
//取得hook函数地址
hkprcMsg =(HOOKPROC) GetProcAddress(hinstDLL, "MessageProc"); 
//取得DLL共享变量hhook(用于CallNextHookEx函数)和logfont地址
phhook=(HHOOK*)GetProcAddress(hinstDLL, "hhook"); 
lplogfont=(LPLOGFONT)GetProcAddress(hinstDLL, "logfont"); 
//修改logfont结构体的内容
memcpy(lplogfont,cf.lpLogFont,sizeof(LOGFONT));

//向目标窗体(hwnd_Tar)安装hook
*phhook = SetWindowsHookEx(WH_CALLWNDPROCRET, hkprcMsg, hinstDLL,GetWindowThreadProcessId(hwnd_Tar,NULL)); 

//当然,要修改目标窗体中控件的字体的话还要向控件发送WM_SETFONT消息,不用放HFONT句柄

///////
//以下是卸载hook的代码,在hook使用完之后要把hook卸载掉
///////
UnhookWindowsHookEx(*phhook);

如果还要源代码的话再发贴。

#13


to loyee()
我也知道DLL有全局可用的变量,但是HFONT作为GDI对象好像是比较特殊的东西,不是一般的变量,直接通过WM_SETFONT来传HFONT是没有用的。
HFONT是“句柄”——相似于指针但又不相同,所以不能用面向内存的一道机理来处理句柄

#14


时间到,闭贴散分罗。

#15


我说到了最核心的内容,才给我5分,下次不干了

#1


up一下,帮忙up者同样给分.

#2


子类化

#3



我个人分析认为:
1 你用WM_SETFONT的方法应该是行不通的,因为你发的这个消息虽然应该是起作用的,但是窗口处理过程中它会获得它的缺省字体,你不能改变这个取得字体的消息处理过程
2 所以我赞成用子类化,设置字体的处理过程你自己重写
3 如果你想改变其它应用程序的字体,我想还必须用钩子,把代码注入到别的进程当中

#4


WM_SETFONT用来设置窗口自己的控件字体绝对是可以用的,没必要用控件子类化的技术,我已经试过了。
但是,把设置自己控件字体的代码应用到其他应用程序窗体中的控件上之后就起不了作用,只是把其他控件变成了Window缺省字体(即使原来不是也会变成这样),我向就是因为WM_SETFONT送走的字体句柄其他进程无法访问导致的,但我不知道解决办法。
至于钩子,我只是大概知道有键盘钩子和鼠标钩子用来截取输入,将代码注入到别的进程中的钩子如何设计呢?

#5


上次帮你up怎么没给分?
up

#6


再up,今天弄这个都要疯掉了……另外我本来是想贴子结了再给分的……
P.s.我不会做hook啊,哪里有比较简单的教学?(我要全局钩子的……)

#7


up

#8


用钩子截获WM_SETFONT消息,在自已程序处理这个消息

#9


根据我的经验你在本地创建的HFONT的资源在本地进程空间有效果,其他的进程无法访问.可以尝试把HFONT资源创建在全局地址空间,比如从DLL中创建.因为DLL的资源加载的地址空间对所有进程都可见.从你本地进程初始话DLL,再把HFONT传给其他进程.

不过我还是怀疑WM_SETFONT不接受外部进程发送.我没有时间来验证.要解决你的问题最标准的做法是用

SetWindowsHookEx(...)

用全局Hook的话一定要把HOOKPROC用DLL加载在全局地址空间.不然有麻烦.具体用法可以查MSN.

#10


在经过无数次导致死机的hook试验后,我终于成功了……
loyee所说的在DLL中创建HFONT再传给其他窗口的方法行不通,因为DLL中的对象(这是指Windows Programing里的对象,不是OOL)仍然只能被调用DLL的线程所访问(每次调用DLL都会创建一个DLL的Module,它们之间其实仍是独立的)。所以DLL创建的HFONT其他进程仍然无法访问。
现在的做法是创建WH_CALLWNDPROCRET类型的hook来截获目标窗口消息,在hook的DLL里向目标窗口发送WM_SETFONT消息,当然HFONT是在hook的DLL里创建的……由于被设置hook的线程会自动地通过LoadLibrary来调入Hook的DLL, 所以这个DLL里的HFONT能被目标窗口访问……当然,为了在这个DLL里创建适当的字体,还是费了不少劲(另:这个DLL和设置hook时调用的DLL是相互独立的)……
感觉好象是走了一大条弯路来达到目的,不知道有没有其他简单的办法……
P.s.我会在三天后结贴,有人想讨论一下吗?

#11


alexanderyu(alex),

DLL中有方法定义全局可见的变量.印象中好象是变量应该声明在一个不同的段里面.我几年前实现过,现在反而忘了代码在哪里.有兴趣可以查MSN中的一些KB文档资料.

#12


to baiyucsdn(西瓜太郎) :
我做这个东西完全是为了做实验,所以源代码很混乱(而且我是用WINAPI而不是MFC来设计的,可读性比较弱),我不推荐你去看我的源代码。不过我可以把源代码利用到hook里的那部分解释一下:
特别注意:由于我做hook是为了实现修改其他窗体的控件字体这个目的,所以有一些特殊的做法,如果想学hook最好还是去看一下别人比较正常的源代码好一点……

这里是DLL的代码:

#include <windows.h>

#define DllExport extern "C" __declspec(dllexport)

//导出函数MessageProc,这个函数就是用于WH_CALLWNDPROCRET钩子的函数
DllExport BOOL MessageProc(int nCode,WPARAM wParam,LPARAM lParam);


//设置共享内存段,只有在共享内存段中的变量才能被所有线程共同访问。
//共享内存段中的变量必须初始化。
#pragma data_seg("shared")
DllExport LOGFONT logfont={0,0,0,0,0,
0,0,0,0,0,0,0,0,
"Arial"};
DllExport HHOOK hhook=NULL;
#pragma data_seg()
#pragma comment(linker,"/SECTION:shared,RWS")


HFONT hf;

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
 )
{
    //在DLL附到进程上的时候创建字体,在DLL离开进程时销毁字体
    //创建字体是由logfont决定的,该共享变量在设置hook的程序中修改
    if (ul_reason_for_call==DLL_PROCESS_ATTACH)
hf=CreateFontIndirect(&logfont);
    else if (ul_reason_for_call==DLL_PROCESS_DETACH&&hf!=NULL)
DeleteObject(hf);
    return TRUE;
}



BOOL MessageProc(int nCode,WPARAM wParam,LPARAM lParam)
{
    //判断如果是WM_SETFONT消息则再发送一个由DLL创建的字体到窗口
if (((LPCWPRETSTRUCT)lParam)->message==WM_SETFONT)
{
if (((LPCWPRETSTRUCT)lParam)->wParam!=(WPARAM)hf)
SendMessage(((LPCWPRETSTRUCT)lParam)->hwnd,
WM_SETFONT,(WPARAM)hf,TRUE);
}
  //调用下一个hook
      return CallNextHookEx(hhook,nCode,wParam,lParam);
}




以下是调用DLL来设置hook的代码,当然,不使用LoadLibrary动态载如也是可行的,只是我一开始就这么干了……

//各变量定义
Static HOOKPROC hkprcMsg; 
static HINSTANCE hinstDLL; 
static LPLOGFONT lplogfont;
static HHOOK *phhook=NULL;

///////
//以下是安装hook的代码
///////

//装入DLL
hinstDLL = LoadLibrary((LPCTSTR)"FontChangerDLL.dll"); 
//取得hook函数地址
hkprcMsg =(HOOKPROC) GetProcAddress(hinstDLL, "MessageProc"); 
//取得DLL共享变量hhook(用于CallNextHookEx函数)和logfont地址
phhook=(HHOOK*)GetProcAddress(hinstDLL, "hhook"); 
lplogfont=(LPLOGFONT)GetProcAddress(hinstDLL, "logfont"); 
//修改logfont结构体的内容
memcpy(lplogfont,cf.lpLogFont,sizeof(LOGFONT));

//向目标窗体(hwnd_Tar)安装hook
*phhook = SetWindowsHookEx(WH_CALLWNDPROCRET, hkprcMsg, hinstDLL,GetWindowThreadProcessId(hwnd_Tar,NULL)); 

//当然,要修改目标窗体中控件的字体的话还要向控件发送WM_SETFONT消息,不用放HFONT句柄

///////
//以下是卸载hook的代码,在hook使用完之后要把hook卸载掉
///////
UnhookWindowsHookEx(*phhook);

如果还要源代码的话再发贴。

#13


to loyee()
我也知道DLL有全局可用的变量,但是HFONT作为GDI对象好像是比较特殊的东西,不是一般的变量,直接通过WM_SETFONT来传HFONT是没有用的。
HFONT是“句柄”——相似于指针但又不相同,所以不能用面向内存的一道机理来处理句柄

#14


时间到,闭贴散分罗。

#15


我说到了最核心的内容,才给我5分,下次不干了