修改通用对话框

几罗星人 2014-08-08 01:34:55

左边的打印对话框是VS【文件】菜单的【打印】子菜单打开的窗口,右边的打印是我调用COMDLG32.dll里的PrintDlg函数打开的打印对话框。很明显,VS的打印框多了“打印内容”这一栏。

本来想着VS的这个打印可能是自己的窗口,完全是自己布局的,然后调用其他API函数获得公共对话框中的数据,例如EnumPrinter获得了“打印机”一栏的“名称”下拉列表,这确实可以做到。但其他的按钮又怎么办呢?后来用句柄查看工具捕获VS的这个打印框,发现其所在的模块也是COMDLG32.dll,也就是这个窗口还是原来COMDLG32.dll提供的,只是被修改过了。

问:VS是怎么改的?
注意:只使用Win32去实现,不使用MFC
...全文
403 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
几罗星人 2014-08-26
  • 打赏
  • 举报
回复
引用 12 楼 xiaohuh421 的回复:
SetWindowPos 是客户区坐标, 也就是相对于父窗口的 而GetWindowRect获取的是 屏幕坐标. 要区分什么是屏幕坐标, 什么是客户区坐标.
这样的话误差就不止一个按钮的宽度了。屏幕坐标 = 客户区坐标 + 父窗口左上角的屏幕坐标,如果按你说的,GetWindowRect获取的是 屏幕坐标,再用SetWindowPos 按客户去坐标去移动,那么新的坐标会再加上父窗口左上角的屏幕坐标一次(由于坐标系原点从屏幕的左上角移动到窗口左上角),数值就会差很多了
xiaohuh421 2014-08-20
  • 打赏
  • 举报
回复
SetWindowPos 是客户区坐标, 也就是相对于父窗口的 而GetWindowRect获取的是 屏幕坐标. 要区分什么是屏幕坐标, 什么是客户区坐标.
几罗星人 2014-08-20
  • 打赏
  • 举报
回复
引用 10 楼 xiaohuh421 的回复:
[quote=引用 9 楼 JiLuoXingRen 的回复:] 这个我知道啊。我只是问为什么拿到的位置不对呢~~~???不要看了标题就急着回答,要慢慢看哦~~
晕你, 自己问是的: 问:VS是怎么改的? [/quote] 我感谢您的热心回答,不过真不要只看个标题,大概逐楼看来下来,看看人家讨论到了哪里,真的不需要急。2楼已经说了可以编写printhook proc来修改,我也尝试了。那劳烦您看看7楼,现在的问题是可以改,当改得不正确,为什么?
xiaohuh421 2014-08-20
  • 打赏
  • 举报
回复
引用 9 楼 JiLuoXingRen 的回复:
这个我知道啊。我只是问为什么拿到的位置不对呢~~~???不要看了标题就急着回答,要慢慢看哦~~
晕你, 自己问是的: 问:VS是怎么改的? 是你自己没表达清楚意思吧. 如果是同一份资源, 那么可能是 加载后经过修改. (移动控件位置和大小, 动态添加一些控件) 如果不是同一份资源, 那就是你使用资源模板跟它使用的不同. (同一个dll中会有很多资源的). 你看看PrintDlgEx 与 PrintDlg是否有区别
几罗星人 2014-08-17
  • 打赏
  • 举报
回复
引用 8 楼 xiaohuh421 的回复:
对话框都是通过资源模板创建出来的. 只要拿到资源ID, 你也可以在自己的Dialog类中创建. 如果你想添加按钮, 那就动态创建, 并添加到位置上即可. 想隐藏原生的控件或者移动布局, 也可以通过窗口句柄来操作.
这个我知道啊。我只是问为什么拿到的位置不对呢~~~???不要看了标题就急着回答,要慢慢看哦~~
xiaohuh421 2014-08-11
  • 打赏
  • 举报
回复
对话框都是通过资源模板创建出来的. 只要拿到资源ID, 你也可以在自己的Dialog类中创建. 如果你想添加按钮, 那就动态创建, 并添加到位置上即可. 想隐藏原生的控件或者移动布局, 也可以通过窗口句柄来操作.
阿呆_ 2014-08-08
  • 打赏
  • 举报
回复
建立自己的dialog template,编写printhook proc, 然后填入PRINTDLG结构,调用PrintDlg()即可
赵4老师 2014-08-08
  • 打赏
  • 举报
回复
逆向
几罗星人 2014-08-08
  • 打赏
  • 举报
回复
顺便问一个问题:看上面代码第68行的注释。很奇怪,用GetWindowRect去拿按钮的矩形信息,但是left和top似乎都比正确的值(指的是我不做任何更改,默认显示出来的位置所对应的值)要大,就以left为例,我拿到之后就直接传进SetWindowPos里,本来是想着这样按钮的left就不改变,只是上下移动,但是却发现显示出来的按钮都向右移动了。试验后减去right-left的值(即一个按钮的长度52),水平方向上就刚好恢复原位了。另外top也是,刚开始我是设置了+=200的,因为窗口拉长了200,按道理按钮也+=200就刚好了,但是发现200的话按钮就消失了(到了窗口可视区域下面),所以也证明top的值大了。为什么呢?
几罗星人 2014-08-08
  • 打赏
  • 举报
回复
OK ,printhook proc已实现。其实有回调,就能拿到句柄,在回调里用句柄设置什么都行了。 贴出当前的回调代码留给后人吧。实现的只是拉长打印对话框,并且将“确认”和“取消”按钮向下移动到合适位置

#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;

HWND SureCmd;
HWND CancelCmd;

LONG PrintDlgBottom;
LONG SureCmdY;
LONG CancelCmdY;

UINT CALLBACK PrintHookProc(HWND hdlg,UINT uiMsg,WPARAM wParam,LPARAM lParam)
{
	switch(uiMsg)
	{
	case WM_PAINT:
		// 修改窗口大小
		RECT rc;
		ZeroMemory(&rc,sizeof(rc));
		GetWindowRect(hdlg,&rc);
		if(PrintDlgBottom == 0)
		{
			rc.bottom += 200;
			PrintDlgBottom = rc.bottom;
			SetWindowPos(
				hdlg,
				0,0,0,
				rc.right - rc.left,
				rc.bottom - rc.top,
				// SWP_NOMOVE不移动,X,Y参数被忽略
				// SWP_NOZORDER不改变Z序列,hWndInsertAfter参数被忽略
				SWP_NOMOVE | SWP_NOZORDER);
		}

		// 获取确认和取消按钮句柄
		if((SureCmd == 0) || (CancelCmd == 0))
		{
			HWND NowWnd ;
			WCHAR WindowCaption[256] = {0};
			WCHAR SureCmdCap[256] = L"确定";
			WCHAR CancelCmdCap[256] = L"取消";

			while(wcscmp(WindowCaption,SureCmdCap) != 0)
			{
				NowWnd= FindWindowEx(hdlg,NowWnd,L"Button",0);
				GetWindowText(NowWnd,WindowCaption,256);
			}
			SureCmd = NowWnd;
			NowWnd = 0;
			while(wcscmp(WindowCaption,CancelCmdCap) != 0)
			{
				NowWnd= FindWindowEx(hdlg,NowWnd,L"Button",0);
				GetWindowText(NowWnd,WindowCaption,256);
			}
			CancelCmd = NowWnd;
		}
		// 修改确认和取消按钮位置
		ZeroMemory(&rc,sizeof(rc));
		GetWindowRect(SureCmd,&rc);
		if(SureCmdY == 0)
		{
			rc.top += 130;
			SureCmdY = rc.top;
			SetWindowPos(
				SureCmd,
				0,
				rc.left-52, // 52是一个按钮的长度,不知道为什么拿到的left总是大了52
				rc.top,
				0,
				0,
				// SWP_NOSIZE不改变大小,cx,cx参数被忽略
				// SWP_NOZORDER不改变Z序列,hWndInsertAfter参数被忽略
				SWP_NOSIZE | SWP_NOZORDER);
		}
		ZeroMemory(&rc,sizeof(rc));
		GetWindowRect(CancelCmd,&rc);
		if(CancelCmdY == 0)
		{
			rc.top += 130;
			CancelCmdY = rc.top;
			SetWindowPos(
				CancelCmd,
				0,
				rc.left-52, // 52是一个按钮的长度,不知道为什么拿到的left总是大了52
				rc.top,
				0,
				0,
				// SWP_NOSIZE不改变大小,cX,cY参数被忽略
				// SWP_NOZORDER不改变Z序列,hWndInsertAfter参数被忽略
				SWP_NOSIZE | SWP_NOZORDER);
		}
		break;
	default:
		break;
	}
	
	return 0;
}

int APIENTRY _tWinMain(
					  HINSTANCE hInstance,
					  HINSTANCE hPrevInstance,
					  LPTSTR	lpCmdLine,
					  int		nCmdShow
					)
{
	
    PRINTDLG pd = {0};
	LPDEVMODE devM = nullptr;
	LPDEVNAMES devN = nullptr;

    pd.lStructSize = sizeof( pd );
    pd.Flags = PD_RETURNDC | PD_ENABLEPRINTHOOK;
	pd.lpfnPrintHook = PrintHookProc;

    // 取得打印机DC
    PrintDlg(&pd);
	// 置空打印设置对话框的公共变量
	PrintDlgBottom = 0;
	SureCmd = 0;
	CancelCmd = 0;
	SureCmdY = 0;
	CancelCmdY = 0;

	// devM将包含打印机名
	devM = (LPDEVMODE)::GlobalLock(pd.hDevMode);
	devN = (LPDEVNAMES)::GlobalLock(pd.hDevNames);
	GlobalUnlock(devM);

        return 0;
}
movsd 2014-08-08
  • 打赏
  • 举报
回复
引用 2 楼 Idle_ 的回复:
建立自己的dialog template,编写printhook proc, 然后填入PRINTDLG结构,调用PrintDlg()即可
正常使用应该用这个方法
几罗星人 2014-08-08
  • 打赏
  • 举报
回复
引用 1 楼 zhao4zhong1 的回复:
逆向
zhao4老师言简意赅啊,但是不懂啊~~
勤奋的小游侠 2014-08-08
  • 打赏
  • 举报
回复
自己搞一个。

64,687

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧