| Visual C++技巧问答 |
| 心铃 |
|
一、如何使用API函数设置打印机的横向或竖向打印
读者 Rafe Fan问:
我有一个问题想请教,就是如何使用API函数设置打印机的横向或竖向打印呢?
答:你可以使用API函数DocumentProperties获取或者设置打印时打印机的初始化信息(包括打印方向)。在使用该函数需要使用DEVMODE结构。你可以参考下面的代码:
LPDEVMODE GetLandscapeDevMode(HWND hWnd, char *pDevice)
{// pDevice打印机设备名称
HANDLE hPrinter;
LPDEVMODE pDevMode;
DWORD dwNeeded, dwRet;
if (!OpenPrinter(pDevice, &hPrinter, NULL)) //打开打印机设备
return NULL;
/*分配合适的存储空间*/
dwNeeded = DocumentProperties(hWnd,
hPrinter, /* handle to our printer */
pDevice, /* Name of the printer */
NULL, /* Asking for size so */
NULL, /* these are not used. */
0); /* Zero returns buffer size. */
pDevMode = (LPDEVMODE)malloc(dwNeeded);
/*获取打印机的缺省信息并修改它*/
dwRet = DocumentProperties(hWnd, hPrinter, pDevice,
pDevMode, /* The address of the buffer to fill. */
NULL, /* Not using the input buffer. */
DM_OUT_BUFFER); /* Have the output buffer filled. */
if (dwRet != IDOK)
{
/*失败则释放存储空间并退出*/
free(pDevMode);
ClosePrinter(hPrinter);
return NULL;
}
//判断打印机是否支持方向打印
if (pDevMode->dmFields & DM_ORIENTATION)
pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
if (pDevMode->dmFields & DM_DUPLEX)
pDevMode->dmDuplex = DMDUP_HORIZONTAL; //设置打印方向
/*用新的设置信息取代原先的打印设置信息*/
dwRet = DocumentProperties(hWnd, hPrinter, pDevice,
pDevMode, /* Reuse our buffer for output. */
pDevMode, /* Pass the driver our changes. */
DM_IN_BUFFER | /* Commands to Merge our changes and */
DM_OUT_BUFFER); /* write the result. */
/* 关闭打印机设备 */
ClosePrinter(hPrinter);
if (dwRet != IDOK)
{
free(pDevMode);
return NULL;
}
/* 返回变化的DevMode 结构 */
return pDevMode;
}
二、怎样才能学好VC++
读者高朋问:
我是一个VC++编程爱好者,但技术实在是太菜了。所以想请教你怎样才能学好VC++,或者怎样才能入门。能否介绍几本供我这种初学者学习的书或教材?还有,哪里可以找到高手,我可以拜师学艺,能否告诉几个相关网址?
答:心铃建议你:
1. 多读一些简单并具有特色的VC程序(如基于对话框Edit控件内容的显示、定时器等),并自己动手实现这些程序的功能。这是一个不断积累的过程,在这个过程中有必要把一些小的技巧记录下来。
2. 需要熟练掌握一些常用控件的编程(如Edit控件、按钮等)、菜单编程和消息响应(鼠标、键盘等)的实现。
3. 必须熟练掌握一些常用类的使用,如CString、CDialog和CEdit等。
4. 经常使用MSDN帮助说明,查找函数和类的具体使用方法。
5. 有条件可以上网获取一些关于VC编程的文档和源程序。
心铃推荐两本VC的学习书籍:《Visiual C++ 6从入门到精通》(北京希望电子出版社),《Visiual C++ 6轻松进阶》(电子工业出版社),当然你可以到相关的VC站点获取有关的源程序和专题论述等。
心铃推荐VC学习的网站:www.vckbase.com (VC知识库)。
三、有关sizeof的问题
读者sjrnlc问:
我是C++爱好者,有几个问题想问你。
1.) byte = 8 bit,一个英文字母占几个字节?一个数字呢?
2.)我写的程序都是在MS-DOS的环境下,我想将它写成window的界面,怎么办?
3.)有关sizeof的问题:
struct Employee
{
short int emplno;
char* name;
float salarg;
};
我的编译器quincy99对sizeof的运算:短整型占 2 byte,指针占 4 byte,浮点占 4 byte. 加起来也只有 1 0 byte,为什么(书中的)结果是12 byte?
答:1.在C++环境下,char类型的数据占1个字节,short int类型的数据占2个字节,int 类型的数据占4个字节。
2.将MS-DOS环境下的程序加上Windows界面,你可以自己编程实现窗口、菜单等。也可以利用VC生成Windows应用程序的框架,将你的代码加入到框架程序中。
3.VC给struct和union分配空间时,会进行字节对齐(或者分段、打包)。参见MSDN中的"#pragma pack"节。象你这种情况,因为自己没有指定pack,则默认以8字节为一段,因此得到的并不是10个字节,而是12个字节。对齐的方式有以下几种:byte、word、double word、quad word,即1字节、2字节、4字节和8字节,一般默认是quad word对齐方式,编程时可以在代码前用#pragma关键字指定对齐方式;如:#pragma pack(1) 。指定对齐方式编译,这时使用sizeof(Employee)得出的结果是10。
四、怎样打开资源管理器?怎样调SetWindowsHookEx用来安装Hook函数?
读者whiteshark1981问:怎样打开资源管理器?怎样调SetWindowsHookEx用来安装Hook函数?
答:可以利用ShellExecute函数打开资源管理器,下面的代码打开资源管理器,并显示目录下c:\\temp的内容:
ShellExecute(NULL,"explore",_T("c:\\temp"),NULL,NULL,SW_SHOWNORMAL);
要实现Win32的系统钩子,必须调用SDK中的API函数SetWindowsHookEx来安装这个钩子函数,这个函数的原型是HHOOK SetWindowsHookEx(int idHook,HOOKPROC lpfn,HINSTANCE hMod,DWORD dwThreadId);,其中,第一个参数是钩子的类型;第二个参数是钩子函数的地址;第三个参数是包含钩子函数的模块句柄;第四个参数指定监视的线程。如果指定确定的线程,即为线程专用钩子;如果指定为空,即为全局钩子。其中,全局钩子函数必须包含在DLL(动态链接库)中,而线程专用钩子还可以包含在可执行文件中。得到控制权的钩子函数在完成对消息的处理后,如果想要该消息继续传递,那么它必须调用另外一个SDK中的API函数CallNextHookEx来传递它。钩子函数也可以通过直接返回TRUE来丢弃该消息,并阻止该消息的传递。
五、读取与当前程序同一目录下的systemset.ini文件
读者capy问:
我在进行VC程序设计时遇到一个百思不得其解的问题,现写下请心铃老师指教。要读取与当前程序同一目录下的systemset.ini文件。我的方法为:
char path[50];
CString strPath;
::GetCurrentDirectory(50,path); //得到当前应用程序所在的路径
strcat(path,"\\");
strPath=_T(path);
strPath+="systemset.ini"; //将所对应文件改成所要的文件名
int nCount=::GetPrivateProfileInt("AdageCount","Current",0,strPath);
//从ini文件中获得信息
strKeyNameE.Format("AdageE%d",nCount); ::GetPrivateProfileString("AdageSet",strKeyNameE,NULL,strAdageEnglish.GetBuffer(128),128,strPath);
在程序第一次运行时没有错误,(比如为E:\vc\adage\systemset.ini),可是当系统重新启动后(程序会自动运行),程序获得的路径不对了,不是当前与程序同一目录下的文件,而是指向了C:\systemset.ini(在Win200下。在WinXP下为C:\Doucument And Setting\Administrator\systemset.ini)。我不知道为什么会这样。请心铃老师指教。
答:你好,GetCurrentDirectory只是获取当前的目录,当计算机重新启动后,当前的路径一般为系统目录,因此系统启动后,使用该函数只能获取当前的目录,而不是应用程序所在的目录。我建议你使用GetModuleFileName函数,GetModuleFileName()是一个得到路径的API函数。本函数将这个API函数封装在其中,为的是简化调用的目的。
当执行这个函数时,返回本程序所在的绝对路径,包括本程序的文件名。 具体使用方法为:
//获取主程序所在路径,存在sPath中
CString sPath;
GetModuleFileName(NULL,sPath.GetBufferSetLength (MAX_PATH+1),MAX_PATH);
sPath.ReleaseBuffer ();
int nPos;
nPos=sPath.ReverseFind (’’\\’’);
sPath=sPath.Left (nPos);
……
六、改变子窗口的尺寸
读者wengxiong200问:
我用MDI作为主窗口,这样之后我就无法改变子窗口的尺寸,改变Height和Width 的数值无济于事,但若不作为MDI的子窗口的就有效,我想手工改变子窗口的大小, 请问我该如何操作?
答:心铃建议使用API函数MoveWindow,函数原型为:BOOL MoveWindow(
HWND hWnd, // handle of window
int X, // horizontal position
int Y, // vertical position
int nWidth, // width
int nHeight, // height
BOOL bRepaint // repaint flag
);
你可以参考下面的代码:
……
TMDIChild *Child;
//--- create a new MDI child window ----
Child = new TMDIChild(Application);
Child->Caption = Name;
if (FileExists (Name))
Child->Memo1->Lines->LoadFromFile(Name);
MoveWindow(Child->Handle,0,0,200,400,true);
……
七、编译链接和窗口重画问题
读者Yuan Jinrong问:
非常感谢您上次解答了我的关于VC编程中遇到的难题,现在我又遇到一些问题,特来信请教:两个问题:
1.编译链接
我写的一个文档/视图结构的VC程序,除了MFC外还有另外的一个库文件,我将这个库文件及其头文件都拷贝到所在目录,当use MFC in a shared DLL,顺利链接连接,程序能运行,但当use MFC in a Static Library时出现以下连接错误:
错误信息如下:
Generating Code...
Linking...
msvcrt.lib(MSVCRT.dll) : error LNK2005: _memmove already defined in libcmt.lib(memmove.obj)
msvcrt.lib(MSVCRT.dll) : error LNK2005: __mbscmp already defined in libcmt.lib(mbscmp.obj)
msvcrt.lib(MSVCRT.dll) : error LNK2005: __setmbcp already defined in libcmt.lib(mbctype.obj)
LINK : warning LNK4098: defaultlib "mfc42.lib" conflicts with use of other libs; use /NODEFAULTLIB:library
LINK : warning LNK4098: defaultlib "mfcs42.lib" conflicts with use of other libs; use /NODEFAULTLIB:library
LINK : warning LNK4098: defaultlib "msvcrt.lib" conflicts with use of other libs; use /NODEFAULTLIB:library
Release/FEMprocess.exe : fatal error LNK1169: one or more multiply defined symbols found Error executing link.exe.
FEMprocess.exe - 4 error(s), 120 warning(s)
2.窗口重画问题
有一个基于对话框的程序,其中有一个Picture控件用于显示计算结果的图形,但每次该对话框失去焦点后(比如操作另外的软件覆盖了该对话框),再回到该对话框界面时,原来的图形不能自动重新显示出来,我希望能在回到该对话框界面后,自动刷新,不知如何实现?
答:心铃建议你在工程设置中添加lib库文件,点击工程菜单下的工程设置子菜单,弹出工程设置对话框,在该对话框的link属性页上的对象/库模块一栏中添加库文件的名称,再编译试试。
第二个问题,心铃建议在对话框的OnPaint事件中添加显示的代码,同OnDraw事件相同,当窗口焦点或者尺寸发生变化时,产生该事件,另外计算的代码不要添加在该事件中,否则重画的速度缓慢。
|
|
文章检索
编程>热门文章
|