VC/MFC 問答 200409

laiyiling收集整理,以後如果有時間會進行分類整理些資料,便於閱讀查找。

問】如何判定剪貼板中有沒有文本數據?
答】
COleDataObject dataObject;
dataObject.AttachClipboard();
if(dataObject.IsDataAvailable(CF_TEXT))
{
    .....//有文本數據
}
問】如何得到ComboBox的Edit句柄?
答】CEdit *pEdit = (CEdit*)CComboBox.GetWindow(GW_CHILD)
問】得到當前用戶目錄,即:C:/Documents and Settings/...
答】SHGetSpecialFolderPath(NULL,(LPTSTR)szPath,CSIDL_PERSONAL,FALSE);
問】狀態欄的高度怎樣改變?
答】m_wndStatusBar.GetStatusBarCtrl().SetMinHeight(40);
問】動態調整控件大小時需要注意的問題
答】
程序在執行WM_SIZE時,可能控件還沒有被程序創建完成,你必須確保你的控件被創建後才能使用MoveWindow,
1,你可以設一個BOOL變量,初值爲FALSE,在OnInitDialog的最後將它的值變成TRUE,在WM_SIZE中判斷這個變量,只有當它爲真時才進行MoveWindow操作。
2,你也可經先用::IsWindow(控件.GetSafeHwnd())判斷控件是否創建,只有當它爲真時才進行MoveWindow操作。
問】在PreTranslateMessage()中如何取得組合鍵比如CTRL+F1
答】if(pMsg->message ==WM_KEYDOWN&&pMsg->wParam==VK_F1 &&GetKeyState(VK_CONTROL)&0x80)
問】SendMessage和PostMessage的區別是什麼?
答】
PostMessage發送消息後就不等了,發了就回,管你處不處裏呢
SendMessage發送消息後還要等消息被處理之後函數才返回
更具體的解釋可以看:
http://msdn.microsoft.com/msdnmag/issues/1200/c/
問】文檔視圖程序怎麼使程序開始運行後不打開任何一個文檔?
答】
MDI
在程序的InitInstance中的ProcessShellCommand函數之前加入:
cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing
SDI
InitInstance函數中關於OnFileNew的調用去掉
問】如何向一個按鈕發送單擊消息?
答】
SendMessage(WM_COMMAND,((WPARAM)BN_CLICKED)<<8|(WPARAM)IDC_BUTTON,0L);
::PostMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDOK,BN_CLICKED),0);
::SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDOK,BN_CLICKED),0);
問】
sdi工程,在關閉窗口的時候總是提示我是否保存?怎麼才能不讓這個窗口彈出直接關閉呢?
答】
void CMainFrame::OnClose()
{
    // TODO: Add your message handler code here and/or call default
    GetActiveDocument()->SetModifiedFlag(FALSE); //加入這句!
    CFrameWnd::OnClose();
}
問】如何得到其他應用程序的文本內容?
答】發送WM_GETTEXT消息,而不能直接用GetWindowText函數,如果是用SDK,直接把CWnd換爲HWND
CWnd* pWnd = GetOtherAppWindow();
TCHAR buf[512];
pWnd->SendMessage(WM_GETTEXT,sizeof(buf)/sizeof(TCHAR),(LPARAM)(void*)buf);
看到這裏肯定有人會問?爲什麼GetWindowText函數不行呢?GetWindowText函數不就是發送WM_GETTEXT消息嗎?不是。GetWindowText函數只有在窗口屬於當前進程的時候纔會發送WM_GETTEXT消息。如果窗口屬於不同的進程,GetWindowText函數的行爲是不一樣的,MSDN的文檔說的很清楚:
如果目標窗口是屬於其他進程的,並且窗口也有標題欄。GetWindowText函數返回窗口的標題。如果窗口沒有標題欄則返回NULL。微軟一開始就是這麼設計GetWindowText函數的。也就是說我們用GetWindowText函數只能得到其他進程窗口的標題,而不能得到其他進程窗口裏子窗口的文本內容,如:編輯礦、組合框。
問】如何獲知某進程打開了哪些文件?
答】http://www.codeguru.com/Cpp/W-P/system/processesmodules/article.php/c2827
問】如何用CMyListCtrl(即自定義控件)取代CListView中的控件?
答】I made a custom control derived from CWnd, and now I want to use it as a view. My first solution was to embed the control into the view and handle OnSize in the view to position the control over the client area. The problem is that mouse messages go to the control and cannot be overridden in the view. The keystroke messages go to the view and must be manually forwarded to the control.
I read about CCtrlView as a base class for common controls. I've even managed to write the view around it (I believe that you wrote about this in an issue of MSJ), but I could not get it to work with my CWnd-based control. Can this be done, and how?
更多信息參見
http://msdn.microsoft.com/msdnmag/issues/01/11/c/default.aspx
問】誰能講講如何實現API鉤子?
答】My motivation for writing this article was the need for a really simple hooking framework, that will offer an easy to use interface and ability to capture different APIs. It intends to reveal some of the tricks that can help you to write your own spying system. It suggests a single solution how to build a set for hooking Win32 API functions on NT/2K as well as 98/Me (shortly named in the article 9x) family Windows. For the sake of simplicity I decided not to add a support for UNICODE. However, with some minor modifications of the code you could easily accomplish this task.
For more infomation please read the following article,更多信息參見
http://www.codeguru.com/Cpp/W-P/system/misc/article.php/c5667/
問】// 激活當前屏幕保護程序可以發送如下消息
答】PostMessage(WM_SYSCOMMAND,SC_SCREENSAVE,0);
問】怎樣得到屏幕的DC?
答】CDC *dc=CDC::FromHandle(::GetDC(NULL));
問】如何在狀態欄裏顯示漢字?
答】
m_wndStatusBar.SetPaneText(nPane, sMsg);
nPane是格子的序號,從0開始
sMsg是顯示的內容
問】TabCtrl響應雙擊關閉
答】可以用SetWindowLong設置上CS_DBLCLKS屬性
問】取得桌面的地址
答】char szPath[1000];
SHGetSpecialFolderPath(this->GetSafeHwnd(),szPath,CSIDL_DESKTOP,false);
問】如何編程修改系統文件的顯示屬性?
答】直接修改註冊表可以。
HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/Advanced
值Hidden,
當這個值爲2時,是“不顯示隱藏的文件和文件夾”
當這個值爲1時,是“顯示所有文件和文件夾”
問】如何判斷一個是否正被使用?
答】
HANDLE hf = CreateFile(cName,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
if(hf==INVALID_HANDLE_VALUE)
{
  messageBox("該文件正在被使用,請關閉部分程序在試");
  return;
}
CloseHandle(hf);
問】調試命令行參數程序時怎麼輸入參數?
答】
Project | Seeting | Debug
Program arguments中輸入你的參數
問】關於組合框的屬性
答】
如果組合框具有不可輸入只能下拉選擇屬性(DROPLIST),則直接關聯的成員變量只能是int類型,你需要GetLBText()函數來獲取當前選擇的文本。(這是我們使用組合框時情況最多的一種)
如果組合框除了下拉選擇外還可以輸入字符串(DropDown),則只能直接關聯CString類型的成員變量。要獲取當前選擇的序號需要自己構造函數來完成

ComboBox下拉框的可視長度是指在create的時候指定的rect高度,就是combox下拉框的高度。
問】如何編程打開關閉顯示器?
答】
SendMessage(hWnd, WM_SYSCOMMAND,SC_MONITORPOWER,-1);  //打開顯示器
SendMessage(hWnd, WM_SYSCOMMAND,SC_MONITORPOWER,1);  //關閉顯示器
問】如何控制系統任務欄的顯示和隱藏?
答】
//隱藏WINDOWS系統任務欄
 ::ShowWindow (::FindWindow("Shell_TrayWnd",NULL),SW_HIDE);
//恢復WINDOWS系統任務欄正常顯示
::ShowWindow (::FindWindow("Shell_TrayWnd",NULL),SW_SHOW);
問】如何去掉樹控件水平滾動條?
答】long style  = GetWindowLong(Handle,GWL_STYLE);
style |= TVS_NOHSCROLL;
SetWindowLong(Handle,GWL_STYLE,style);
::ShowWindow(hwnd,SW_HIDE);
問】怎樣在CFormView去掉滾動條?
答】
在OnInitialUpdate函數裏邊,用下面的語句就OK了,
SetScrollSizes(MM_TEXT,CSize(0,0))
問】
CRuntimeClass 的 m_pNextClass如何使用,我添加一個從CObject繼承的類,實現了序列化,但是得到改類的CRuntimeClass 的m_pNextClass爲空,爲什麼?
有沒有給定一個類的字符串名字,比如 "CMyObj",
通過CRuntimeClass *pClass = RUNTIME_CLASS(CMyObj);pClass->CreateObject();創建對象.注意"CMyObj" 與CMyObj不同,是否能自動轉換,或者使用CRuntimeClass 的字段m_lpszClassName進行匹配(關鍵是如何得到鏈表的頭部)
答】
1) m_pNextClass 爲空,表示你的類可能在鏈表尾部!
2) 可以實現,部分代碼如下:
CObject* GetShapeClass(CString strClassName)
{
 CRuntimeClass *pClass;
 AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
 for(pClass = pModuleState->m_classList;pClass!=NULL;
              pClass=pClass->m_pNextClass)
         {
  if(strClassName.Compare(pClass->m_lpszClassName)==0){
   return (pClass->CreateObject());
  }
 }
 return null;
}
返回的指針是cobject類型,你可以轉換成正確的類型!
問】怎樣編程改變某個文件夾的圖標?
答】
只需要在指定的文件夾下建立Desktop.ini文件,其內容如下
[.ShellClassInfo]
IconFile=E:/資源/icon/icon/tree5s.ico
IconIndex=0
改變IconFile的值爲你的圖標
並且設置該文件夾爲系統屬性
問】VC程序怎樣防止多重啓動?
答】
初始化函數裏創建互斥量,判斷返回值
BOOL CYourApp::InitInstance()
{
   HANDLE Handle;
   Handle = CreateMutex(NULL,FALSE,_T("MakeSheet3.0"));
   if(Handle==NULL)
 return FALSE;
   if(GetLastError() == ERROR_ALREADY_EXISTS)
   {
 AfxMessageBox("MakeSheet3.0已運行!",MB_ICONSTOP);
 return FALSE;
   }
   ........
}

或者使用原子:

#define AtomName "MyProgramNameAtom" //這個字串可以自己取,儘量取得特殊些

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    ATOM Atom;
    // 程序一開始,判斷原子是否存在
    if (GlobalFindAtom(AtomName))
        return 1;  // 程序已經運行,這兒直接退出
    Atom = GlobalAddAtom(AtomName);
    //...... 你的代碼
    // 程序退出前,刪除原子
    GlobalDeleteAtom(Atom);  return 1;
}
參考:
http://msdn.microsoft.com/msdnmag/issues/0900/c/default.aspx
問】誰能介紹ASSERT函數的用法?
答】
ASSERT()是一個調試程序時經常使用的宏,在程序運行時它計算括號內的表達式,如果表達式爲FALSE (0), 程序將報告錯誤,並終止執行。如果表達式不爲0,則繼續執行後面的語句。這個宏通常原來判斷程序中是否出現了明顯非法的數據,如果出現了終止程序以免導致嚴重後果,同時也便於查找錯誤。
ASSERT只有在Debug版本中才有效,如果編譯爲Release版本則被忽略。
ASSERT宏定義如下
#define ASSERT(f) /
do /
{ /
    if (!(f) && AfxAssertFailedLine(THIS_FILE, __LINE__)) /
        AfxDebugBreak(); /
} while (0) /
ASSERT(邏輯表達式)
如果括號中的邏輯表達式值爲假的話,會彈出調試命令窗口,提示具體在哪個文件的哪一行發生了斷言錯誤!
問】如何在建立文件時就分配好指定的磁盤空間?
答】
int iLength = 100000 ;
CFile file ;
file.Open(filename,CFile::modeCreate | CFile::modeWrite) ;
file.SetLength(iLength) ;
這是通過文件操作控制的,也可以參考<Windows核心編程>第17章中介紹的文件映射。
問】如何讓對話框帶上分割條?
答】
參考:http://www.codeproject.com/splitter/zsplitter.asp
http://www.codeproject.com/splitter/simpledlgsplitter.asp
問】誰做過UNICODE下,導出.CSV文件,怎麼寫入中文字符?
答】
應該就是文本寫入吧!
當然,不能使用CStdioFile的類,因爲他不支持UNICODE的讀寫,我做的一個給你參考
#ifndef __TEXTFILE_H
#define __TEXTFILE_H

class CTextFile : public CFile
{
public:
 virtual BOOL ReadString(CString& rString) {
#ifdef _UNICODE
  if (GetPosition() == 0) {
   Seek(2, CFile::begin);
  }
#endif  
  TCHAR tc;
  BOOL bFlag = false;

  rString.Empty();
  while (CFile::Read(&tc, sizeof(TCHAR))) {
   switch (tc) {
   case 0x0D: break;
   case 0x0A:
    bFlag = true;
    break;
   default:
    rString += tc;
   }

   if (bFlag)
    break;
  }
  return (!bFlag && rString.IsEmpty()) ? false : true;
 }

 virtual void WriteString(LPCTSTR lpsz) {
#ifdef _UNICODE
  if (GetPosition() == 0) {
   char  tc[2];
   tc[0] = (char)0xFF;
   tc[1] = (char)0xFE;
   CFile::Write(tc, 2);
  }
#endif
  CFile::Write(lpsz, _tcslen(lpsz) * sizeof(TCHAR));
 }
};
#endif //!__TEXTFILE_H
問】如何獲得指定網卡序號的Mac地址?
答】
提供一個函數供參考
void CGetMacAddrDlg::GetOneMac(int AdapterIndex)
{
    NCB ncb;
    UCHAR uRetCode;
 ASTAT Adapter;
    memset( &ncb, 0, sizeof(ncb) );
    ncb.ncb_command = NCBRESET;
    ncb.ncb_lana_num = AdapterIndex;   // 指定網卡號
 
 //首先對選定的網卡發送一個NCBRESET命令,以便進行初始化
 uRetCode = Netbios( &ncb );

    memset( &ncb, 0, sizeof(ncb) );
    ncb.ncb_command = NCBASTAT;
    ncb.ncb_lana_num = AdapterIndex;  // 指定網卡號

    strcpy( (char *)ncb.ncb_callname,"*" );
 // 指定返回的信息存放的變量
    ncb.ncb_buffer = (unsigned char *) &Adapter;
 ncb.ncb_length = sizeof(Adapter);

 // 發送NCBASTAT命令以獲取網卡的信息
 uRetCode = Netbios( &ncb );
    if ( uRetCode == 0 )
    {
  // 把網卡MAC地址格式化成常用的16進制形式,如0010-A4E4-5802
  CString strMacAddr;
  strMacAddr.Format( "%02X%02X-%02X%02X-%02X%02X/n",
      Adapter.adapt.adapter_address[0],
      Adapter.adapt.adapter_address[1],
      Adapter.adapt.adapter_address[2],
      Adapter.adapt.adapter_address[3],
      Adapter.adapt.adapter_address[4],
      Adapter.adapt.adapter_address[5] );

  //將網卡地址和序號存入數組中
  ADPTSTRCT AdptSt;
  AdptSt.nIndex = AdapterIndex;
  AdptSt.strMac = strMacAddr;
  m_arrAdapters.Add(AdptSt);
    }
}

void CGetMacAddrDlg::OnGetaddr()
{
 NCB Ncb;
    UCHAR uRetCode;
 LANA_ENUM lenum;
 int i = 0;
 
 memset(&Ncb, 0, sizeof(Ncb));
 Ncb.ncb_command = NCBENUM;
 Ncb.ncb_buffer = (UCHAR *)&lenum;
 Ncb.ncb_length = sizeof(lenum);

 //向網卡發送NCBENUM命令,以獲取當前機器的網卡信息,如有多少個網卡、每張網卡的編號等
 uRetCode = Netbios( &Ncb );
 //獲得所有網卡信息
 for(i=0; i < lenum.length ;i++)
 {
  GetOneMac(lenum.lana[i]);
 }
 
 //將保存到數組中的所有網卡信息在列表中顯示
 int iActualItem;
 LV_ITEM lvitem;
 TCHAR buffer[128];
 for(int iItem=0;iItem<m_arrAdapters.GetSize();iItem++)
 {
  for(int iSubItem=0;iSubItem<2;iSubItem++)
  {
   lvitem.mask = LVIF_TEXT|(iSubItem == 0? LVIF_IMAGE : 0);
   lvitem.iItem = (iSubItem == 0)? iItem : iActualItem;
   lvitem.iSubItem = iSubItem;
   lvitem.iImage = (iItem%2)?0:2;
  
   if (iSubItem == 0)
   {//序號
    sprintf(buffer,"%d", m_arrAdapters.GetAt(iItem).nIndex);
    lvitem.pszText = buffer;
    iActualItem = m_ctrlAdaptersLst.InsertItem(&lvitem);
   }
   else
   {//Mac地址
    sprintf(buffer,"%s",m_arrAdapters.GetAt(iItem).strMac);
    lvitem.pszText = buffer;
    m_ctrlAdaptersLst.SetItem(&lvitem);
   }
  }
 }
}

問】如何把一個程序註冊爲系統explore組件來運行?
答】
在Windows操作系統上,我們最常見的瀏覽器有兩種:文件瀏覽器(exploer.exe,應用於文件系統)和Internet瀏覽器(iexplore.exe,應用於互聯網資源)。由於這兩個瀏覽器功能強大,而且又與Windows操作系統捆綁銷售,最終也就成爲了瀏覽器的標準。但有時候,爲了給瀏覽器加入一些新的特性,我們往往會重新設計一個自己的瀏覽器。新的瀏覽器模仿標準瀏覽器的大部分功能,同時加入新特性。這種做法最直觀,但實際上也是相對於微軟的重複勞動,且工作量比較大。其實,使用BHO插件,一切都變得很簡單。

BHO(Browser Help Objects),是實現了特定接口的COM組件。開發好的BHO插件在註冊表特定的位置註冊好後,每當微軟的瀏覽器啓動,BHO實例就會被創建。在瀏覽器工作的工程中,BHO會接收到很多事件,比如瀏覽器瀏覽新的地址、前進或後退、生成新的窗口、瀏覽器退出等等;BHO可以在這些事件的響應中實現與瀏覽器的交互。

下面,我們首先來介紹一下BHO的工作原理。上面我們已經提到,BHO是COM組件,而且一定實現了IObjectWithSite接口。這些組件除了在註冊表中註冊爲COM Server外,還必須將它們的CLSID在HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/ CurrentVersion/Explorer/Browser Helper Objects下注冊爲子鍵。微軟在設計瀏覽器的時候,已經給這些組件預留了空間。每當瀏覽器啓動時,瀏覽器會首先在上述註冊表位置查看是否有註冊的BHO CLSID;如果有則分別創建一個實例,並對BHO實例進行初始化,建立交互連接。(注:BHO實例只有在創建它的瀏覽器窗口銷燬時才被釋放。)下圖演示了BHO的創建過程:


成功創建的BHO,不僅可以得到各種標準的瀏覽器操作事件,並做出響應;還可以定製瀏覽器的菜單、工具條等界面元素;更或者可以安裝鉤子函數,監視瀏覽器的一舉一動。值得注意的是,使用BHO插件,Internet瀏覽器要求在4.0以上版本;如果是文件瀏覽器,操作系統要求是Windows 95/98/2000或Window NT 4.0以上版本,並且Shell的版本在4.71以上。下面是支持BHO特性的系統一覽表:

Shell版本 操作系統版本 支持BHO
4.00 Windows 95 and Windows NT 4.0(IE版本爲 4.0) 僅IE4.0
4.71 Windows 95 and Windows NT 4.0(IE版本爲 4.0) IE和文件瀏覽器
4.72 Windows 98 IE和文件瀏覽器
5.00  Windows 2000 IE和文件瀏覽器

接下去,筆者就來介紹一下如何開發BHO插件,開發環境爲VC6.0(使用ATL),安裝Platform SDK中的Internet Development SDK。首先,啓動VC的ATL COM AppWizard,生成一個項目名爲BhoPlugin,其餘均採用默認設置。接着,我們就來分步詳細闡述。
第一步,增加一個ATL Object到該項目中。VC菜單Insert->New ATL Object…,在彈出的對話框中選擇“Internet Explorer Object”,輸入COM類名(在Short Name後輸入EyeOnIE,其它各項會自動生成)。完成後,我們可以看到CEyeOnIE類有一個基類IObjectWithSiteImpl,這個就是實現IObjectWithSite接口的模版類。
第二步,實現IObjectWithSite的接口方法。在這之前,我們要先定義幾個成員變量:CComQIPtr<IWebBrowser2, &IID_IWebBrowser2> mWebBrowser2,(需要加入#include "ExDisp.h"),用以保存瀏覽器組件的指針;DWORD mCookie,用以保存與瀏覽器的連接ID。IObjectWithSite有兩個接口方法:SetSite和GetSite。我們只需重載SetSite就行了。在EyeOnIE.h中增加函數聲明STDMETHOD(SetSite)(IUnknown *pUnkSite),在EyeOnIE.cpp實現如下:
STDMETHODIMP CEyeOnIE::SetSite(IUnknown *pUnkSite)
{
USES_CONVERSION;

if (pUnkSite)
{
mWebBrowser2 = pUnkSite;
if (mWebBrowser2)
{
return RegisterEventHandler(TRUE);
}
}
return E_FAIL;
}

HRESULT CEyeOnIE::RegisterEventHandler(BOOL inAdvise)
{
CComPtr<IConnectionPoint> spCP;
// Receives the connection point for WebBrowser events
CComQIPtr<IConnectionPointContainer, &IID_IConnectionPointContainer> spCPC(mWebBrowser2);
HRESULT hr = spCPC->FindConnectionPoint(DIID_DWebBrowserEvents2, &spCP);
if (FAILED(hr))
return hr;

if (inAdvise)
{
// Pass the event handlers to the container
hr = spCP->Advise(reinterpret_cast<IDispatch*>(this), &mCookie);
}
else
{
spCP->Unadvise(mCookie);
}
return hr;
}
我們可以看到,SetSite的參數實際上指向的是瀏覽器組件。在SetSite實現中,我們首先保存瀏覽器組件指針,然後將該BHO向瀏覽器註冊爲事件處理器。
第三步,實現IDispatch接口方法。事件處理也就在IDispatch::Invoke中實現(各個事件的ID在ExDispID.h中定義)。BHO可能會接收到很多事件,但我們只需要響應我們感興趣的那一部分。首先在EyeOnIE.h中增加該函數的聲明,在EyeOnIE.cpp的實現中,筆者試着響應瀏覽器瀏覽一個地址之前發出的事件DISPID_BEFORENAVIGATE2,以此來實現簡單的網址過濾功能,代碼參考如下:
STDMETHODIMP CEyeOnIE::Invoke(DISPID dispidMember,REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS * pDispParams,
VARIANT * pvarResult,EXCEPINFO * pexcepinfo,
UINT * puArgErr)
{
USES_CONVERSION;

if (!pDispParams)
return E_INVALIDARG;

switch (dispidMember)
{
//
// The parameters for this DISPID are as follows:
// [0]: Cancel flag - VT_BYREF|VT_BOOL
// [1]: HTTP headers - VT_BYREF|VT_VARIANT
// [2]: Address of HTTP POST data - VT_BYREF|VT_VARIANT
// [3]: Target frame name - VT_BYREF|VT_VARIANT
// [4]: Option flags - VT_BYREF|VT_VARIANT
// [5]: URL to navigate to - VT_BYREF|VT_VARIANT
// [6]: An object that evaluates to the top-level or frame
// WebBrowser object corresponding to the event.
//
case DISPID_BEFORENAVIGATE2:
{
LPOLESTR lpURL = NULL;
mWebBrowser2->get_LocationURL(&lpURL);
char * strurl;
if (pDispParams->cArgs >= 5 && pDispParams->rgvarg[5].vt == (VT_BYREF|VT_VARIANT))
{
CComVariant varURL(*pDispParams->rgvarg[5].pvarVal);
varURL.ChangeType(VT_BSTR);
strurl = OLE2A(varURL.bstrVal);
}
if (strstr(strurl, "girl.com"))
{
*pDispParams->rgvarg[0].pboolVal = TRUE;
::MessageBox(NULL, _T("該網頁已被禁止!"),_T("Warning"),MB_ICONSTOP);
return S_OK;
}
break;
}

case DISPID_NAVIGATECOMPLETE2:
break;
case DISPID_DOCUMENTCOMPLETE:
break;
case DISPID_DOWNLOADBEGIN:
break;
case DISPID_DOWNLOADCOMPLETE:
break;
case DISPID_NEWWINDOW2:
break;
case DISPID_QUIT:
RegisterEventHandler(FALSE);
break;
default:
break;
}

return S_OK;
}
我們看到,當用戶瀏覽的新地址包含"girl.com"字符的時候,瀏覽器就會彈出一個警告對話框,並且停止進一步的動作。另外值得注意的是,在DISPID_QUIT事件(瀏覽器將要退出)的響應中,我們將BHO事件處理器進行了註銷。
第四步,因爲BHO可能會被文件瀏覽器加載。如果我們不想這樣,我們就要在DllMain中對加載者進行判斷,參考如下:
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
// Check who's loading us.
// If it's Explorer then "no thanks" and exit...
TCHAR pszLoader[MAX_PATH];
GetModuleFileName(NULL, pszLoader, MAX_PATH);
_tcslwr(pszLoader);
if (_tcsstr(pszLoader, _T("explorer.exe")))
return FALSE;

_Module.Init(ObjectMap, hInstance, &LIBID_BHOPLUGINLib);
DisableThreadLibraryCalls(hInstance);
}
else if (dwReason == DLL_PROCESS_DETACH)
_Module.Term();
return TRUE; // ok
}
最後,別忘了修改註冊表文件,追加BHO的註冊信息。在EyeOnIE.rgs文件的下面增加如下代碼:
HKLM
{
SOFTWARE
{
Microsoft
{
Windows
{
CurrentVersion
{
Explorer
{
'Browser Helper Objects'
{
{6E28339B-7A2A-47B6-AEB2-46BA53782379}
}
}
}
}
}
}
}
注意,{6E28339B-7A2A-47B6-AEB2-46BA53782379}是筆者這個BHO的CLSID,如果你自己開發BHO,這裏應該正確填寫你的CLSID。

好了,一個簡單的BHO開發完成了。(可以到本人的個人主頁http://hqtech.nease.net下載實例源代碼。)BHO插件可以實現的功能還有很多,比如網頁內容分析、IE界面定製等等。作爲總結,筆者還要提醒讀者一點的是,如果不想讓BHO起作用了,可以註銷該插件,如下格式:regsvr32 /u yourpath/yourbho.dll,或者直接在註冊表中將“Browser Helper Objects”目錄下注冊的CLSID刪掉。
問】線程中用ADO訪問數據庫失敗?在非線程中是可以的,但在線程中就是連不上數據庫,爲什麼呀?
答】
在使用ADO的各個子線程中都要加入COM的初始化/反初始化代碼
//in the beginning of the thread
CoInitialize
.....
//in the end-point of the thread
CoUninitialize
問】怎麼用SQL語句更改ACCESS數據表一個字段的長度?
答】
改列大小:
ALTER TABLE 你的表 ALTER COLUMN 列名 你的類型 NOT NULL
也可以採用笨方法先drop某列,再alter tablenaem add column
問】
一個數據庫程序,用ACCESS,但在存儲數據後如MDB文件爲10M,但將數據全部刪除後MDB文件仍爲10M,這是爲什麼?具體改怎麼做?
答】
應該在刪除數據後將MDB文件壓縮

stdafx.h 文件中:
#import "c:/program files/common files/system/ado/msado15.dll" no_namespace rename("EOF","adoEOF")
#import "c:/program files/common files/system/ado/msjro.dll"

壓縮文件代碼:
try
{
 CString csSourceConnection;
 CString csDestConnection;

 CoInitialize(NULL);
  
 csSourceConnection.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s;Jet OLEDB:Database password=%s","c://tanyizhi.mdb","");
 csDestConnection.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s;Jet OLEDB:Database password=%s","c://tanyizhi_c.mdb","");
  
 JRO::IJetEnginePtr jet(__uuidof(JRO::JetEngine));
 //-------------------------if "no_namespace" then--------------------------------
 //IJetEnginePtr jet = NULL;
 //jet.CreateInstance(__uuidof(JetEngine));

 BeginWaitCursor();
 jet->CompactDatabase(csSourceConnection.AllocSysString(),csDestConnection.AllocSysString());
 EndWaitCursor();
 CoUninitialize();
 MessageBox("Database Compact Successful !~","Information",MB_ICONEXCLAMATION);
}
catch(_com_error &e)
{
 CString csError;
 csError =(LPCTSTR) e.Description();
 MessageBox(csError,"Error Info",MB_ICONEXCLAMATION);  
}

問】如何在規則DLL中引入DOC/VIEW體系?
答】參考:
http://www.codeproject.com/docview/sdicviewdll.asp
問】DLL中怎麼定義共用變量?
答】共享數據段
http://www.vcshare.net/bbs/ShowPost.asp?id=1193
問】如何取得當前運行進程的可執行文件名及其絕對路徑?
答】
GetModuleFileNameEx(hProcess, hModule, path, sizeof(path));
參考
http://www.vckbase.com/document/viewdoc/?id=1220
問】如何讓 Active X 控件支持 ON_MOUSEWHEEL 事件
答】
因爲 COleControl 不直接支持 ON_MOUSEWHEEL 事件,但 COleControl 是從 CWnd 派生出來的,而 CWnd 是支持這一事件的,因此考慮在應用程序主類(CXXXCtrl)中直接使用 CWnd 類的消息函數。方法如下:
1. 主類頭文件(一般爲XXXCtl.h)
   消息映射段添加如下代碼
   afx_msg void OnMouseWheel( UINT nFlags, short zDelta, CPoint pt );
2. 主類源程序文件(一般爲XXXCtl.cpp)
   在 BEGIN_MESSAGE_MAP 與 END_MESSAGE_MAP 中添加如下代碼
   ON_WM_MOUSEWHEEL()
3. 主類源程序文件
   添加函數實現代碼如下
   void COCXCtrl::OnMouseWheel( UINT nFlags, short zDelta, CPoint pt )
   {
 RECT rect;
 GetClientRect( &rect );
 ClientToScreen( &rect );
 if ((pt.x <= rect.right)&&(pt.x >= rect.left )&&(pt.y <= rect.bottom )&&(pt.y >= rect.top ))
 {
  if (zDelta == WHEEL_DELTA)
  {
   // rotate forward (away from the user)
                }
                else
                {
                           // rotate back (toward the user)
                }
        }
        CWnd::OnMouseWheel( nFlags, zDelta, pt ); 
   }
參考
http://support.microsoft.com/default.aspx?scid=kb;en-us;231465

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