梦想空间's profile梦想空间PhotosBlogListsMore Tools Help

Blog


    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创建数据库应用程序遵循一定的基本步骤:

    第一步是分配ODBC环境,使一些内部结构初始化。完成这一步,须分配一个SQLHENV类型的变量在ODBC环境中做句柄使用。

    第二步是为将要使用的每一个数据源分配一个连接句柄,由函数SQLALLocHandle()完成。

    第三步是使用SQLConnect()把连接句柄与数据库连接,可以先通过SQLSetConnectAttr()设置连接属性。

    然后就可以进行SQL语句的操作,限于篇幅,相关的函数就不具体介绍了,读者可以参考相关书籍。

    操作完成后,用户取回相应的结果,就可以取消与数据库的连接。

    最后需要释放ODBC环境。

    ODBC API的特点是功能强大丰富,提供了异步操作,事务处理等高级功能,但相应的编程复杂,工作量大。

    2.MFC ODBC类

    MFC1.5后的版本里引入封装了ODBC功能的类。通过这些类提供与ODBC的接口,使得用户可以不须处理ODBC API中的繁杂处理就可以进行数据库操作。主要的MFC ODBC类如下。

    CDatabase类:一个CDatabase对象表示一个到数据源的连接,通过它可以操作数据源。应用程序可使用多个CDatabase对象:构造一个对象并调用OpenEx()成员函数打开一个连接。接着构造CRecordSet对象以操作连接的数据源,并向CDatabase对象传递记录集构造程序指针。完成使用后用Close()成员函数销毁CDatabase对象。一般情况下并不需要直接使用CDatabase对象,因为CRecordSet对象可以实现大多数的功能。但是在进行事务处理时,CDatabase就起到关键作用。事务(Transaction)指的是将一系列对数据源的更新放在一起,同时提交或一个也不提交,为的是确保多用户对数据源同时操作时的数据正确性。

    CRecordSet类:一个CRecordSet对象代表一个从数据源选择的一组记录的集合-记录集。记录集有两种形式:snapshot和dynaset。前者表示数据的静态视图,后者表示记录集与其他用户对数据库的更新保持同步。通过CRecordSet对象,用户可以对数据库中的记录进行各种操作。

    CRecordView类:CRecordView对象是在空间中显示数据库记录的视图。这种视图是一种直接连到一个CRecordSet对象的格式视图,它从一个对话框模板资源创建,并将CRecordSet对象的字段显示在对话框模板的控件里。对象利用DDX和RFX机制,使格式上的控件和记录集的字段之间数据移动自动化,也就是说,用户甚至不要编写一行代码就可以实现简单的数据库记录查看程序。

    CDBException类:由Cexception类派生,以三个继承的成员变量反映对数据库操作时的异常:

     m_nRetCode:以ODBC返回代码(SQL_RETURN)的形式表明造成异常的原因。

     m_strError:字符串,描述造成抛出异常的错误原因。

     m_strStateNativeOrigin:字符串,用以描述以ODBC错误代码表示的异常错误。

    MFC数据库类成员函数都能抛出CDBException类型的异常,所以在代码对数据库进行操作后监测异常是正确做法。

    MFC ODBC类在实际开发中应用最广,因为它功能丰富,操作相对简便。

    3.MFC DAO(数据访问对象)编程

    DAO用于和微软的Access数据库接口。在数据库应用程序如果只需与Access数据库接口时,使用DAO编程较方便。其主要类如下。

    CDaoWorkspace:CDaoWorkspace对象可以让一个用户管理从登陆到离开期间,指定的密码保护的数据库会话全过程。大多数情况下不要多个工作区也不要创建明确的工作区对象。因为在打开数据库和记录集对象时,它们可以使用DAO缺省工作区。

    CDaoDatabase:代表一个连接,类似上述CDatabase类。

     CDaoRecordSet:用来选择记录集并操作,类似上述CRecordSet类。

     CDaoRecordView:类似上述CRecordView类。

     CDaoException:类似上述CDBException类。

     CDaoTableDef:表示基本表或附加表的定义。每个DAO数据库对象包括一个称为TableDef的收集,包含所有存储的DAO表定义对象。CDaoTableDef对象可以用来控制表定义。

     CDaoQueryDef:CDaoQueryDef对象表示了一个查询定义(querydef)。

     CDaoFieldExchange:支持数据库类使用的DAO字段交换(DFX)例程。也可处理事务,类似MFC ODBC类。

    MFC DAO仅用来支持Access数据库,应用范围相对固定。

    4.OLE DB

    OLE DB在数据提供程序和用户之间提供了灵活的组件对象模型(COM)接口,这种灵活性有时会使得操作复杂化。OLE DB框架定义了应用的三个基本类。

    数据提供程序Data Provider:拥有自己的数据并以表格形式显示数据的应用程序。提供OLE DB的行集COM接口,期显示范围可以从单一数据表格的简单提供者知道更复杂的分布式数据库系统。

    使用者Consumers:使用OLE DB接口对存储在数据提供程序中的数据进行控制的应用程序。用户应用程序归为使用类。

    服务提供程序Service Provider:是数据提供程序和使用者的组合。服务提供程序没有自己的数据,但使用

    OLE DB使用者接口来访问存储在数据提供程序中的数据。然后,服务提供程序通过打开数据提供程序接口使得数据对使用者有效。服务提供程序常用于向应用程序提供高层次服务,比如高级分布式查询。

    OLE DB编程时,用户使用组件对象开发应用程序。这些组件有:

     枚举器:用于列出可用的数据源;

     数据源:代表单独的数据和服务提供程序,用于创建对话;

     对话:用于创建事务和命令;

     事务:用于将多个操作归并为单一事务处理;

     命令:用于向数据源发送文本命令(SQL),返回行集;

     错误:用于获得错误信息。

    5.ActiveX数据对象(ADO)

    是微软提供的面向对象的接口,与OLE DB类似,但接口更简单,具有更广泛的特征数组和更高程度的灵活性。ADO基于COM,提供编程语言可利用的对象,除了面向VC++,还提供面向其他各种开发工具的应用,如VB,VJ等。ADO在服务器应用方面非常有用,特别是对于动态服务器页面ASP(Active Server Page)。

    ADO对象结构类似于OLE DB,但并不依靠对象层次。大多数情况下,用户只需要创建并只使用需要处理的对象。下面的对象类组成了ADO接口。

     Connection:用于表示与数据库的连接,以及处理一些命令和事务。

     Command:用于处理传送给数据源的命令。

     Recordset:用于处理数据的表格集,包括获取和修改数据。

     Field:用于表示记录集中的列信息,包括列值和其他信息。

     Parameter:用于对传送给数据源的命令之间来回传送数据。

     Property:用与操作在ADO中使用的其他对象的详细属性。

     Error:用于获得可能发生的错误的详细信息。

    在VC++使用ADO需要进行COM操作,详细方法在此就不赘述了。

    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
    #include
    #include
    #include
    #include
    #define BUFSIZE 512
    BOOL GetFileNameFromHandle(HANDLE hFile)
    {
        BOOL bSuccess=FALSE ;
        TCHAR pszFilename[MAX_PATH+1];
        HANDLE hFileMap ;
        // Get the file size.
        DWORD dwFileSizeHi=0 ;
        DWORD dwFileSizeLo=GetFileSize(hFile,&dwFileSizeHi);
        if(dwFileSizeLo==0&&dwFileSizeHi==0)
        {
            printf("Cannot map a file with a length of zero.\n");
            return FALSE ;
        }
        // Create a file mapping object.
        hFileMap=CreateFileMapping(hFile,NULL,PAGE_READONLY,0,1,NULL);
        if(hFileMap)
        {
            // Create a file mapping to get the file name.
            void*pMem=MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,1);
            if(pMem)
            {
                if(GetMappedFileName(GetCurrentProcess(),pMem,pszFilename,MAX_PATH))
                {
                    // Translate path with device name to drive letters.
                    TCHAR szTemp[BUFSIZE];
                    szTemp[0]='\0' ;
                    if(GetLogicalDriveStrings(BUFSIZE-1,szTemp))
                    {
                        TCHAR szName[MAX_PATH];
                        TCHAR szDrive[3]=TEXT(" :");
                        BOOL bFound=FALSE ;
                        TCHAR*p=szTemp ;
                        do
                        {
                            // Copy the drive letter to the template
                            string*szDrive=*p ;
                            // Look up each device name
                            if(QueryDosDevice(szDrive,szName,BUFSIZE))
                            {
                                UINT uNameLen=_tcslen(szName);
                                if(uNameLen<MAX_PATH)
                                {
                                    bFound=_tcsnicmp(pszFilename,szName,uNameLen)==0 ;
                                    if(bFound)
                                    {
                                        // Reconstruct pszFilename using szTemp
                                        // Replace device path with DOS path
                                        TCHAR szTempFile[MAX_PATH];
                                        _stprintf(szTempFile,TEXT("%s%s"),szDrive,pszFilename+uNameLen);
                                        _tcsncpy(pszFilename,szTempFile,MAX_PATH);
                                    }
                                }
                            }
                            // Go to the next NULL character.
                            while(*p++);
                        }
                        while(!bFound&&*p);
                        // end of string
                    }
                }
                bSuccess=TRUE ;
                UnmapViewOfFile(pMem);
            }
            CloseHandle(hFileMap);
        }
        printf("File name is %s\n",pszFilename);
        return(bSuccess);
    }

    怎么扫描出一个特定程序的具体位置


    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;  
    }