VC编程常见问题解答收集贴

1.使用ModifyStyleEx改变了控件风格无效 
答:修改之后,重绘一次,如果还不行的话,再试试看调用SetWindowPos(0,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE | SWP_DRAWFRAME); 

2.动态设置编辑框的ES_PASSWORD无效 
答:修改之后,需要调用一次SetPasswordChar('*'); 

3.如何获取任务栏小图标? 
答:有网友提出,能不能在程序界面上显示当前的托盘图标,这样更直观一些。这一点我也曾想到过,也知道奥秘就在TBBUTTON这个结构体的dwData域里面,可惜这个域的结构在MSDN中没有描述。我也曾试着发送TB_GETIMAGELIST消息获取image list的句柄,然后用CImageList::FromHandle加载到CImageList中,但却都失败了。 
在csdn网友的帮助下,我弄清了dwData的结构,其实dwData有一个这样的机构,我们命名为TRAYDATA: 
struct TRAYDATA 
{ 
    HWND hwnd;                  
    UINT uID;                
    UINT uCallbackMessage;      
    DWORD Reserved[2];          
    HICON hIcon;                //托盘图标的句柄 
};  
要获取到这个hIcon,其实很简单: 
//分配虚拟内存 
lngAddress = VirtualAllocEx(hProcess,  NULL,  sizeof(TBBUTTON), MEM_COMMIT, PAGE_READWRITE);    
//将hProcess进程内,地址为lngAddress中的内容(大小为sizeof(TBBUTTON))获取到tb中 
ret = ::ReadProcessMemory(hProcess, LPVOID(long(lngAddress)), &tb, sizeof(TBBUTTON), 0); 
//将hProcess进程内,地址为tb.dwData中的内容(大小为sizeof(TRAYDATA))获取到tray中 
ret = ::ReadProcessMemory(hProcess, LPVOID(tb.dwData), &tray, sizeof(TRAYDATA), 0); 
然后就可以用tray.hIcon索引到这个图标句柄了 
//释放内存代码略 

4.BeginWaitCursor和EndWaitCursor无效 
答:SetCapture();BeginWaitCursor();....EndWaitCursor();ReleaseCapture(); 

5.打印源码中文件名和行号常用的宏名是什么? 
答:文件名:__FILE__  行号:__LINE__ 

6.如何具体判断一个字符串中哪个是英文字母 
答:函数isalpha 

7.在注册表中如何得到所有安装了的应用程序程序的信息 
答:HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall下面的子键 

8.64位系统下运行32的程序,操作注册表遭遇重定向问题 
答:PVOID  OldValue; 
HINSTANCE  hlibrary; 
typedef    int        (__stdcall  *  Wow64DisableWow64FsRedirection)(LPVOID); 
YWow64DisableWow64FsRedirection  f_Wow64DisableWow64FsRedirection  =  NULL; 
typedef    int        (__stdcall  *  Wow64RevertWow64FsRedirection)(LPVOID); 
Wow64RevertWow64FsRedirection  f_Wow64RevertWow64FsRedirection  =  NULL; 
hlibrary  =  LoadLibrary("Kernel32.dll"); 
f_Wow64DisableWow64FsRedirection  =  (Wow64DisableWow64FsRedirection)  GetProcAddress(hlibrary,"Wow64DisableWow64FsRedirection"); 
if(!f_Wow64DisableWow64FsRedirection) { } 
f_Wow64DisableWow64FsRedirection  (&OldValue); 
//这里写注册表操作函数,Open的时候要指定  KEY_WOW64_64KEY标志 
f_Wow64RevertWow64FsRedirection  =  (Wow64RevertWow64FsRedirection)  GetProcAddress(hlibrary,"Wow64RevertWow64FsRedirection"); 
if(!f_Wow64RevertWow64FsRedirection) { } 
f_Wow64RevertWow64FsRedirection  (OldValue); 
FreeLibrary(hlibrary); 

9.怎么使用系统默认浏览器在新窗口打开网页 
答:ShellExecute是我们常用的一个API,可以运行程序,打开网页。 
ShellExecute(NULL,  "open",  "http://www.csdn.net",  NULL,NULL,SW_SHOWMAXIMIZED); 
这样可以打开一个网页,但不是在新IE中打开,改成下面方式时就可以在一个新的IE中打开网页了 
ShellExecute(NULL,  "open",  "IEXPLORE",  "http://www.csdn.net",NULL,SW_SHOWMAXIMIZED);  

10.怎么清除串口的输入缓冲 
答:PurgeComm(hCom,PURGE_TXABORT ¦ PURGE_RXABORT ¦ PURGE_TXCLEAR ¦ PURGE_RXCLEAR); 

11.显示桌面属性对话框 
答:ShellExecute(GetDesktopWindow()->m_hWnd,"open","control.exe","desk.cpl Display,@Theme","",SW_SHOW ); 

12.限制Edit只能输入0-F 
答:WNDPROC wpOrigEditProc; 
LRESULT CALLBACK wpSubclassEditProc(HWND hDlg,UINT uiMsg,WPARAM wParam,LPARAM lParam); 
wpOrigEditProc = (WNDPROC) SetWindowLong(GetDlgItem(IDC_EDIT_DATA)->m_hWnd, 
                GWL_WNDPROC, (LONG) wpSubclassEditProc); 
LRESULT CALLBACK wpSubclassEditProc(HWND hDlg,UINT uiMsg,WPARAM wParam,LPARAM lParam) 
{ 
switch(uiMsg) 
{ 
case WM_CHAR: 
  if((wParam >= 0x30 && wParam <= 0x39) || 
    (wParam >= 0x41 && wParam <= 0x46) || 
    (wParam >= 0x61 && wParam <= 0x66) || 
    (wParam == 0x08) || wParam == 0x20 || wParam == 0x0D) 
  { 
  return CallWindowProc(wpOrigEditProc,hDlg,uiMsg,wParam,lParam); 
  } 
  else 
  { 
  if(GetKeyState(VK_CONTROL) & 0x8000) 
  { 
    return CallWindowProc(wpOrigEditProc,hDlg,uiMsg,wParam,lParam); 
  } 
  return true; 
  } 
  break; 
} 
return CallWindowProc(wpOrigEditProc,hDlg,uiMsg,wParam,lParam); 
}

13.

//一些帮助函数

//返回当前程序的路径
//例如c:/abc/abc.exe则返回c:/abc
BOOL    GetPath(TCHAR * strPath)
{
    TCHAR sDrive[_MAX_DRIVE];
    TCHAR sDir[_MAX_DIR];
    TCHAR sFilename[_MAX_FNAME],Filename[_MAX_FNAME];
    TCHAR sExt[_MAX_EXT];
    
    GetModuleFileName(NULL, Filename, _MAX_PATH);
    _tsplitpath(Filename, sDrive, sDir, sFilename, sExt);
    
    _tcscpy(strPath,sDrive);
    _tcscat(strPath,sDir);

    strPath[_tcslen(strPath)
-1] = _T('/0');
    
    
return TRUE;
}

//获得父进程ID,失败则返回0
DWORD   GetPPid()   
{           
    HANDLE            hProcessSnap   
=   NULL;     
    PROCESSENTRY32    pe32    
=    {0};
    DWORD dwPID 
= GetCurrentProcessId();
    
    hProcessSnap   
=   CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,   0);     
    
    
if(hProcessSnap==(HANDLE)-1)     
        
return   (FALSE);     

    pe32.dwSize   
=   sizeof(PROCESSENTRY32);     
    
    
if   (Process32First(hProcessSnap,   &pe32))     
    {   
        
while(pe32.th32ProcessID!=dwPID)   
            Process32Next(hProcessSnap,   
&pe32);   
    } 
    
    CloseHandle(hProcessSnap);
    
    
return(pe32.th32ParentProcessID);   
}

//判断程序是否以服务运行
BOOL isRuninServices()
{
    DWORD dwPPID 
= GetPPid();

    HANDLE hProcessSnap   
=   NULL;     
    PROCESSENTRY32   pe32  
=   {0};     
  
    hProcessSnap   
=   CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,   0);     
    
    
if   (hProcessSnap   ==   (HANDLE)-1)     
        
return   (FALSE);     
   
    pe32.dwSize   
=   sizeof(PROCESSENTRY32);     
    
    
if   (Process32First(hProcessSnap,   &pe32))     
    {   
        
while(pe32.th32ProcessID!=dwPPID)   
            Process32Next(hProcessSnap,   
&pe32);   
    } 
    
    CloseHandle(hProcessSnap);

    
if(_tcsncicmp(pe32.szExeFile,_T("services.exe"),20)==0)
        
return TRUE;
    
else return FALSE;

}

//提升为调试权限
BOOL EnableDebugPrivilege(BOOL bEnable) 
{
    BOOL bOk 
= FALSE; 
    HANDLE hToken;
    
    
if(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) 
    {
        LUID uID;
        ::LookupPrivilegeValue(NULL, SE_DEBUG_NAME, 
&uID);

        TOKEN_PRIVILEGES tp;
        tp.PrivilegeCount 
= 1;
        tp.Privileges[
0].Luid = uID;
        tp.Privileges[
0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
        ::AdjustTokenPrivileges(hToken, FALSE, 
&tp, sizeof(tp), NULL, NULL);
        bOk 
= (::GetLastError() == ERROR_SUCCESS);

        ::CloseHandle(hToken);
    }
    
return bOk;
}

//用于在release下输出调试信息
void KDbgPrint(LPCTSTR lpszFormat, ...)
{
#define _countof(array) (sizeof(array)/sizeof(array[0]))
#ifdef KOUT_DEBUG_STRING 
    va_list args;
    va_start(args, lpszFormat);

    
int nBuf;
    TCHAR szBuffer[
512];

    nBuf 
= _vsntprintf(szBuffer, _countof(szBuffer), lpszFormat, args);

    OutputDebugString(szBuffer);

    va_end(args);
#endif
}

//从地址去获得模块基址
HMODULE WINAPI ModuleFromAddress(PVOID pv)
{
    MEMORY_BASIC_INFORMATION mbi;
    
if(::VirtualQuery(pv, &mbi, sizeof(mbi)) != 0)
    {
        
return (HMODULE)mbi.AllocationBase;
    }
    
else
    {
        
return NULL;
    }
}

//获得DLL自身
BOOL GetDllPath(TCHAR * path)
{
    HMODULE hDll 
= ModuleFromAddress(GetDllPath);

    
if(hDll==NULL)
        
return FALSE;
    
else
    {
        GetModuleFileName(hDll, path, _MAX_PATH);
        
return TRUE;
    }
}


//格式化string
void format_string(string & str,LPCTSTR lpszFormat, ...)
{
#define _countof(array) (sizeof(array)/sizeof(array[0]))
    va_list args;
    va_start(args, lpszFormat);
    
    
int nBuf;
    TCHAR szBuffer[
1024];
    
    nBuf 
= _vsntprintf(szBuffer, _countof(szBuffer), lpszFormat, args);
    
    str 
= szBuffer;
    
    va_end(args);
}

//提升所需的权限
BOOL EnablePrivilege(LPCTSTR lpName,BOOL bEnable) 
{
    BOOL bOk 
= FALSE; 
    HANDLE hToken;
    
    
if(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) 
    {
        LUID uID;
        ::LookupPrivilegeValue(NULL, lpName, 
&uID);
        
        TOKEN_PRIVILEGES tp;
        tp.PrivilegeCount 
= 1;
        tp.Privileges[
0].Luid = uID;
        tp.Privileges[
0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
        ::AdjustTokenPrivileges(hToken, FALSE, 
&tp, sizeof(tp), NULL, NULL);
        bOk 
= (::GetLastError() == ERROR_SUCCESS);
        
        ::CloseHandle(hToken);
    }
    
return bOk;
}

//跳转到注册表
void Jump2Reg(string strRegPath,string strKey)
{
    
//ShellExecute(NULL,NULL,"regjump.exe",strRegPath.c_str(),NULL,SW_SHOW);
    ShellExecute(NULL,NULL,"regedit.exe",NULL,NULL,SW_SHOW);
    
    
//然后查找注册表窗口
    HWND hMain = NULL;
    HWND hTree 
= NULL;
    HWND hList 
= NULL;
    BOOL bFind 
= FALSE;
    
    
for(int i=0;i<10;i++)
    {
        hMain 
= FindWindow("RegEdit_RegEdit","注册表编辑器");
        
        
if(hMain!=NULL)
        {
//查找成功
            bFind = TRUE;
            
break;
        }
        
        Sleep(
200);
    }
    
    
if(bFind)
    {
        hTree 
= FindWindowEx(hMain,NULL,"SysTreeView32",NULL);
        hList 
= FindWindowEx(hMain,NULL,"SysListView32",NULL);
        
        
//选择树
        SetForegroundWindow(hTree);
        SetFocus(hTree);
        
        DWORD dwPID;
        GetWindowThreadProcessId(hMain,
&dwPID);
        HANDLE hProc 
= OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
        
        
//先把树给折叠起,最多30层
        for(int i=0;i<30;i++)
        {
            SendMessage(hTree, WM_KEYDOWN, VK_LEFT, 
0);
        }
        
        SendMessage(hTree, WM_KEYDOWN, VK_RIGHT, 
0);
        WaitForInputIdle(hProc, INFINITE);
        
        
        
for(i=0;i<strRegPath.length();i++)
        {
            
if(strRegPath.at(i)=='//')
                SendMessage(hTree, WM_KEYDOWN, VK_RIGHT, 
0);
            
else
                SendMessage(hTree,WM_CHAR,WPARAM(strRegPath.at(i)),
0);
            
        }
        
        WaitForInputIdle(hProc, INFINITE);
        
        
//然后到列表了..
        SetForegroundWindow(hList);
        SetFocus(hList);
        
        Sleep(
1000);
        
        SendMessage(hList, WM_KEYDOWN, VK_HOME, 
0);
        
        
for(i=0;i<strKey.length();i++)
        {
            SendMessage(hList,WM_CHAR,WPARAM(strKey.at(i)),
0);
        }
        
        CloseHandle(hProc);
    }
    
    
return;
}

//////////////////////////////////////////////////////////////////////////
//显示文件属性
void ShowProperties(string strPath)
{
    SHELLEXECUTEINFO si;
    
    ZeroMemory(
&si,sizeof(SHELLEXECUTEINFO));
    
    si.cbSize 
= sizeof(SHELLEXECUTEINFO);
    si.fMask 
= SEE_MASK_NOCLOSEPROCESS | SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI ;
    si.lpVerb 
= "properties";
    si.lpFile 
= strPath.c_str();
    si.nShow 
= SW_SHOW;
    
    ShellExecuteEx(
&si);
}

//定位文件
void Jump2File(string strPath)
{
    
string cmd = "/e,/select,"+strPath;
    ShellExecute(NULL,NULL,
"explorer",cmd.c_str(),NULL,SW_SHOW);
}

14. 动态修改ComboBox的DROPDOWN,DROPDOWNLIST属性 

DWORD  theStyle; 
HWND  theChild; 

theChild  =  ::GetWindow( GetDlgItem(IDC_COMBO1)->m_hWnd  ,  GW_CHILD  );  
theStyle = GetWindowLong(GetDlgItem(IDC_COMBO1)->m_hWnd, GWL_STYLE  );  
theStyle  &=  ~CBS_DROPDOWN;//去掉DROPDOWN  
theStyle  |=  CBS_DROPDOWNLIST; //添加DROPDOWNLIST 

::DestroyWindow(  theChild  );  
SetWindowLong(GetDlgItem(IDC_COMBO1)->m_hWnd, GWL_STYLE  ,  theStyle  );

15. 如何制作透明窗体 
  使用SetLayeredWindowAttributes可以方便的制作透明窗体,此函数在w2k以上才支持,而且如果希望直接使用的话,可能需要下载最新的SDK。不过此函数在w2k的user32.dll里有实现,所以如果你不希望下载巨大的sdk的话,可以直接使用GetProcAddress获取该函数的指针。 


SetLayeredWindowAttributes的函数原型如下: 

BOOL SetLayeredWindowAttributes( 
HWND hwnd, // handle to the layered window 
COLORREF crKey, // specifies the color key 
BYTE bAlpha, // value for the blend function 
DWORD dwFlags // action 
); 


Windows NT/2000/XP: Included in Windows 2000 and later. 
Windows 95/98/Me: Unsupported.(注意了,在win9x里没法使用的) 
Header: Declared in Winuser.h; include Windows.h. 
Library: Use User32.lib. 


一些常量: 


WS_EX_LAYERED = 0x80000; 
LWA_ALPHA = 0x2; 
LWA_COLORKEY=0x1; 

  其中dwFlags有LWA_ALPHA和LWA_COLORKEY 

  LWA_ALPHA被设置的话,通过bAlpha决定透明度. 

  LWA_COLORKEY被设置的话,则指定被透明掉的颜色为crKey,其他颜色则正常显示. 

  要使使窗体拥有透明效果,首先要有WS_EX_LAYERED扩展属性(旧的sdk没有定义这个属性,所以可以直接指定为0x80000). 

  例子代码: 

  在OnInitDialog()加入: 

//加入WS_EX_LAYERED扩展属性 
SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE, 
GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^0x80000); 
HINSTANCE hInst = LoadLibrary("User32.DLL"); 
if(hInst) 
{ 
 typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD); 
 MYFUNC fun = NULL; 
 //取得SetLayeredWindowAttributes函数指针 
 fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes"); 
 if(fun)fun(this->GetSafeHwnd(),0,128,2); 
 FreeLibrary(hInst); 
} 

  稍加修改还可以作出淡出淡入的效果. 注意第三个参数(128)不要取得太小了,为0的话就完全透明,看不到了。

16.如何使框架窗口的图标为动画显示 

  可以用TIMER,但是TIMER不能有效的定时。因为TIMER发送的是窗口消息,当窗口忙于处理键盘、鼠标等消息时就不能及时处理TIMER,会使间隔时间变得很长 。 

  可以考虑用一个单独得TIMER线程,用Sleep()定时来解决此问题。 


UINT Timer(LPVOID param) 
{ 
 HWND hWnd=(HWND)param; 
 while(1) 
 { 
  Sleep(ms); 
  PostMessage(hWnd,CH_PICTURE,NULL,NULL) 
 } 
} 

  Sleep(ms)后发送自定义消息。消息处理函数就选择某一个ICON或BITMAP来显示。如 : 


MyBotton.SetBitmap((HBITMAP)Bitmap[i]); 

  Bitmap是一个位图数组,存放有j个位图。消息处理函数运行一次,i就累加一次,当i==j时,i就回到0;

17.Q 如何处理ComboBox中的回车键?避免退出程序? 
A 在一般的EDIT中采用的方法是处理PretranlateMessage(),执行代码 
CWnd *pWnd = GetFocus(); 
if(pWnd != NULL) 
{ 
  if(pWnd == GetDlgItem(IDC_EDIT1) 
  { 
    ...//IDC_EDIT1具有焦点 
  } 
} 

但在ComboBox中好象不同,是ComboBox的编辑控件得到了焦点,所以判断代码: 
BOOL CDlg::PreTranslateMessage(MSG *pMsg) 
{ 
  if(pMsg->message==WM_KEYDOWN && pMsg->wParam == VK_RETURN) 
  { 
      CWnd *pWnd = GetFocus(); 
      if(pWnd != NULL) 
      { 
        if(pWnd->GetParent() == GetDlgItem(IDC_COMBO1)//更改ID 
        { 
              return TRUE; 
        } 
      } 
  } 
  return CDialog::PreTranslateMessage(pMsg); 
} 

//------------------------------------------------- 
Q 动态创建的组合框如何设置下拉列表框的高度? 
A m_combo.Create(WS_CHILD | WS_VISIBLE | WS_VSCROLL CBC_SORT | CBC_DROPDOWNLIST | WS_TABSTOP, CRect(320,10,580,280),this,114); 
//CRect的最后一个参数(这里是280)就表示下拉大小 

//------------------------------------------------- 
Q 是否能不选择下拉列表样式而禁止用户输入值,有什么方法可以实现? 
A 将下拉列表的编辑控件设置为只读的,方法如下: 
CComboBox *pcombo; 
CWnd *pWnd = pcombo->GetWindow(GW_CHILD); 
while(pWnd) 
{ 
  char classname[256]; 
  ::GetClassName(pWnd->m_hWnd,classname,256) 
  if(strcmp(classname,"edit") == 0) 
  { 
    CEdit *pEdit; 
    pEdit = new CEdit(); 
    pEdit->SubClassWindow(pWnd->m_hWnd); 
    pEdit->SetReadOnly(); 
    pWnd = pWnd->GetNextWindow(); 
    delete pEdit; 
  } 
  if(pWnd) 
    pWnd = pWnd->GetNextWindow(); 
} 

//------------------------------------------------- 
Q ComboBox的自定义弹出菜单,想在右击组合框的编辑部分的时候弹出菜单? 
A 一种方法就是在CCustomCombo的OnCtlColor函数里进行,生成ComboBox中编辑框的子类,示例: 
HBRUSH CCustomCombo::OnCtlColor(CDC *pDC,CWnd *pWnd,UINT nCtlColor) 
{ 
  if(nCtlColor == CTLCOLOR_EDIT) 
  { 
    if(m_edit.GetSafeHwnd()==NULL) 
        m_eidt.SubClassWindow(pWnd->GetSafeHwnd()); 
  } 
  HBRUSH hbr = CComboBox::OnCtlColor(pDC,pWnd,nCtlColor); 
  return hbr; 
} 
//其中m_edit是CEdit类的实现,它在WM_RBUTTONUP上显示右键菜单 

//------------------------------------------------- 
Q 如何给按钮加位图 
A 
对动态创建的按钮: 
CButton button; 
button.Create(_T("My Button"),WS_CHILD | WS_VISIBLE | BS_BITMAP,CRect(10,10,60,50),pParentWnd,1); 
button.SetBitmap(::LoadBitmap(NULL,MAKEINTRESOURCE(IBM_CHECK))); 
或者修改风格: 
UINT Style = Button.GetButtonStyle(); 
Style = Style | BS_BITMAP; 
Button.SetBitmap(::LoadBitmap(NULL,MAKEINTRESOURCE(IBM_CHECK))); 

//------------------------------------------------- 
Q 如何在CButton派生类中以及父对话框中捕获BN_CLICKED消息? 
A 于WM_NOTIFY消息相反,通知消息BN_CLICKED作为WM_COMMAND消息发送。因此应用程序应该使用ON_CONTROL_REFLECT_EC而不是ON_NOTIFY_REFLECT 

//------------------------------------------------- 
Q 如何判断某个对象是否具有当前焦点? 
A return (CWnd::GetFocus() == pWnd); 

//------------------------------------------------- 
Q 如何设置编辑控件的数字限制属性? 
A 
long Style = GetWindowLong(m_EditCtrl.m_hWnd,GWL_STYLE); 
Style |= ES_NUMBER; 
SetWindowLong(m_EditCtrl.m_hWnd,GWL_STYLE,Style); 

//------------------------------------------------- 
Q 希望在LISTCTRL中显示文件,如何才能得到explorer使用的相同图象? 
A 可以将系统的ImageList加到LISTCTRL上,然后用具有SHGFI_ICON标志的SHGetFileInfo获取适当的图标索引: 
//图象列表设置 
HIMAGELIST himagelist; 
SHFILEINFO fi; 
CImageList m_smalllist; 
//得到系统小图标列表的句柄 
himagelist = (HIMAGELIST)SHGetFileInfo((LPCTSTR)_T("C://"),0,&fi,sizeof(SHFILEINFO),SHGFI_SYSICONINDEX | SHGFI_SMALLICON); 
//添加到小图象列表 
m_smalllist.Attach(himagelist); 
//设置LISTCTRL的图象列表 
m_listCtrl.SetImageList(&m_smalllist,LVSIL_SMALL); 
//分离图象列表 
m_smalllist.Detach(); 

//------------------------------------------------- 
Q 如何在列表的任何一列显示图标,而不是第一列? 
A 
LV_ITEM item; 
... 
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM; 
item.iItem = ...//设置行号 
item.lParam = ...//如何需要就设置lparam参数 
item.iSubItem = ...//设置列号,从0开始的 
item.stateMask = LVIS_STATEIMAGEMASK; 
item.state = INDEXTOSTATEIMAGEMASK(...);//参数为图标号 
item.iImage = ...//设置图标号 
item.pszText = ...//显示文本 
//插入新项 
m_listctrl.InsertItem(&item); 
//现在设置图标 
m_listctrl.SetItemText(0,4,szField); 

//------------------------------------------------- 
Q 给LISTBOX添加新项时如何实现自动下滚? 
A 在调用AddString后,添加如下代码: 
m_listbox.SetTopIndex(m_listbox.GetCount()-1); 

//------------------------------------------------- 
Q listBox的文本超过框的宽度时,如何让水平滚动条正常工作? 
A 用下面的代码,设置滚动条的宽度为最长的字符串宽度 
void SetHorizontalExtent(CListBox &listbox) 
{ 
    int index = listbox.GetCount(); 
    if(index == LB_ERROR) 
      return; 
    int nExtent = 0; 
    if(index) 
    { 
        CDC *pDC = listbox.GetDC(); 
CFont *poldfont = pDC->SelectObject(listbox.GetFont()); 
CString s; 
SIZE text; 
LONG maxtxt = 0; 
whilw(index--) 
{ 
            listbox.GetText(index,s); 
      text = pDC->GetOutputTextExtent(s); 
      if(text.cx > maxtxt) 
                maxtxt = text.cx; 
  } 
        text.cx = maxtxt; 
      pDC->LPToDP(&text); 
      nExtent = text.cx+2; 
      pDC->SelectObject(poldfont); 
      listbox.ReleaseDC(pDC); 
    }  
    listbox.SetHorizontalExtent(nExtent); 
} 

//-------------------------------------------------

18.Q 在拆分视图的时候,创建了四个视图(2行2列),右下的是CFormView,其他的都是CView,在CMainFrame的OnCreateCilent不管怎么指定CRect的大小,下方的两个视图都占了整个窗口,需要拖动! 
A 一般只需要在OnCreateClient的末尾添加: 
m_wndSpitter.SetRowInfo(0,200,0);//添加此行代码 

//------------------------------------------------- 
Q 如何指定拆分窗口的最小宽度? 
A 使用CSpitterWnd::SetColumnInfo() 
  void SetColumnInfo(int col, //指定列 
      int deal, //理想宽度(像素) 
      int cxmin); //最小宽度(像素) 
在使用SetColumnInfo之后还应该调用RecalLayout();重新调整布局。 
  
//-------------------------------------------------- 
Q 如何判断工具栏是水平还是垂直的? 
A if((m_toolbar.GetBarStyle() & CBRS_ALIGN_LEFT) == CBRS_ALIGN_LEFT || 

(m_toolbar.GetBarStyle() & CBRS_ALIGN_RIGHT) == CBRS_ALIGN_RIGHT) 
    AfxMessageBox("vertical"); 
  else 
    AfxMessageBox("horizontal"); 

//-------------------------------------------------- 
Q 编程方式修改工具栏按钮的可见性? 
A 示例代码: 
DWORD style = m_toolbar.GetButtonStyle(nIndex); 
if(m_bHide) 
  m_toolbar.SetButtonStyle(nIndex,style & ~WS_VISIBLE); 
else 
  m_toolbar.SetButtonStyle(nIndex,style | WS_VISIBLE); 
m_bHide = !m_bHide; 

//-------------------------------------------------- 
Q 如何在状态栏添加按钮并响应? 
A 创建一个从CButton派生的CMyButton类,在主框架类添加CMyButton类的成员变量,然后在OnCreate函数中创建按钮,并把它和状态栏关联起来: 
m_mybtn.Create("MyButton",WS_CHILD | VISIBLE,CRect(0,0,60,20),&m_WndStatusBar,0); 
通过处理BN_CLICKED消息,可以在CMyButton类中处理所有的点击事件 

//-------------------------------------------------- 
Q 如何隐藏属性CPropertySheet的标题栏,使用ModifyStyle(WINDOW_CAPTION,0)没有效果 
A 创建自己的CPropertySheet派生类,并覆盖OnInitDialog,转到默认的情况后,使用ModifyStyle来删除WS_CAPTION标志 

//-------------------------------------------------- 
Q 如何让属性页有两行标签? 
A 从CPropertySheet派生类,添加PreCreateWindow的处理,在调用基类之前添加代码: 
cs.style |= TCS_MULTILINE; 

//------------------------------------------------------ 
Q 如何在属性表的两个页之间传递数据? 
A 
CPropertyPage有一个成员函数QuerySiblings(WPARAM, LPARAM)。应用程序可以使用这个函数。 
QuerySiblings生成一条PSM_QUERYSIBLINGS消息,它传递给所有的兄弟,也就是属性表上的其他属性页。  一般可创建一个所有页可见的枚举,如: 
enum{QUERY_MY_STRING,  QUERY_SOMETHING_ELSE,.......} 
然后,在一个属性页需要其他属性页中的信息时,使用代码: 
CString myString; 
if(lL == QuerySiblings(QUERY_MY_STRING,(LPARAM)&myString)) 
{ 
        ....//获取字符串 
} 
提供字符串的页处理PSM_QUERYSIBLINGS消息: 
LRESULT CPageThatHasString::OnQuerySiblings(WPARAM wParam, LPARAM lParam) 
{ 
        if(QUERY_MY_STRING == wParam) 
      { 
              *((CString *)lParam) = _T(“Test String“); 
              return 1L; 
      } 
      else 
              return 0L; 
} 

//---------------------------------------------------------- 
Q  如何让属性页具有两行标签? 
 
从CPropertySheet派生一个自己的类,添加一个PreCreateWindow的处理,然后在调用基类的处理前加如下代码:cs.style |= TCS_MULTILINE; 

//----------------------------------------------------------- 
Q  如何隐藏属性页的标题栏? 
 
从CPropertySheet派生一个自己的类,并覆盖OnInitDialog,在转到默认的情况以后,使用 ModifyStyle来删除标题栏标志WS_CAPTION。 
  ModifyStyle(WS_CAPTION,0); 

//------------------------------------------------------------------- 
Q 如何枚举桌面项目? 
A 
1 得到指向IShellFolder接口的指针 
2 得到指向IMalloc接口的指针 
3 得到指向IEnumIDList接口的指针 
4 提取枚举中下一项目的PIDL 
5 测定PIDL代表的标志符的类型 
6 处理该项目 
7 释放PIDL分配的内存 
8 重复4到7步,知道所有的项目都枚举完 
9 释放IShellFolder IMalloc IEnumIDList接口的指针 

LPSHELLFOLDER lpshellfolder; 
LPMALLOC lpmalloc; 
LPENUMIDLIST lpidlist; 
m_namecount = 0; 
HRESULT hr = SHGetDestopFolder(&lpshellfolder); 
if(hr == NOERROR) 
{ 
    hr = ::SHGetMalloc(&lpmalloc); 
    if(hr == NOERROR) 
    { 
        hr = lpshellfolder->EnumObject(NULL,SHCONTF_FOLDERS | SHCONTF_NONFOLDERS,&lpidlist); 
        if(hr == NOERROR) 
            ProcessFolder(lpshellfolder,lpmalloc,lpidlist);//custom deal function 
        lpmalloc->Release(); 
        lpidlist->Release(); 
        InValidate(); 
    } 
    lpshellfolder->Release(); 
} 

void ***::ProcessFolder(LPSHELLFOLDER lpshellfolder,LPMALLOC lpmalloc,LPENUMIDLIST lpidlist) 
{ 
  STRRET strret; 
  ULONG numfetch; 
  LPITEMIDLIST lpitemlist; 
  HRESULT hr = lpidlist->Next(1,&lpitemlist,&numfetch); 
  while(hr == NOERROR) 
  { 
      ULONG attributes = SFGAO_FOLDER; 
      lpshellfolder->GetAttributes(1,(const struct _ITEMIDLIST **)&lpitemlist,&attributes); 
      if(attributes & SFGAO_FOLDER) 
      { 
          hr = lpshellfolder->GetDiaplayNameOf(lpitemlist,SHGDN_NORMAL,&strret); 
          if(m_nameCount < 20) 
              m_names[m_namecount++] = strret.str; 
      } 
      lpmalloc->Free(lpitemlist); 
      hr = lpidlist->Next(1,&lpitemlist,&numfetch); 
  } 
} 
//------------------------------------------------------------------- 
Q  如何创建桌面快捷方式? 
A: 
1 initialize com 
2 create LShellLink Object 
3 Use IShellLink interface to get the pointer about IPersistFile 
4 Use IShellLink interface to initialize link 
5 Use LPersistFile interface to save the link 
6 Release all the com pointer 
7 Com return to previous status 

1 
HRESULT hr = CoInitialize(NULL); 
if(hr == S_OK) 
{ 
  ...//Continue 
} 

2 
IShellLink *pshelllink; 
pshelllink = CoCreateInstance(CLSID_ShellLink,NULL,CLSCTX_INPROC_SERVER,IID_IShellLink,(void **)&pshelllink); 

3 
IPersistFile *persistfile; 
persistfile = pshelllink->QueryInterface(IID_IPersistFile,(void **)&persistfile); 

4 
pshelllink->SetPath("C://config.sys"); 
pshelllink->SetDescription("ShortCut to config.sys"); 

5 
char path[MAX_PATH]; 
GetWindowsDirectory(path,MAX_PATH); 
int len = strlen(path); 
strcpy(&path[len],"//desktop//config.lik"); 
//change the char from ANSI to UNICODE 
OLECHAR widepath[MAX_PATH]; 
MultiByteToWideChar(CP_ACP,0,path,-1,widepath,MAX_PATH); 
persistfile->Save(widepath,TRUE); 

6 
pshelllink->Release(); 
psersistfile->Release(); 

7 
CoUnInitialize(); 

有部分代码有点错误,但修改容易

19.Q 在拆分视图的时候,创建了四个视图(2行2列),右下的是CFormView,其他的都是CView,在CMainFrame的OnCreateCilent不管怎么指定CRect的大小,下方的两个视图都占了整个窗口,需要拖动! 
A 一般只需要在OnCreateClient的末尾添加: 
m_wndSpitter.SetRowInfo(0,200,0);//添加此行代码 

//------------------------------------------------- 
Q 如何指定拆分窗口的最小宽度? 
A 使用CSpitterWnd::SetColumnInfo() 
  void SetColumnInfo(int col, //指定列 
      int deal, //理想宽度(像素) 
      int cxmin); //最小宽度(像素) 
在使用SetColumnInfo之后还应该调用RecalLayout();重新调整布局。 
  
//-------------------------------------------------- 
Q 如何判断工具栏是水平还是垂直的? 
A if((m_toolbar.GetBarStyle() & CBRS_ALIGN_LEFT) == CBRS_ALIGN_LEFT || 

(m_toolbar.GetBarStyle() & CBRS_ALIGN_RIGHT) == CBRS_ALIGN_RIGHT) 
    AfxMessageBox("vertical"); 
  else 
    AfxMessageBox("horizontal"); 

//-------------------------------------------------- 
Q 编程方式修改工具栏按钮的可见性? 
A 示例代码: 
DWORD style = m_toolbar.GetButtonStyle(nIndex); 
if(m_bHide) 
  m_toolbar.SetButtonStyle(nIndex,style & ~WS_VISIBLE); 
else 
  m_toolbar.SetButtonStyle(nIndex,style | WS_VISIBLE); 
m_bHide = !m_bHide; 

//-------------------------------------------------- 
Q 如何在状态栏添加按钮并响应? 
A 创建一个从CButton派生的CMyButton类,在主框架类添加CMyButton类的成员变量,然后在OnCreate函数中创建按钮,并把它和状态栏关联起来: 
m_mybtn.Create("MyButton",WS_CHILD | VISIBLE,CRect(0,0,60,20),&m_WndStatusBar,0); 
通过处理BN_CLICKED消息,可以在CMyButton类中处理所有的点击事件 

//-------------------------------------------------- 
Q 如何隐藏属性CPropertySheet的标题栏,使用ModifyStyle(WINDOW_CAPTION,0)没有效果 
A 创建自己的CPropertySheet派生类,并覆盖OnInitDialog,转到默认的情况后,使用ModifyStyle来删除WS_CAPTION标志 

//-------------------------------------------------- 
Q 如何让属性页有两行标签? 
A 从CPropertySheet派生类,添加PreCreateWindow的处理,在调用基类之前添加代码: 
cs.style |= TCS_MULTILINE; 

//------------------------------------------------------ 
Q 如何在属性表的两个页之间传递数据? 
A 
CPropertyPage有一个成员函数QuerySiblings(WPARAM, LPARAM)。应用程序可以使用这个函数。 
QuerySiblings生成一条PSM_QUERYSIBLINGS消息,它传递给所有的兄弟,也就是属性表上的其他属性页。  一般可创建一个所有页可见的枚举,如: 
enum{QUERY_MY_STRING,  QUERY_SOMETHING_ELSE,.......} 
然后,在一个属性页需要其他属性页中的信息时,使用代码: 
CString myString; 
if(lL == QuerySiblings(QUERY_MY_STRING,(LPARAM)&myString)) 
{ 
        ....//获取字符串 
} 
提供字符串的页处理PSM_QUERYSIBLINGS消息: 
LRESULT CPageThatHasString::OnQuerySiblings(WPARAM wParam, LPARAM lParam) 
{ 
        if(QUERY_MY_STRING == wParam) 
      { 
              *((CString *)lParam) = _T(“Test String“); 
              return 1L; 
      } 
      else 
              return 0L; 
} 

//---------------------------------------------------------- 
Q  如何让属性页具有两行标签? 
 
从CPropertySheet派生一个自己的类,添加一个PreCreateWindow的处理,然后在调用基类的处理前加如下代码:cs.style |= TCS_MULTILINE; 

//----------------------------------------------------------- 
Q  如何隐藏属性页的标题栏? 
 
从CPropertySheet派生一个自己的类,并覆盖OnInitDialog,在转到默认的情况以后,使用 ModifyStyle来删除标题栏标志WS_CAPTION。 
  ModifyStyle(WS_CAPTION,0); 

//------------------------------------------------------------------- 
Q 如何枚举桌面项目? 
A 
1 得到指向IShellFolder接口的指针 
2 得到指向IMalloc接口的指针 
3 得到指向IEnumIDList接口的指针 
4 提取枚举中下一项目的PIDL 
5 测定PIDL代表的标志符的类型 
6 处理该项目 
7 释放PIDL分配的内存 
8 重复4到7步,知道所有的项目都枚举完 
9 释放IShellFolder IMalloc IEnumIDList接口的指针 

LPSHELLFOLDER lpshellfolder; 
LPMALLOC lpmalloc; 
LPENUMIDLIST lpidlist; 
m_namecount = 0; 
HRESULT hr = SHGetDestopFolder(&lpshellfolder); 
if(hr == NOERROR) 
{ 
    hr = ::SHGetMalloc(&lpmalloc); 
    if(hr == NOERROR) 
    { 
        hr = lpshellfolder->EnumObject(NULL,SHCONTF_FOLDERS | SHCONTF_NONFOLDERS,&lpidlist); 
        if(hr == NOERROR) 
            ProcessFolder(lpshellfolder,lpmalloc,lpidlist);//custom deal function 
        lpmalloc->Release(); 
        lpidlist->Release(); 
        InValidate(); 
    } 
    lpshellfolder->Release(); 
} 

void ***::ProcessFolder(LPSHELLFOLDER lpshellfolder,LPMALLOC lpmalloc,LPENUMIDLIST lpidlist) 
{ 
  STRRET strret; 
  ULONG numfetch; 
  LPITEMIDLIST lpitemlist; 
  HRESULT hr = lpidlist->Next(1,&lpitemlist,&numfetch); 
  while(hr == NOERROR) 
  { 
      ULONG attributes = SFGAO_FOLDER; 
      lpshellfolder->GetAttributes(1,(const struct _ITEMIDLIST **)&lpitemlist,&attributes); 
      if(attributes & SFGAO_FOLDER) 
      { 
          hr = lpshellfolder->GetDiaplayNameOf(lpitemlist,SHGDN_NORMAL,&strret); 
          if(m_nameCount < 20) 
              m_names[m_namecount++] = strret.str; 
      } 
      lpmalloc->Free(lpitemlist); 
      hr = lpidlist->Next(1,&lpitemlist,&numfetch); 
  } 
} 
//------------------------------------------------------------------- 
Q  如何创建桌面快捷方式? 
A: 
1 initialize com 
2 create LShellLink Object 
3 Use IShellLink interface to get the pointer about IPersistFile 
4 Use IShellLink interface to initialize link 
5 Use LPersistFile interface to save the link 
6 Release all the com pointer 
7 Com return to previous status 

1 
HRESULT hr = CoInitialize(NULL); 
if(hr == S_OK) 
{ 
  ...//Continue 
} 

2 
IShellLink *pshelllink; 
pshelllink = CoCreateInstance(CLSID_ShellLink,NULL,CLSCTX_INPROC_SERVER,IID_IShellLink,(void **)&pshelllink); 

3 
IPersistFile *persistfile; 
persistfile = pshelllink->QueryInterface(IID_IPersistFile,(void **)&persistfile); 

4 
pshelllink->SetPath("C://config.sys"); 
pshelllink->SetDescription("ShortCut to config.sys"); 

5 
char path[MAX_PATH]; 
GetWindowsDirectory(path,MAX_PATH); 
int len = strlen(path); 
strcpy(&path[len],"//desktop//config.lik"); 
//change the char from ANSI to UNICODE 
OLECHAR widepath[MAX_PATH]; 
MultiByteToWideChar(CP_ACP,0,path,-1,widepath,MAX_PATH); 
persistfile->Save(widepath,TRUE); 

6 
pshelllink->Release(); 
psersistfile->Release(); 

7 
CoUnInitialize(); 

有部分代码有点错误,但修改容易

20.一、新建一个类,已经保存,为何有时候在"ClassView"里看不到这个类? 
答:菜单[工程]->[添加到工程...]->[文件...]添加XXXClass.h和.cpp文件,如果在"ClassView"里还是看不到,"FileView"里找到XXXClass.h文件,在class CXXXClass的CXXXClass这个地方任意改变类名,此时就看到了,之后再改变为CXXXClass. 

二、怎么改变对话框上各控件的tab顺序? 
答:在资源视图,对话框IDD_DIALOG1下,按Ctrl+D,看到各个控件前有个数字,这个数字便是TAB键顺序,按照你要求重新排序这些数字便可。 

三、在使用COMBOBOX时,怎么设置当弹出下拉列表框时的高度? 
答:在资源视图,找到IDC_COMBOBOX1,单击“箭头”,此时调整个高度便是下拉列表框可见时的高度,如果是动态create出来的,参数rect的高便是下拉列表框可见时的高,而CComboBox::SetItemHeight(-1, 15)为设置组合框高度。 

四、在IDC_LIST1与CListCtrl m_list关联后,有时输入m_list.后并没有智能提示出CListCtrl的函数是怎么回事? 
答:是VC开发环境的BUG,我个人的解决方法是先用CXXXClass::出现提示后定位选择函数,再把CXXXClass::换成变量名.这个问题希望有朋友可以解答下。 

五、在用TabCtrl控件时,为何不可以按标签页来定制某页上的控件? 
答:VC的TabCtrl不支持这样的操作,方法是先建立一对话框资源IDD_DIALOGX(跟工程无关的),把某标签页上所有控件调整大小并排版,然后全选粘贴在工程中正式的对话框IDD_DIALOG1中,反复这样的操作,tabctrl有几页就招待几次,最后再添加TabCtrl在IDD_DIALOG1中,然后通过将IDC_TABCTRL1与CTabCtrl m_tab1关联,之后添加IDC_TABCTRL1的TCN_SELCHANGE消息处理函数,便可用int nPage = m_tab1.GetCurSel()取得当前标签号,接着再用switch(nPage)来选择处理各页显示的控件,控件显示可用ShowWindow(SW_SHOW/SW_HIDE)来控制,小技巧,在第一步时,可有意识的将第某页上的控件ID设为IDC_TAB1_NAME,IDC_TAB2_NAME,这样的形式,便于清楚的知道哪个控件是第几页中的。

在debug窗口怎么看不到调试输出的信息?

用Go不要用Run来运行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章