Visual C++技巧问答 - 11 February 2009 - Blog - ystyle paltform
Home » 2009 » February » 11 » Visual C++技巧问答
4:38 PM
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事件相同,当窗口焦点或者尺寸发生变化时,产生该事件,另外计算的代码不要添加在该事件中,否则重画的速度缓慢。
Views: 484 | Added by: ystyle | Rating: 0.0/0
Total comments: 0
Only registered users can add comments.
[ Sign Up | Log In ]