编程语言

img laiyiling

VC/MFC Q&A 200409

发表于2004/10/1 18:00:00  4352人阅读

分类: Summarize ActiveX/Com

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

阅读全文
0 0

相关文章推荐

img
取 消
img