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來運行。

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