梦想空间's profile梦想空间PhotosBlogListsMore ![]() | Help |
|
|
June 22 五种VC++数据库开发技术的比较(收藏)从功能简单的数据库(如Jet Engine)到复杂的大型数据库系统(如oracle),VC++6.0都提供了一些编程接口。本文主要介绍以下五种: 1.ODBC API; 2.MFC ODBC类; 3.MFC DAO类;(数据访问对象) 4.MFC的OLE/DB; 5.ActiveX数据对象(ADO)。 1.开放数据库连接(ODBC API) 提供了一个通用的编程接口,允许程序与多种不同的数据库连接。它为Oracle,SQL Server,MS Excel等都提供了驱动程序,使得用户可以使用SQL语句对数据库进行直接的底层功能操作。在使用ODBC API时,用户须引入的头文件为"sql.h","sqlext.h","sqltypes.h"。用ODBC API创建数据库应用程序遵循一定的基本步骤: MFC1.5后的版本里引入封装了ODBC功能的类。通过这些类提供与ODBC的接口,使得用户可以不须处理ODBC API中的繁杂处理就可以进行数据库操作。主要的MFC ODBC类如下。 3.MFC DAO(数据访问对象)编程 DAO用于和微软的Access数据库接口。在数据库应用程序如果只需与Access数据库接口时,使用DAO编程较方便。其主要类如下。 OLE DB在数据提供程序和用户之间提供了灵活的组件对象模型(COM)接口,这种灵活性有时会使得操作复杂化。OLE DB框架定义了应用的三个基本类。 是微软提供的面向对象的接口,与OLE DB类似,但接口更简单,具有更广泛的特征数组和更高程度的灵活性。ADO基于COM,提供编程语言可利用的对象,除了面向VC++,还提供面向其他各种开发工具的应用,如VB,VJ等。ADO在服务器应用方面非常有用,特别是对于动态服务器页面ASP(Active Server Page)。 June 17 技巧1. 如何激活当前屏幕保护程序 //激活当前屏幕保护程序, jingzhou xu PostMessage(WM_SYSCOMMAND,SC_SCREENSAVE,0); 2. 如何禁止/启用屏幕保护及电源管理 static UINT dss_GetList[] = {SPI_GETLOWPOWERTIMEOUT, SPI_GETPOWEROFFTIMEOUT, SPI_GETSCREENSAVETIMEOUT}; static UINT dss_SetList[] = {SPI_SETLOWPOWERTIMEOUT, SPI_SETPOWEROFFTIMEOUT, SPI_SETSCREENSAVETIMEOUT}; static const int dss_ListCount = _countof(dss_GetList); l 禁止屏幕保护及电源管理 { m_pValue = new int[dss_ListCount]; for (int x=0;x<dss_ListCount;x++) { //禁止屏幕保护及电源管理 VERIFY(SystemParametersInfo (dss_SetList[x], 0, NULL, 0)); } delete[] m_pValue; } l 启用屏幕保护及电源管理 { m_pValue = new int[dss_ListCount]; for (int x=0;x<dss_ListCount;x++) { //启用屏幕保护及电源管理 VERIFY(SystemParametersInfo (dss_SetList[x], m_pValue[x], NULL, 0)); } delete[] m_pValue; } 3. 如何激活和关闭IE浏览器 //激活并打开IE void lounchIE() { HWND h=FindWindowEx(NULL,NULL,NULL, "Microsoft Internet Explorer") ; ShellExecute(h,"open","C:\\simple.html", NULL,NULL,SW_SHOWNORMAL); } //关闭IE及其它应用 void CloseIE() { int app=BSM_APPLICATIONS; unsigned long bsm_app=(unsigned long )app; BroadcastSystemMessage(BSF_POSTMESSAGE,&bsm_app, WM_CLOSE,NULL,NULL); } 4. 如何给树控件加入工具提示 l 首先给树控件加入TVS_INFOTIP属性风格,如下所示: if (!m_ctrlTree.Create(WS_CHILD ¦WS_VISIBLE ¦ TVS_HASLINES ¦TVS_HASBUTTONS ¦TVS_LINESATROOT ¦TVS_SHOWSELALWAYS ¦TVS_INFOTIP, //加入提示TVS_INFOTIP,jingzhou xu(树控件ID:100) CRect(0, 0, 0, 0), &m_wndTreeBar, 100)) { TRACE0("Failed to create instant bar child\n"); return -1; } l 其次加入映射消息声明,如下所示: afx_msg void OnGetInfoTip(NMHDR* pNMHDR,LRESULT* pResult); //树控件上加入提示消息,jingzhou xu ON_NOTIFY(TVN_GETINFOTIP, 100, OnGetInfoTip) //树控件条目上加入提示,jingzhou xu l 最后加入呼应涵数处理: void CCreateTreeDlg::OnGetInfoTip(NMHDR* pNMHDR, LRESULT* pResult) { *pResult = 0; NMTVGETINFOTIP* pTVTipInfo = (NMTVGETINFOTIP*)pNMHDR; LPARAM itemData = (DWORD) pTVTipInfo->lParam; //对应每个条目的数据 HTREEITEM hItem = pTVTipInfo->hItem; CString tip; HTREEITEM hRootItem = m_chassisTree.GetRootItem(); if (hRootItem != pTVTipInfo->hItem) { tip = "树结点的提示"; } else { tip = "树根上的提示"; } strcpy(pTVTipInfo->pszText, (LPCTSTR) tip); } 5. 如何获取系统信息框的路径 #include <atlbase.h> #define IDS_REG_KEY_MSINFO_PATH1 _T( "Software\\Microsoft\\Shared Tools\\MSInfo" ) #define IDS_REG_KEY_MSINFO_PATH2 _T( "Software\\Microsoft\\Shared Tools Location" ) #define IDS_REG_VAL_MSINFO_PATH1 _T( "Path" ) #define IDS_REG_VAL_MSINFO_PATH2 _T( "MSInfo" ) #define IDS_MSINFO_EXE_NAME _T( "MSInfo32.exe" ) //... BOOL GetSysInfoPath( CString& strPath ) { strPath.Empty(); LPTSTR pszPath = strPath.GetBuffer( MAX_PATH ); CRegKey reg; DWORD dwSize = MAX_PATH; LONG nRet = reg.Open( HKEY_LOCAL_MACHINE, IDS_REG_KEY_MSINFO_PATH1, KEY_READ ); //在注册表中寻找第一个"MSInfo32.exe"位置 if ( nRet == ERROR_SUCCESS ) { #if ( _MFC_VER >= 0x0700 ) nRet = reg.QueryStringValue( IDS_REG_VAL_MSINFO_PATH1, pszPath, &dwSize ); #else nRet = reg.QueryValue( pszPath, IDS_REG_VAL_MSINFO_PATH1, &dwSize ); #endif reg.Close(); } //如果第一次寻找失败,则进行第二次寻找 if ( nRet != ERROR_SUCCESS ) { nRet = reg.Open( HKEY_LOCAL_MACHINE, IDS_REG_KEY_MSINFO_PATH2, KEY_READ ); if ( nRet == ERROR_SUCCESS ) { #if ( _MFC_VER >= 0x0700 ) reg.QueryStringValue( IDS_REG_VAL_MSINFO_PATH2, pszPath, &dwSize ); #else reg.QueryValue( pszPath, IDS_REG_VAL_MSINFO_PATH2, &dwSize ); #endif //路径名不包括EXE文件名 if ( nRet == ERROR_SUCCESS ) VERIFY( ::PathAppend( pszPath, IDS_MSINFO_EXE_NAME ) ); reg.Close( --------------------------------------------------------------- 7. 如何遍历整个目录 #include <windows.h> #include <shlobj.h> //浏览目录. void BrowseFolder( void ) { TCHAR path[MAX_PATH]; BROWSEINFO bi = { 0 }; bi.lpszTitle = ("递归调用所有目录"); LPITEMIDLIST pidl = SHBrowseForFolder ( &bi ); if ( pidl != 0 ) { //获取目录路径 SHGetPathFromIDList ( pidl, path ); //设置为当前路径 SetCurrentDirectory ( path ); //搜索所有子目录 SearchFolder( path ); //释放内存 IMalloc * imalloc = 0; if ( SUCCEEDED( SHGetMalloc ( &imalloc )) ) { imalloc->Free ( pidl ); imalloc->Release ( ); } } //搜索其下所有子目录及文件. void SearchFolder( TCHAR * path ) { WIN32_FIND_DATA FindFileData; HANDLE hFind; TCHAR filename[ MAX_PATH + 256 ]; TCHAR pathbak[ MAX_PATH ]; //复制初始用户选择目录 strcpy( pathbak, path ); //寻找第一个文件 hFind = FindFirstFile ( "*.*", &FindFileData ); //搜索所有文件及子目录 do { if ( hFind != INVALID_HANDLE_VALUE ) { //如果是当前目录或父目录,跳过 if ( ! ( strcmp( FindFileData.cFileName, "." ) ) ¦ ¦ ! ( strcmp( FindFileData.cFileName, ".." ) ) ) { continue; } //恢复初始用户选择目录 strcpy( path, pathbak ); //列出所有发现的文件 sprintf( path, "%s\\%s", path, FindFileData.cFileName ); //如果SetCurrentDirectory成功的话,则它是一个目录,递归调用继续搜索子目录 if ( ( SetCurrentDirectory( path ) ) ) { SearchFolder( path ); } //插入文件及路径名到列表框m_listbox_hwnd中 SendMessage( m_listbox_hwnd, LB_ADDSTRING, 0, path ); //<--INSERT WHAT YOU WANT DONE HERE! } } while ( FindNextFile ( hFind, &FindFileData ) && hFind != INVALID_HANDLE_VALUE ); FindClose ( hFind ); } 8. 如何禁止/启用系统热键 bool bOld; l 禁止系统热键 //屏蔽掉系统键 SystemParametersInfo(SPI_SETSCREENSAVERRUNNING,true,&bOld,SPIF_UPDATEINIFILE); l 启用系统热键 //恢复系统热键 SystemParametersInfo(SPI_SETSCREENSAVERRUNNING,false,&bOld,SPIF_UPDATEINIFILE); 9. 如何隐藏/显示WINDOWS系统任务栏 l 隐藏系统任务栏 //隐藏WINDOWS系统任务栏 ::ShowWindow (::FindWindow("Shell_TrayWnd",NULL),SW_HIDE); l 显示系统任务栏 //恢复WINDOWS系统任务栏正常显示 ::ShowWindow (::FindWindow("Shell_TrayWnd",NULL),SW_SHOW); VC编程经验总结1. 如何获取应用程序的实例句柄?
应用程序的 实例句柄保存在CWinAppIm_hInstance 中,可以这么调用 AfxGetInstancdHandle获得句柄. Example: HANDLE hInstance=AfxGetInstanceHandle(); 2. 如何通过代码获得应用程序主窗口的指针? 主窗口的 指针保存在CWinThread::m_pMainWnd中,调用 AfxGetMainWnd实现。 AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED); //使程序最大化. 3. 如何在程序中获得其他程序的 图标? 两种方法: (1) SDK函数 SHGetFileInfo 或使用 ExtractIcon获得图标资源的 handle, (2) SDK函数 SHGetFileInfo获得有关文件的 很多信息,如大小图标,属性,类型等. Example(1): 在程序窗口左上角显示 NotePad图标. void CSampleView: OnDraw(CDC * pDC) { if( :: SHGetFileInfo(_T("c:\\pwin95\\notepad.exe"),0, &stFileInfo,sizeof(stFileInfo),SHGFI_ICON)) { pDC ->DrawIcon(10,10,stFileInfo.hIcon); } } Example(2): 同样功能,Use ExtractIcon Function void CSampleView:: OnDraw(CDC *pDC) { HICON hIcon=:: ExtractIcon(AfxGetInstanceHandle(),_T ("NotePad.exe"),0); if (hIcon &&hIcon!=(HICON)-1) pDC->DrawIcon(10,10,hIcon); } 说明: 获得notepad.exe 的路径正规上来说用GetWindowsDirectory 函数得到,如果是 调用 win95下的画笔,应该用访问注册表的方法获得其路径,要作成一个比较考究的程 序,考虑应该全面点. 4. 如何编程结束应用程序?如何编程控制windows 的重新引导? 这是个很简单又是编程中经常要遇到的问题. 第一问,向窗口发送 WM_CLOSE消息,调用 CWnd::OnClose成员函数.允许对用户提示 是否保存修改过的数据. Example: AfxGetMainWindow()->SendMessage(WM_CLOSE); 还可以创建一个自定义的函数 Terminate Window void Terminate Window(LPCSTR pCaption) { CWnd *pWnd=Cwnd::FindWindow(NULL,pCaption); if (pWnd) pWnd ->SendMessage(WM_CLOSE); } 说明: FindWindow 函数不是提倡的做法,因为它无法处理标题栏自动改变,比如我们要 检测 Notepad 是不是已运行而事先不知道Notepad 的标题栏,这时 FindWindow 就无能 为力了,可以通过枚举 windows 任务列表的办法来实现。 在 机械出版社"Windows 95 API开发人员指南"一书有比较详细的介绍,这里就不再多说乐。 第二问,Use ExitWindowsEx Function 函数控制系统是重新引导,还是重启 windows. 前面已经有人讲过乐,就不再提了。 5. 怎样加栽其他的应用程序? 我记得这好象是出场频度很高的问题。 三个SDK函数 winexec, shellexecute,createprocess可以使用。 WinExec 最简单,两个参数,前一个指定路径,后一个指定显示方式.后一个参数值得说 一下,比如泥用 SW_SHOWMAXMIZED 方式去加栽一个无最大化按钮的 程序,呵呵就是 Neterm,calc 等等,就不会出现正常的 窗体,但是已经被加到任务列表里了。 ShellExecute较 WinExex灵活一点,可以指定工作目录,下面的 Example就是直接打开 c:\temp\1.txt,而不用加栽与 txt 文件关联的应用程序,很多安装程序完成后都会打开 一个窗口,来显示Readme or Faq,偶猜就是这么作的啦. ShellExecute(NULL,NULL,_T("1.txt"),NULL,_T("c:\\temp"),SW_SHOWMAXMIZED); CreateProcess最复杂,一共有十个参数,不过大部分都可以用NULL 代替,它可以指定 进程的安全属性,继承信息,类的优先级等等.来看个很简单的 Example: STARTUPINFO stinfo; //启动窗口的信息 PROCESSINFO procinfo; //进程的信息 CreateProcess(NULL,_T("notepad.exe"),NULL,NULL.FALSE, NORMAL_PRIORITY_ CLASS,NULL,NULL, &stinfo,&procinfo); 6. 确定应用程序的 路径 前些天好象有人问过这个问题. Use GetModuleFileName 获得应用程序的路径,然后去掉可执行文件名。 Example: TCHAR exeFullPath[MAX_PATH]; // MAX_PATH在API中定义了吧,好象是128 GetModuleFileName(NULL,exeFullPath,MAX_PATH) 7. 获得各种目录信息 Windows目录: Use "GetWindowsDirectory“ Windows下的system目录: Use "GetSystemDirectory" temp目录: Use "GetTempPath " 当前目录: Use "GetCurrentDirectory" 请注意前两个函数的第一个参数为 目录变量名,后一个为缓冲区; 后两个相反. 8. 如何自定义消息 也有人问过的,其实不难。 (1) 手工定义消息,可以这么写 #define WM_MY_MESSAGE(WM_USER+100), MS 推荐的至 少是 WM_USER+100; (2)写消息处理函数,用 WPARAM,LPARAM返回LRESULT. LRESULT CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam) { //加入你的处理函数 } (3) 在类的 AFX_MSG处进行声明,也就是常说的"宏映射" 9. 如何改变窗口的图标? 向窗口发送 WM_SECTION消息。 Example: HICON hIcon=AfxGetApp() ->LoadIcon(IDI_ICON); ASSERT(hIcon); AfxGetMainWnd() ->SendMessage(WM_SECTION,TRUE,(LPARAM) hIcon); 10. 如何改变窗口的缺省风格? 重栽 CWnd:: PreCreateWindow 并修改CREATESTRUCT 结构来指定窗口风格和其他创建 信息. Example: Delete "Max" Button and Set Original Window's Position and Size BOOL CMainFrame:: PreCreateWindow (CREATESTRUCT &cs) { cs.style &=~WS_MAXINIZEMOX; cs.x=cs.y=0; cs.cx=GetSystemMetrics(SM_CXSCREEN/2); cs.cy=GetSystemMetrics(SM_CYSCREEN/2); return CMDIFramewnd ::PreCreateWindow(cs); } 11. 如何将窗口居中显示? Easy, Call Function CWnd:: Center Windows Example(1): Center Window( ); //Relative to it's parent // Relative to Screen Example(2): Center Window(CWnd:: GetDesktopWindow( )); //Relative to Application's MainWindow AfxGetMainWnd( ) -> Center Window( ); 12. 如何让窗口和 MDI窗口一启动就最大化和最小化? 先说窗口。 在 InitStance 函数中设定 m_nCmdShow的 取值. m_nCmdShow=SW_SHOWMAXMIZED ; //最大化 m_nCmdShow=SW_SHOWMINMIZED ; //最小化 m_nCmdShow=SW_SHOWNORMAL ; //正常方式 MDI窗口: 如果是创建新的应用程序,可 LIB里面有和IntvnOptics.cpp里面一样的函数实现。估计你在编译库的时候将NewtonRingsCreate的实现写在头文件里面,然后你使用库的那个CPP文件include了那个头文件。 ll.h // void func() { //... } ll.cpp #include "ll.h" 以上两个文件编译成lib,使用库的时候 ul.cpp #include "ll.h" 这时候ul里面也连接了func,lib里面也有func。 解决方法: 1、实现放到CPP里面 或者 2、使用inline修饰 inline void func() { //... } --------------------------------------------------------------- 另外,个人觉得VC不是一个好东东. 学它主要是为了提高一点能力.要是只知道跟着MS小心中弹. 大伙儿还是得先去把数据结构,编译原理,操作系统学好。 还得学好哲学,历史,数学,工程学,经济学,美学.......哈哈,我瞎掰了. --------------------------------------------------------------- 我很丑,可是我很温柔。我很温柔,不过我很丑。 10进制:0-9,只有十进制的才有正负之分。 16进制:以0x或0X开头,0-9+a-f(A-F) 8进制:以0开头,0-7 默认的数是double型,有f\F表示float型,有l\L表示long double型。 C语言中,#include “stdio.h” 格式控制符: d:十进制 o:八进制 x:十六进制 c:单个字符 f:浮点数(double\float) e\E:浮点数(输入和f一样,科学计数发输出) s:以’\0’结束的字符串 u:十进制无符号 g:f\e中较短的一种 指定字符宽: *:删除空格前剩余数 0:前面补0,而不是补空格 格式控制:% +/- m . n l/h □ +/-:对齐方式,默认+,右对齐;-左对齐。 m:输出宽度(float时候包含小数点),大于时按实际输出,小于时补空格 . :小数点,float\double时候才用 n:小数点后面的位数,float\double时候才用 l/h:表示是long\shot □:格式控制符d\o\x\c\f\e\s\u\g --------------------------------------------------------------- 设置窗口的透明度(win2000以上) ----------------------------------- 第一步 定义功能 typedef BOOL (FAR PASCAL * FUNC1)( HWND hwnd, // handle to the layered window COLORREF crKey, // specifies the color key BYTE bAlpha, // value for the blend function DWORD dwFlags // action ); 第二步 实现代码 在OnInitDialog中加入下列代码(如果在SDI里面,应该是在OnCreat里面添加) ..... HMODULE hModule = GetModuleHandle("user32.dll"); FUNC1 SetLayeredWindowAttributes; SetLayeredWindowAttributes = (FUNC1) GetProcAddress (hModule, _T( "SetLayeredWindowAttributes" ) ); // 设置分层扩展标记 SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE) ¦ 0x80000L); // 70% alpha SetLayeredWindowAttributes(GetSafeHwnd(), 0, (255 * 70) / 100, 0x2); 工作完成,怎么样,现在你可以运行你的程序来查看效果,即使背景变化也能立刻反映到你的窗口当中,这一点比金山词霸的效果要好。 第三步:如何除去透明选项? // 除去分层扩展标记 SetWindowLong(GetSafeHwnd(),, GWL_EXSTYLE, GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE) & ~ 0x80000L); // 重画窗口 RedrawWindow(); --------------------------------------------------------------- 斑竹很负责任啊。 技术方面偶的水平差的很,就不说了。以下是偶的一点经验之谈: 1、调试程序的时候有简单到复杂:碰到程序运行出错时,可以先把一些程序注释掉,只留很少的一部分,确保程序的正确运行,然后再逐段逐段代码的释放,很容易发现问题所在。 2、单独做试验:对程序中用到的一些独立的模块和功能,如果不是太熟悉或则把握不准,可以单独的写一个小的程序去做试验,验证用法以及结果。不要在很大的工程中调试某些独立的模块。 3、仔细认真地作试验。在研究一个新的控件或功能时,要象对待正式程序一样认真的对待,否则如果出现错误,你就有可能得出一个错误的结论,一旦用到整个的程序中就会是一个很难发现的错误,浪费大量的时间去查找其他的代码。 4、有时候错误的程序会莫名其妙的运行正常,但你并没有找到出错的原因。这时千万不要高兴太,应该继续调试和试验,一定要把错误找出来。只要你找不出来,这个错误就是一个炸弹,不一定什么时候发作。 5、进行数据库操作的时候,碰到比较复杂的SQL语句,最好先在数据库中执行测试你的SQL语句,以保证该语句的正确性。 6、建议在操作数据库的时候使用“事务处理”,否则程序在运行时(特别在网络中)会遇到意想不到的问题,如:网络不稳定可能会使你的操作只执行一部分。 7、长期连续运行的程序中,一些复杂的功能不要在定时器(OnTimer)中完成,而尽量使用线程完成,我的感觉是,放在线程中要比定时器稳定的多。(只是我自己的看法) --------------------------------------------------------------- 谢谢bluebohe (薄荷) ! 对我帮助挺大。 我也凑凑热闹: 下面是一个VC调试观察窗口的格式化符号表格,希望对大家有帮助 —————————————————————————————————— 符号 格式 例子 输出 d或者i 有符号十进制整数 -42,d -42 U 无符号十进制整数 42,d 42 O 无符号八进制整数 42,o 052 x或X 十六进制整数 42,x 0x0000002a或0x0000002A H 为d,I,u,o,x显示前缀 42,hx 0X002a F 有符号浮点数 1.5,f 1.500000 E 有符号科学计数法 1.5,e 1.500000e+000 G 压缩的有符号浮点数 1.5,g 1.5 C 字符 42,c '*' S ANSI字符串 "bugs",s "bugs" Su Unicode字符串 "bugs",st "bugs" Hr HRESULT和Win32错误码 0X06,hr The handle is invalid wm Windows消息号 0x01,wm WM_CREATE [digits] 显示数组元素 s,5 显示s[]前五个值 --------------------------------------------------------------- 自己水平有限 就奉献一篇文章表示支持 也希望大家以后多多帮助 AND_CATCHAND_CATCH AND_CATCH(exception_class,exception _object_point_name) 说明: 定义一个代码块,它用于获取废除当前TRY块中的附加异常类型。使用CATCH宏以获得一个异常类型,然后使用AND_CATCH宏获得随后的异常处理代码可以访问异常对象(若合适的话)已得到关于异常的特别原因的更多消息。在AND_CATCH块中调用THROW_LAST宏以便把处理过程移到下个外部异常框架。AND_CATCH可标记CATCH或AND_CATCH块的末尾。 注释: AND_CATCH块被定义成为一个C++作用域(由花括号来描述)。若用户在此作用域定义变量,那么记住他们只在此作用域中可以访问。他也用于exception_object_pointer_name变量。 ASSERT ASSERT(booleanExpression) 说明: 计算变量的值。如果结构的值为0,那么此宏便打印一个诊断消息并且成讯运行失败。如果条件为非0,那么什么也不做。 诊断消息的形式为: assertion failed in file in line 其中name是元文件名,num是源文件中运行失败的中断号。 在Release版中,ASSERT不计算表达式的值也就不中断程序。如果必须计算此表达式的值且不管环境如何那么用VERIFY代替ASSERT。 注释: ASSERT只能在Debug版中用 ASSERT_VAILD ASSERT_VAILD(pObject) 说明: 用于检测关于对象的内部状态的有效性。ASSERT_VALID调用此对象的AssertValid成员函数(把它们作为自己的变量来传递)。在Release版中ASSERT_VALID什么也不做。在DEBUG版中,他检查指针,以不同于NULL的方式进行检查,并调用对象自己的AssertValid成员函数。如果这些检测中有任何一个失败的话,那么他会以与ASSERT相同的方法显示一个警告的消息。 注释: 此函数只在DEBUG版中有效。 BEGIN_MESSAGE_MAP BEGIN_MESSAGE_MAP(the class,baseclass) 说明: 使用BEGIN_MESSAGE_MAP开始用户消息映射的定义。在定义用户类函数的工具(.cpp)文件中,以BEGIN_MESSAGE_MAP宏开始消息映射,然后为每个消息处理函数增加宏项,接着以END_MESSAGE_MAP宏完成消息映射。 CATCH CATCH(exception_class,exception_object_pointer_name) 说明: 使用此用定义一个代码块,此代码用来获取当前TRY块中都一个异常类型。异常处理代码可以访问异常对象,如何合适的话,就会得到关于异常的特殊原因的更多消息。调用THROW_LAST宏以把处理过程一下一个外部异常框架,如果exception-class是类CExceptioon,那么会获取所有异常类型。用户可以使用CObject::IsKindOf成员函数以确定那个特别异常被排除。一种获取异常的最好方式是使用顺序的AND_CATCH语句,每个带一个不同的异常类型。此异常类型的指针由宏定义 VC数据类型转换大全VC常用数据类型使用转换详解 2002-7-29 12:40:48 PCVC.NET 程佩君 阅读次数: 7824 刚接触VC编程的朋友往往对许多数据类型的转换感到迷惑不解,本文将介绍一些常用数据类型的使用。 我们先定义一些常见类型变量借以说明 int i = 100; long l = 2001; float f=300.2; double d=12345.119; char username[]="女侠程佩君"; char temp[200]; char *buf; CString str; _variant_t v1; _bstr_t v2; 一、其它数据类型转换为字符串 短整型(int) itoa(i,temp,10);///将i转换为字符串放入temp中,最后一个数字表示十进制 itoa(i,temp,2); ///按二进制方式转换 长整型(long) ltoa(l,temp,10); ////////////////////////////////////////// 二、从其它包含字符串的变量中获取指向该字符串的指针 CString变量 str = "2008北京奥运"; buf = (LPSTR)(LPCTSTR)str; BSTR类型的_variant_t变量 v1 = (_bstr_t)"程序员"; buf = _com_util::ConvertBSTRToString((_bstr_t)v1); ////////////////////////////////////////////// 三、字符串转换为其它数据类型 strcpy(temp,"123"); 短整型(int) i = atoi(temp); 长整型(long) l = atol(temp); 浮点(double) d = atof(temp); 四、其它数据类型转换到CString 使用CString的成员函数Format来转换,例如: 整数(int) str.Format("%d",i); 浮点数(float) str.Format("%f",i); 字符串指针(char *)等已经被CString构造函数支持的数据类型可以直接赋值 str = username; 五、BSTR、_bstr_t与CComBSTR CComBSTR、_bstr_t是对BSTR的封装,BSTR是指向字符串的32位指针。 char *转换到BSTR可以这样: BSTR b=_com_util::ConvertStringToBSTR("数据");///使用前需要加上头文件comutil.h 反之可以使用char *p=_com_util::ConvertBSTRToString(b); 六、VARIANT 、_variant_t 与 COleVariant VARIANT的结构可以参考头文件VC98\Include\OAIDL.H中关于结构体tagVARIANT的定义。 对于VARIANT变量的赋值:首先给vt成员赋值,指明数据类型,再对联合结构中相同数据类型的变量赋值,举个例子: VARIANT va; int a=2001; va.vt=VT_I4;///指明整型数据 va.lVal=a; ///赋值 对于不马上赋值的VARIANT,最好先用Void VariantInit(VARIANTARG FAR* pvarg);进行初始化,其本质是将vt设置为VT_EMPTY,下表我们列举vt与常用数据的对应关系: unsigned char bVal; VT_UI1 short iVal; VT_I2 long lVal; VT_I4 float fltVal; VT_R4 double dblVal; VT_R8 VARIANT_BOOL boolVal; VT_BOOL SCODE scode; VT_ERROR CY cyVal; VT_CY DATE date; VT_DATE BSTR bstrVal; VT_BSTR IUnknown FAR* punkVal; VT_UNKNOWN IDispatch FAR* pdispVal; VT_DISPATCH SAFEARRAY FAR* parray; VT_ARRAY ¦* unsigned char FAR* pbVal; VT_BYREF ¦VT_UI1 short FAR* piVal; VT_BYREF ¦VT_I2 long FAR* plVal; VT_BYREF ¦VT_I4 float FAR* pfltVal; VT_BYREF ¦VT_R4 double FAR* pdblVal; VT_BYREF ¦VT_R8 VARIANT_BOOL FAR* pboolVal; VT_BYREF ¦VT_BOOL SCODE FAR* pscode; VT_BYREF ¦VT_ERROR CY FAR* pcyVal; VT_BYREF ¦VT_CY DATE FAR* pdate; VT_BYREF ¦VT_DATE BSTR FAR* pbstrVal; VT_BYREF ¦VT_BSTR IUnknown FAR* FAR* ppunkVal; VT_BYREF ¦VT_UNKNOWN IDispatch FAR* FAR* ppdispVal; VT_BYREF ¦VT_DISPATCH SAFEARRAY FAR* FAR* pparray; VT_ARRAY ¦* VARIANT FAR* pvarVal; VT_BYREF ¦VT_VARIANT void FAR* byref; VT_BYREF _variant_t是VARIANT的封装类,其赋值可以使用强制类型转换,其构造函数会自动处理这些数据类型。 例如: long l=222; ing i=100; _variant_t lVal(l); lVal = (long)i; COleVariant的使用与_variant_t的方法基本一样,请参考如下例子: COleVariant v3 = "字符串", v4 = (long)1999; CString str =(BSTR)v3.pbstrVal; long i = v4.lVal; 七、其它 对消息的处理中我们经常需要将WPARAM或LPARAM等32位数据(DWORD)分解成两个16位数据(WORD),例如: LPARAM lParam; WORD loValue = LOWORD(lParam);///取低16位 WORD hiValue = HIWORD(lParam);///取高16位 对于16位的数据(WORD)我们可以用同样的方法分解成高低两个8位数据(BYTE),例如: WORD wValue; BYTE loValue = LOBYTE(wValue);///取低8位 BYTE hiValue = HIBYTE(wValue);///取高8位 --------------------------------------------------------------- int ->str itoa,atoi double- str ftoa,atof _bstr_t,_variant_t,CString,long 等等看看下面: 我给你点详细的例子,看下面 先看懂_variant_t与_bstr_t这两个类的构造函数和 operator= 里面有重载了很多情况, 其他类型向_variant_t 赋值: _variant_t( ) throw( ); _variant_t( const VARIANT& varSrc ) throw( _com_error ); _variant_t( const VARIANT* pVarSrc ) throw( _com_error ); _variant_t( const _variant_t& var_t_Src ) throw( _com_error ); _variant_t( VARIANT& varSrc, bool fCopy ) throw( _com_error ); _variant_t( short sSrc, VARTYPE vtSrc = VT_I2 ) throw( _com_error ); _variant_t( long lSrc, VARTYPE vtSrc = VT_I4 ) throw( _com_error ); _variant_t( float fltSrc ) throw( ); _variant_t( double dblSrc, VARTYPE vtSrc = VT_R8 ) throw( _com_error ); _variant_t( const CY& cySrc ) throw( ); _variant_t( const _bstr_t& bstrSrc ) throw( _com_error ); _variant_t( const wchar_t *wstrSrc ) throw( _com_error ); _variant_t( const char* strSrc ) throw( _com_error ); _variant_t( bool bSrc ) throw( ); _variant_t( IUnknown* pIUknownSrc, bool fAddRef = true ) throw( ); _variant_t( IDispatch* pDispSrc, bool fAddRef = true ) throw( ); _variant_t( const DECIMAL& decSrc ) throw( ); _variant_t( BYTE bSrc ) throw( ); operator=的重载形式: _variant_t& operator=( const VARIANT& varSrc ) throw( _com_error ); _variant_t& operator=( const VARIANT* pVarSrc ) throw( _com_error ); _variant_t& operator=( const _variant_t& var_t_Src ) throw( _com_error ); _variant_t& operator=( short sSrc ) throw( _com_error ); _variant_t& operator=( long lSrc ) throw( _com_error ); _variant_t& operator=( float fltSrc ) throw( _com_error ); _variant_t& operator=( double dblSrc ) throw( _com_error ); _variant_t& operator=( const CY& cySrc ) throw( _com_error ); _variant_t& operator=( const _bstr_t& bstrSrc ) throw( _com_error ); _variant_t& operator=( const wchar_t* wstrSrc ) throw( _com_error ); _variant_t& operator=( const char* strSrc ) throw( _com_error ); _variant_t& operator=( IDispatch* pDispSrc ) throw( _com_error ); _variant_t& operator=( bool bSrc ) throw( _com_error ); _variant_t& operator=( IUnknown* pSrc ) throw( _com_error ); _variant_t& operator=( const DECIMAL& decSrc ) throw( _com_error ); _variant_t& operator=( BYTE bSrc ) throw( _com_error ); 有了以上两个函数,举个例子: double f=1.0 _variant_t v; v=f; //是合法的看看operator=的重载形式就知道了 CString str="ddd" _variant_t v; v=str.AllocSysString() 或者v=(_bstr_t)(char*)str; 即可 _variant_t转换成别的形式 你首先必须确定你要转化成什么样的形式 double f; _variant_t v f=v.dblVal 即可或者f=(double)v;也可以 附:_variant_t的操作符 operator short( ) const throw( _com_error ); operator long( ) const throw( _com_error); operator float( ) const throw( _com_error ); operator double( ) const throw( _com_error ); operator CY( ) const throw( _com_error ); operator bool( ) const throw( _com_error ); operator DECIMAL( ) const throw( _com_error ); operator BYTE( ) const throw( _com_error ); operator _bstr_t( ) const throw( _com_error ); operator IDispatch*( ) const throw( _com_error ); operator IUnknown*( ) const throw( _com_error ); June 16 已知文件句柄,求文件名zhucde(【風間苍月】)(MVP)曾经给出这么一个解决方案: CString str; 句柄->GetWindowText(str); str中部分即为文件标题,其中部分即为文件名 不过我4了一下,失败 ——! --------------------------------------------------------------- http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/obtaining_a_file_name_from_a_file_handle.asp Obtaining a File Name From a File Handle The following example obtains a file name from a file handle using a file mapping object. It uses the CreateFileMapping and MapViewOfFile functions to create the mapping. Next, it uses the GetMappedFileName function to obtain the file name. For remote files, it prints the device path received from this function. For local files, it converts the path to use a drive letter and prints this path. To test this code, create a main function that opens a file using CreateFile and passes the resulting handle to GetFileNameFromHandle. #include 怎么扫描出一个特定程序的具体位置1.enum process and get process id DWORD GetProcessIdFromName(LPCTSTR name) { PROCESSENTRY32 pe; DWORD id = 0; HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); pe.dwSize = sizeof(PROCESSENTRY32); if( !Process32First(hSnapshot,&pe) ) return 0; while(1) { pe.dwSize = sizeof(PROCESSENTRY32); if( Process32Next(hSnapshot,&pe)==FALSE ) break; if(_strnicmp(pe.szExeFile,name,strlen(name)) == 0) { id = pe.th32ProcessID; break; } }; CloseHandle(hSnapshot); return id; } DWORD ProcessID=GetProcessIdFromName(SLCC_APPNAME); if(ProcessID) { HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,NULL,ProcessID); } 2.from process id can get file path char szPath[256]; GetModuleFileName(hProcess,szPath,256); vc中调用windows中拷贝文件的那个进度条Requirements Version 5.00 and later of Shell32.dll Windows NT/2000: Requires Windows 2000. Windows 95/98/Me: Requires Windows Me. IProgressDialog The IProgressDialog interface is exported by the progress dialog box object (CLSID_ProgressDialog). This object is a generic way to show a user how an operation is progressing. It is typically used when deleting, uploading, copying, moving, or downloading large numbers of files. The progress dialog box object creates a modeless dialog box and allows the client to set its title, animation, text lines, and progress bar. The object then handles updating on a background thread and allows the user to cancel the operation. Optionally, it estimates the time remaining until the operation is complete and displays the information as a line of text. BUG: PROGDLG_NOMINIMIZE Flag in IProgressDialog::StartProgressDialog() Has No Effect Q260222 -------------------------------------------------------------------------------- The information in this article applies to: Microsoft Win32 Software Development Kit (SDK), on platform(s): the operating system: Microsoft Windows 2000 用ShellAPI实现目录树以下代码是经过测试能够定位以d:\test目录为跟的树: LPITEMIDLIST pidl; LPITEMIDLIST pidlRoot; LPMALLOC lpMalloc; CHAR pszPath[MAX_PATH]; strcpy(pszPath, ""); BROWSEINFO bi = { m_hWnd, NULL, (char *)pszPath, "请选择存放的路径:", BIF_BROWSEFORCOMPUTER ¦ BIF_RETURNONLYFSDIRS, NULL, 0L, 0}; IShellFolder *psf; SHGetDesktopFolder( &psf ); DWORD dwAttribs = SFGAO_COMPRESSED; ULONG cbEaten; HRESULT hres = psf->ParseDisplayName(NULL, NULL, L"d;\\test", &cbEaten, &pidlRoot, &dwAttribs); bi.pidlRoot = pidlRoot; psf->Release(); pidl = SHBrowseForFolder(&bi); if (NULL != pidl) { SHGetPathFromIDList(pidl, pszPath); m_strFilePath = pszPath; } else { return; } // Get the shell's allocator to free PIDLs if (!SHGetMalloc(&lpMalloc) && (NULL != lpMalloc)) { if (NULL != pidlRoot) { lpMalloc->Free(pidlRoot); } if (NULL != pidl) { lpMalloc->Free(pidl); } lpMalloc->Release(); } --------------------------------------------------------------- 如何做到让一个程序同一时刻只能运行一个实例一个应用程序,并且让它同一时刻只能运行一个实例。当用户启动时,如果已经运行了,则激活已运行的那个实例。 --------------------------------------------------------------- 结合刚才的代码, 同时在XXView.cpp中的BOOL CAaView::PreCreateWindow(CREATESTRUCT& cs)里加上: BOOL CAaView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs CWnd *pwnd=CWnd::FindWindow(NULL,"无标题 - aa");//这里换成你的程序的标 //题 if(pwnd) { pwnd->ShowWindow(SW_SHOWNORMAL); } return CView::PreCreateWindow(cs); } 就可以实现程序只能运行一次,如果已经运行,则激活.(已经测试通过) 如何运行快捷方式我用ShellExecute运行时返回错误,返回值为SE_ERR_ACCESSDENIED(The operating system denied access to the specified file ) 我用CreateProcess是返回193,意思是 193 %1 is not a valid Win32 application. ERROR_BAD_EXE_FORMAT 有何方法? 调用COM把原执行文件找出来的方法是可以,我觉麻烦 有何良策或我的调用方法哪里有问题? --------------------------------------------------------------- MFC源代码的filecore.cpp里面 AfxResolveShortcut 可以解决 --------------------------------------------------------------- ShellExecute 可以的 lpOperation 设为NULL就行 ShellExecute(GetSafeHwnd(), NULL, "D:\\microsoft word", "", NULL, SW_SHOWNORMAL); 关于几个常见的SHELL问题怎样实现显示查找文件对话框,显示浏览文件夹对话框,显示关闭Windows对话框,一类的问题,这里整理了几个常用的SHELL实现的方法。如下: IShellDispatch* pShellDispatch = NULL; HRESULT hResult = CoInitialize(NULL); if(FAILED(hResult)) { return; } hResult = CoCreateInstance(CLSID_Shell,NULL,CLSCTX_INPROC_SERVER, IID_IDispatch,(LPVOID*)&pShellDispatch); if(FAILED(hResult)) { return; } // COleVariant OleVariant("桌面"); // COleVariant OleTitle("IShellDispatch test"); // Folder* pFolder = NULL; // hResult = pShellDispatch->BrowseForFolder((LONG)GetSafeHwnd(), // OleTitle.bstrVal,BIF_RETURNONLYFSDIRS,OleVariant,&pFolder); //显示浏览文件夹对话框 // hResult = pShellDispatch->CascadeWindows();//层叠窗口 // COleVariant OleVariant("access.cpl"); // hResult = pShellDispatch->ControlPanelItem(OleVariant.bstrVal);//打开控制面板的程序 // COleVariant OleVariant("我的电脑"); // hResult = pShellDispatch->Explore(OleTitle);//用资源管理器打开文件夹 // hResult = pShellDispatch->FileRun();//显示运行对话框 // hResult = pShellDispatch->FindComputer();//显示查找电脑对话框 // hResult = pShellDispatch->FindFiles();//显示查找文件对话框 // hResult = pShellDispatch->MinimizeAll();//显示桌面 // COleVariant OleVariant("我的电脑"); // hResult = pShellDispatch->Open(OleTitle);//打开文件夹 // hResult = pShellDispatch->ShutdownWindows();//显示关闭Windows对话框 // hResult = pShellDispatch->TileHorizontally();//横向平铺窗口 // hResult = pShellDispatch->TileVertically();//纵向平铺窗口 // hResult = pShellDispatch->TrayProperties();//显示任务栏属性对话框 // hResult = pShellDispatch->UndoMinimizeALL();//撤销最小化窗口 windows2000里怎样得到用户登陆信息及登陆期间的操作信息要求得到用户的登陆信息,比如说什么时候登陆,什么时候退出,在用户登陆期间进行了哪些操作,比如说访问哪些程序,删除哪些文件阿什么的。 是否有相关的函数可以调用,然后得到这些信息。 要么是否微软有相关的文件记录可以用来察看。 我的目的就是把这些相关的信息都提取出来,然后有选择的储存到我创建的一个文件当中。 --------------------------------------------------------------- http://www.vckbase.com/document/viewdoc/?id=798 --------------------------------------------------------------- 控制面板-》管理工具-》事件查看器-》操作-》属性 这里可以设置和查看Windows的系统日志等,找找相关的东东 --------------------------------------------------------------- IADsUser property lastlogin lastlogoff --------------------------------------------------------------- 访问哪些程序: IShellExecute 删除哪些文件: ICopyHook --------------------------------------------------------------- get user login time: #include "stdafx.h" #include <activeds.h> #pragma comment(lib,"activeds.lib") #pragma comment(lib,"adsiid.lib") #include <comutil.h> #pragma comment(lib,"comsupp.lib") #include <Adshlp.h> #include <comdef.h> #include <initguid.h> #include <Iads.h> void PrintUser(IADsUser* pUser) { if(!pUser) return; BSTR bstr; HRESULT hr = pUser->get_FullName(&bstr); printf("User: %S\n", bstr); SysFreeString(bstr); DATE lastlogin,lastlogoff; hr = pUser->get_LastLogin(&lastlogin); hr = pUser->get_LastLogoff(&lastlogoff); SYSTEMTIME stlogin,stlogoff; VariantTimeToSystemTime(lastlogin,&stlogin); VariantTimeToSystemTime(lastlogoff,&stlogoff); printf("last login time %d-%d-%d %d:%d:%d\n",stlogin.wYear,stlogin.wMonth,stlogin.wDay, stlogin.wHour,stlogin.wMinute,stlogin.wSecond); } int _tmain(int argc, _TCHAR* argv[]) { CoInitialize(NULL); IADsWinNTSystemInfo *pNTsys; HRESULT hr = CoCreateInstance(CLSID_WinNTSystemInfo, NULL,CLSCTX_INPROC_SERVER, IID_IADsWinNTSystemInfo, (void**)&pNTsys); pNTsys->AddRef(); BSTR bstrCompName; pNTsys->get_ComputerName(&bstrCompName); BSTR bstrDomainName; pNTsys->get_DomainName(&bstrDomainName); pNTsys->Release(); wchar_t buf[512]; wsprintfW(buf,L"WinNT://%s/%s",L"workgroup",bstrCompName); SysFreeString(bstrCompName); SysFreeString(bstrDomainName); IADsContainer* pUsers; hr=ADsGetObject(buf,IID_IADsContainer,(void **)&pUsers); IEnumVARIANTPtr pEnum; ADsBuildEnumerator (pUsers,&pEnum); int cnt=0; while(1) { _variant_t vChild; hr=ADsEnumerateNext (pEnum,1,&vChild,NULL); if(hr!=S_OK) break; IADsUser *pUser = NULL; hr=vChild.pdispVal->QueryInterface (IID_IADsUser,(void **)&pUser); if(hr!=S_OK) continue; else { PrintUser(pUser); pUser->Release(); } } pEnum.Release(); pUsers->Release(); CoUninitialize(); return 0; } 得到windows文件所关联的执行程序路径如: txt文件 得到 D:\winnt\notepad.exe dsw文件 得到 D:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin\MSDEV.EXE ShellExecute就做到了~~ 请问有什么简单方法可以实现吗? --------------------------------------------------------------- FindExecutable or AssocQueryString 怎么弹出U盘要求效果和在U盘上面点击右键,然后选择eject一样. 在WinXP,VC6.0下面实现.. --------------------------------------------------------------- DeviceIoControl -------------------------------------------------------------- 搞定了.下面一句就可以了. ::DeviceIoControl(usbhandle,IOCTL_STORAGE_EJECT_MEDIA,NULL,0,NULL,0,&dwOutBytes,(LPOVERLAPPED)NULL); 打印分页问题在OnDraw()里画出要打印的数据,不管又多少数据,一直画完为止,预览和打印时只能看到一页,怎么样才能预览和打印多页 --------------------------------------------------------------- 关于打印的可以覆盖的6个虚函数(以FrameWork调用次序列出): CMyView::OnPreparePrinting 设定Document长度,调用CView::DoPreparePrinting以显示打印对话框并产生打印机DC CMyView::OnBeginPrinting 设定以DC为准的Document长度(可以计算页数并设置),配置GDI资源 CMyView::OnPrepareDC 改变viewport原点、剪截区以及其他DC属性 CMyView::OnPrint CMyView::OnDraw 打印页眉、页脚等等 CMyView::OnEndPrinting 释放GDI资源 基于此,可以知道如:动态计算页码并决定是否继续打印应该在CMyView::OnPrepareDC中、设置页码数应该在CMyView::OnBeginPrinting中。 --------------------------------------------------------------- void CMyView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add extra initialization before printing } BOOL CMyView::OnPreparePrinting(CPrintInfo* pInfo) { pInfo->SetMaxPage(2); // the document is two pages long: // the first page is the title page // the second is the drawing BOOL bRet = DoPreparePrinting(pInfo); // default preparation pInfo->m_nNumPreviewPages = 2; // Preview 2 pages at a time // Set this value after calling DoPreparePrinting to override // value read from .INI file return bRet; } void CMyView::OnPrint(CDC* pDC, CPrintInfo* pInfo) { if (pInfo->m_nCurPage == 1) // page no. 1 is the title page { PrintTitlePage(pDC, pInfo); return; // nothing else to print on page 1 but the page title } CString strHeader = _T("My Print Header"); PrintPageHeader(pDC, pInfo, strHeader); // PrintPageHeader() subtracts out from the pInfo->m_rectDraw the // amount of the page used for the header. pDC->SetWindowOrg(pInfo->m_rectDraw.left,-pInfo->m_rectDraw.top); // Now print the rest of the page OnDraw(pDC); } void CMyView::PrintPageHeader(CDC* pDC, CPrintInfo* pInfo, CString& strHeader) { // Print a page header consisting of the name of // the document and a horizontal line pDC->SetTextAlign(TA_LEFT); pDC->TextOut(0,-25, strHeader); // 1/4 inch down // Draw a line across the page, below the header TEXTMETRIC textMetric; pDC->GetTextMetrics(&textMetric); int y = -35 - textMetric.tmHeight; // line 1/10th inch below text pDC->MoveTo(0, y); // from left margin pDC->LineTo(pInfo->m_rectDraw.right, y); // to right margin // Subtract out from the drawing rectange the space used by the header. y -= 25; // space 1/4 inch below (top of) line pInfo->m_rectDraw.top += y; } void CMyView::PrintTitlePage(CDC* pDC, CPrintInfo* pInfo) { // Prepare a font size for displaying the file name LOGFONT logFont; memset(&logFont, 0, sizeof(LOGFONT)); logFont.lfHeight = 75; // 3/4th inch high in MM_LOENGLISH // (1/100th inch) CFont font; CFont* pOldFont = NULL; if (font.CreateFontIndirect(&logFont)) pOldFont = pDC->SelectObject(&font); // Get the file name, to be displayed on title page CString strPageTitle = _T("My Print Header"); // Display the file name 1 inch below top of the page, // centered horizontally pDC->SetTextAlign(TA_CENTER); pDC->TextOut(pInfo->m_rectDraw.right/2, -100, strPageTitle); if (pOldFont != NULL) pDC->SelectObject(pOldFont); } void CMyView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add cleanup after printing } 如何得知打印机中的一个作业已经完成(打印机监控)如果把打印机设置为保存已打印完作业,比较简单,使用enumjobs即可,但是不能设置为保存模式,因此打印完的作业就从打印队列中清空,无法得到它的信息,如果可以在程序开始把打印机设置为保存打印完作业,程序结束再改回不保存状态也可以 ,但是我不知道怎么编程实现,请高人赐教!!!! 我有一种方法,是设置一个timer,隔断时间取一次打印队列的信息,然后比较两次采样的第一个作业,如果两个作业不同,表明之前采样时的作业已经完成,但是这种方法有缺陷,如果用户可以把打印机状态设置为暂停,再把第一个作业取消,我就无法判断它究竟是打印完了,还是被用户取消了. --------------------------------------------------------------- 你可以捕获打印机的状态改变做一些处理。使用API函数: HANDLE FindFirstPrinterChangeNotification( HANDLE hPrinter, // handle to printer or print server to monitor // for changes DWORD fdwFlags, // flags that specify the conditions to monitor DWORD fdwOptions, // reserved, must be zero LPVOID pPrinterNotifyOptions // pointer to structure specifying printer // information to monitor ); --创建一个打印机状态改变对象,并获得其句柄。 使用PRINTER_CHANGE_JOB作为fdwFlags。 然后使用API函数: BOOL FindNextPrinterChangeNotification( HANDLE hChange, // handle to change notification // object of interest PDWORD pdwChange, // pointer to a value that indicates // the condition that changed LPVOID pPrinterNotifyOptions, // pointer to a structure that // specifies a refresh flag LPVOID *ppPrinterNotifyInfo // pointer to a pointer that receives // printer information buffer ); 使用PRINTER_CHANGE_WRITE_JOB --Job data was written作为pdwChange。用于捕获Job被执行完毕。在这个过程中你可以使用WaitSingleObject捕获这些改变,做处理。具体的参考MSDN。记得在不需要这个打印机状态改变对象的时候使用API函数: BOOL FindClosePrinterChangeNotification( HANDLE hChange // handle to change notification object to close ); 释放这个对象。 这几个API函数的作用就是:创建一个打印机状态改变通知对象,然后使用Wait系列函数在打印机状态发生改变的时候得到通知,就和线程等内核对象的同步操作是一样的,当得到这个通知以后使用第二个API获得具体的信息。 ==================================== 你可以在微软的网站上下载到例子: http://support.microsoft.com/kb/q196805/ PrintMon.exe中示范了怎么使用那几个API。 如何取消打印机的所有正在打印的文档使用 BOOL SetPrinter( HANDLE hPrinter, // handle to printer object DWORD Level, // structure level LPBYTE pPrinter, // pointer to array containing printer data DWORD Command // printer-state command ); 最后的Command参数使用: PRINTER_CONTROL_PURGE Deletes all print jobs in the printer. 具体的参考MSDN! 如何枚举打印机,以及取到打印机代码如下: CDC dc; CPringtDialog printDlg; HANDLE m_hDevName,m_hDevMode; m_hDevName = printDlg.m_pd.hDevName; m_hDevMode = printDlg.m_pd.hDevName; 但是没有取得任何值,大家帮忙看看,在线等 --------------------------------------------------------------- --------------------------------------------------------------- 下面的例子,用来枚举当前机器上所有的打印机,并检查是否安装有PDF的打印机: bool GetPdfWriter(char *driver,char *device,char *port) { DWORD dwFlags = PRINTER_ENUM_FAVORITE ¦ PRINTER_ENUM_LOCAL; LPPRINTER_INFO_2 pPrinters; DWORD cbPrinters; DWORD cReturned, i; EnumPrinters (dwFlags, NULL, 2, NULL, 0, &cbPrinters, &cReturned); if (!(pPrinters = (LPPRINTER_INFO_2) LocalAlloc (LPTR, cbPrinters + 4)))return 0; if (!EnumPrinters (dwFlags, NULL, 2, (LPBYTE) pPrinters, cbPrinters, &cbPrinters, &cReturned)) { LocalFree (LocalHandle (pPrinters)); return 0; } if (cReturned > 0){ for (i = 0; i < cReturned; i++) { //AfxMessageBox((pPrinters + i)->pPrinterName); //if(strstr((pPrinters + i)->pPrinterName,"PDFWriter")!=0){ if(strstr((pPrinters + i)->pPrinterName,"PDF")!=0){ //CString sMsg; //sMsg.Format("当前选择了这个打印机:%s", (pPrinters + i)->pPrinterName); //AfxMessageBox(sMsg); strcpy (device, (pPrinters + i)->pPrinterName); strcpy (port, (pPrinters + i)->pPortName); strcpy (driver, (pPrinters + i)->pDriverName); LocalFree (LocalHandle (pPrinters)); return 1; } } } LocalFree (LocalHandle (pPrinters)); ::MessageBox(0,"为了得到PDF,请首先安装Acrobat(包括Pdf Writer)","提示",MB_OK); return 0; } 有关打印设置的问题怎么样才能在程序中直接设置打印的方向是纵向还是横向,而不用调出打印对话框进行设置--------------------------------------------------------------- /* 设置系统打印模式 #define DMORIENT_PORTRAIT 1 //纵向 #define DMORIENT_LANDSCAPE 2 //横向 */ /************************************************************************/ void CXTReportApp::SetLandscapeMode(int PrintMode) { PRINTDLG pd; pd.lStructSize=(DWORD)sizeof(PRINTDLG); BOOL bRet=GetPrinterDeviceDefaults(&pd); if(bRet) { // protect memory handle with ::GlobalLock and ::GlobalUnlock DEVMODE FAR *pDevMode=(DEVMODE FAR *)::GlobalLock(m_hDevMode); // set orientation to landscape if(PrintMode==1)//纵向打印 pDevMode->dmOrientation=DMORIENT_PORTRAIT; else if(PrintMode==2)//横向打印 pDevMode->dmOrientation=DMORIENT_LANDSCAPE; ::GlobalUnlock(m_hDevMode); } --------------------------------------------------------------- 打印的方向是通过调用 Windows API 函数 Escape 和设定参数 GETSETPRINTORIENT 来获得的。返回值通常为 1 或 2,1 代表纵向模式(正规的打印布局),2 代表横向模式(侧转打印)。 --------------------------------------------------------------- 我是从精华中摘下来的,没看,现在改了一下 /* 设置系统打印模式 #define DMORIENT_PORTRAIT 1 //纵向 #define DMORIENT_LANDSCAPE 2 //横向 */ /************************************************************************/ void SetLandscapeMode(int PrintMode) { PRINTDLG pd; pd.lStructSize=(DWORD)sizeof(PRINTDLG); BOOL bRet=AfxGetApp()->GetPrinterDeviceDefaults(&pd); if(bRet) { // protect memory handle with ::GlobalLock and ::GlobalUnlock DEVMODE FAR *pDevMode=(DEVMODE FAR *)::GlobalLock(pd.hDevMode); // set orientation to landscape if(PrintMode==1)//纵向打印 pDevMode->dmOrientation=DMORIENT_PORTRAIT; else if(PrintMode==2)//横向打印 pDevMode->dmOrientation=DMORIENT_LANDSCAPE; ::GlobalUnlock(pd.hDevMode); } } 如何得到系统中安装的打印机名比如安装了3个打印,有本地,网络的,还有虚拟的. 什么函数可以枚举这些信息,特别的要得到打印机名称. 谢谢 --------------------------------------------------------------- BOOL DisplayEnumPrintersInfo (HWND hwnd) { DWORD dwBytesNeeded; DWORD dwPrtRet1, dwPrtRet2; DWORD dwMaxPrt; LPTSTR lpName = gdwEnumFlags & PRINTER_ENUM_NAME ? gszEnumName : NULL; LPPRINTER_INFO_1 pPrtInfo1; LPPRINTER_INFO_2 pPrtInfo2; BOOL bReturn = TRUE; // // get byte count needed for buffer, alloc buffer, the enum the printers // EnumPrinters (gdwEnumFlags, lpName, 1, NULL, 0, &dwBytesNeeded, &dwPrtRet1); // // (simple error checking, if these work assume rest will too) // if (!(pPrtInfo1 = (LPPRINTER_INFO_1) LocalAlloc (LPTR, dwBytesNeeded))) { ErrMsgBox (GetStringRes(IDS_ENUMPRTLALLOCFAIL), GetStringRes2(ERR_MOD_NAME)); bReturn = FALSE; goto display_prts_info_done1; } if (!EnumPrinters (gdwEnumFlags, lpName, 1, (LPBYTE) pPrtInfo1, dwBytesNeeded, &dwBytesNeeded, &dwPrtRet1)) { TCHAR tcBuffer[256]; wsprintf (tcBuffer, "%s, 1, GetLastError: %d", GetStringRes2(ERR_MOD_NAME), GetLastError()); ErrMsgBox (GetStringRes(IDS_ENUMPRT1FAIL), tcBuffer); bReturn = FALSE; goto display_prts_info_done2; } // // If we don't get any printers from the Level == 1 call, there is // no point in continuing... report it, free memory, and return. // if (dwPrtRet1 == 0) { MessageBox (ghwndMain, (LPCTSTR) "EnumPrinters (Level == 1) returned 0 printers", GetStringRes2(ERR_MOD_NAME), MB_OK); bReturn = FALSE; goto display_prts_info_done2; } // // Call EnumPrinters again with Level == 2. // // get byte count needed for buffer, alloc buffer, the enum the printers // EnumPrinters (gdwEnumFlags, lpName, 2, NULL, 0, &dwBytesNeeded, &dwPrtRet2); pPrtInfo2 = (LPPRINTER_INFO_2) LocalAlloc (LPTR, dwBytesNeeded); EnumPrinters (gdwEnumFlags, lpName, 2, (LPBYTE) pPrtInfo2, dwBytesNeeded, &dwBytesNeeded, &dwPrtRet2); // // Calling EnumPrinters with Level == 2 frequently returns 0 printers. // If so display only the PRINTER_INFO_1 structures we got before. // if (dwPrtRet2 == 0) { dwMaxPrt = dwPrtRet1; pPrtInfo2 = NULL; } else { dwMaxPrt = dwPrtRet1 > dwPrtRet2 ? dwPrtRet2 : dwPrtRet1; } SetEnumPrintersDlgFields (hwnd, dwMaxPrt, pPrtInfo1, pPrtInfo2); LocalFree (LocalHandle (pPrtInfo2)); display_prts_info_done2: LocalFree (LocalHandle (pPrtInfo1)); display_prts_info_done1: return bReturn; } |
|
|