使用ATL开发AJAX控件即XMLHttpRequest控件的经验体会

原创 2006年06月09日 10:33:00

由于最近一段时间要使用ATL开发相关的Ajax的组件,在开发过程中遇到的一些难点与大家分享一下

1)在COM中使用线程,要注意线程内与COM是否同步,使用散列集的方法可以保证
   在创建线程前使用散列,参考代码:
   HRESULT hr = CoMarshalInterThreadInterfaceInStream(IID_IReadXML, m_RXML, &m_pStr);//IID_IReadXML为接口IID,m_RXML为接口的智能指针CComQIPtr m_RXML,m_pStr为流IStream *m_pStr;
   if(FAILED(hr))
   {
    return E_NOTIMPL;
   }
   DWORD thread;
   ::CreateThread(NULL, 0, BackSendThread, (void *)this, 0, &thread);
   在线程中通过流来获取同步
   参考代码:
   DWORD WINAPI CXMLHttp::BackSendThread(void *pThis)
{
 CoInitialize(NULL);
 CXMLHttp *This = (CXMLHttp *)pThis;
 HRESULT hRes;
 CComQIPtr<IReadXML, &IID_IReadXML> m_spT;
 m_spT.Release();

 //接口散集
 if (This->m_pStr)
 {
  hRes =::CoGetInterfaceAndReleaseStream(This->m_pStr, IID_IReadXML, (void**)&m_spT);
 }
 //m_spT->backSend(This->m_varBody);
 m_spT->CallBackSend();
 m_spT.Release();

 CoUninitialize();
 return 0;
}

如果需要消息循环:可以在主线程中使用AtlWaitWithMessageLoop(handle);这样会保证线程的同步运行,毕竟运行STA环境里的

2)与网络实名等软件使用全局HOOK技术的软件的冲突,这些软件通常会截取软件发出的系统信息,造成资源被占用,解决方法是自定义用户消息
   WM_USER+1616等
   参考代码:
   发送消息
 HWND Wnd= ::FindWindow(NULL,"XMLDlg");
 IDispatch *temp = this;
 if(Wnd)
 {
  ::SendMessage(Wnd, WM_USER+1616, 0, (LPARAM)temp);
 }
   接收消息
   1、先映射消息
   BEGIN_MESSAGE_MAP(CXMLDlgDlg, CDHtmlDialog)
 ON_WM_SYSCOMMAND()
 //}}AFX_MSG_MAP
 ON_MESSAGE(WM_USER+1616, OnIDispatcMsg)
   END_MESSAGE_MAP()
   2、实现代码
   LRESULT CXMLDlgDlg::OnIDispatcMsg(WPARAM wParam, LPARAM lParam)
{
 m_spObj = (IDispatch *)lParam;
 const IID IID_IXMLHttpEvents = {0x030AB05F, 0x2898, 0x4042, 0x88, 0xC1, 0x3D, 0x9D, 0x4F, 0x1F, 0xE9, 0xE7};
 if(m_onCopyData)
 { 
  m_sink.SetDispPatch( m_spObj );//用于回调函数访问控件接口(IReadXML)
  CComQIPtr<IConnectionPointContainer> spContainer( m_spObj );
  if( !spContainer )
  {
   AfxMessageBox( _T("组件没有提供连接点功能") );
   return FALSE;
  }
  // 得到连接点接口
  spContainer->FindConnectionPoint(
   IID_IXMLHttpEvents,
   &m_spCP );
  if( !m_spCP )
  {
   AfxMessageBox( _T("没有找到连接点接口") );
   return FALSE;
  }
  HRESULT hr = m_spCP->Advise( &m_sink, &m_dwCookie );
  if( FAILED( hr ) )
  {
   AfxMessageBox( _T("连接失败") );
  }
  m_onCopyData = FALSE;
 }
 else
 {
  if( m_spCP )
  {
   m_spCP->Unadvise( m_dwCookie );
   m_spCP.Release();
   
   m_sink.SetDispPatch( m_spObj );
   CComQIPtr<IConnectionPointContainer> spContainer( m_spObj );
   if( !spContainer )
   {
    AfxMessageBox( _T("组件没有提供连接点功能") );
    return FALSE;
   }
   // 得到连接点接口
   spContainer->FindConnectionPoint(
    IID_IXMLHttpEvents,
    &m_spCP );

   if( !m_spCP )
   {
    AfxMessageBox( _T("没有找到连接点接口") );
    return FALSE;
   }
   HRESULT hr = m_spCP->Advise( &m_sink, &m_dwCookie );
   if( FAILED( hr ) )
   {
    AfxMessageBox( _T("连接失败") );
   }
   m_onCopyData = FALSE;
  }
 }
 return 0;
}

3)对于获取其它容器所创建的控件的接口(比如JS创建的控件),主动获取有可能会比较困难,可以逆向思维,让创建的控件将接口自已以消息的方式发送过来,这样要相对简单一些。

4)增加MFC的浏览器滚动条
   在OnInitDialog()中 CDHtmlDialog::OnInitDialog();之前使用:SetHostFlags(DOCHOSTUIFLAG_NO3DBORDER   |   DOCHOSTUIFLAG_FLAT_SCROLLBAR );
   参考代码:
   BOOL CXMLDlgDlg::OnInitDialog()
{
 SetHostFlags(DOCHOSTUIFLAG_NO3DBORDER   |   DOCHOSTUIFLAG_FLAT_SCROLLBAR );//增加浏览器滚动条
 CDHtmlDialog::OnInitDialog();

 // 将/“关于.../”菜单项添加到系统菜单中。

 // IDM_ABOUTBOX 必须在系统命令范围内。
 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
 ASSERT(IDM_ABOUTBOX < 0xF000);

 CMenu* pSysMenu = GetSystemMenu(FALSE);
 if (pSysMenu != NULL)
 {
  CString strAboutMenu;
  strAboutMenu.LoadString(IDS_ABOUTBOX);
  if (!strAboutMenu.IsEmpty())
  {
   pSysMenu->AppendMenu(MF_SEPARATOR);
   pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  }
 }

 // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
 //  执行此操作
 SetIcon(m_hIcon, TRUE);   // 设置大图标
 SetIcon(m_hIcon, FALSE);  // 设置小图标

 // TODO: 在此添加额外的初始化代码
 return TRUE;  // 除非设置了控件的焦点,否则返回 TRUE
}

5)直接调用JS函数
HRESULT CXMLHttp::CallJsFun(IDispatch *Fun)
{

//Fun为你的JS函数地址

 try
 {
  HRESULT hr;
  DISPPARAMS dispparams;
  memset(&dispparams, 0, sizeof dispparams);
  CComVariant vResult;
  EXCEPINFO excepInfo;
  memset(&excepInfo, 0, sizeof excepInfo);
  UINT nArgErr = (UINT)-1;
  hr = Fun->Invoke(0, IID_NULL, 0, DISPATCH_METHOD, &dispparams, &vResult, &excepInfo, &nArgErr);
 }
 return S_OK;
 }
 catch(...)
 {
   return E_FAIL;
 }

6)接收回车键退出,且其它控件可以响应回车键
1:重载PreTranslateMessage函数:virtual BOOL PreTranslateMessage(MSG* pMsg);
2: 参考代码如下
BOOL CXXXDlg::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message == WM_KEYDOWN)
{
if (pMsg->wParam == VK_ESCAPE)//Esc键不退出程序
{
return TRUE;
}
else if(pMsg->wParam == VK_RETURN)
{
return FALSE;//对话框内部控件可以接收到回车消息!!如果你想将回车安全交给前台页面,请用DispatchMessage(pMsg);
//return TRUE;//对话框内部控件不可以接收到回车消息!!
//原因原来在这里,难为我困惑了那么久!!!
}
}

return CDialog::PreTranslateMessage(pMsg);
}

相关文章推荐

使用ATL开发ActiveX控件(添加事件,自己整理)

1、添加事件 在类视图中的XXXlib下面的_ICaleEvents中添加方法,带有钥匙标记的那个项(xxx为项目名,不要在类视图的根目录下找),根据需要选择有无参数、有无返回值,其中的参数是返回值...

ATL 开发ActiveX控件之定时器使用(改进,含源码)

原定时器设计:http://blog.csdn.net/strmagic/archive/2007/10/23/1840365.aspx 原定时器缺点1:使用继承方式无法实现一个类具有多个定时器...
  • willnow
  • willnow
  • 2011年05月31日 09:47
  • 2473

使用ATL开发ActiveX控件(转载)

www.cnblogs.com/watchdatalearn2012620/archive/2012/08/07/2626720.html 本文描述了使用ATL开发一个ActiveX控件的完整过程。...

使用ATL开发ActiveX控件MagicBox

  • 2011年11月27日 09:52
  • 116KB
  • 下载

RichEdit嵌入自开发OLE控件技术要点(ATL)

richedit插入gif实例下载: OLE封装库 RICHEDIT_DEMO 1、创建ATL复合文档控件。可通过wizard创建。 下面是创建OLE控件的最小头文件 // CSimpl...
  • wcyoot
  • wcyoot
  • 2012年02月15日 10:17
  • 3786

基于ATL开发ActiveX控件(第一节,简单的Hello world)

 一、开发环境     XP、Visual Studio2010。 二、 开发第一个ActiveX控件      第一步:创建工程      运行Visual Studio2010,我用C++语言开发...

atl开发ActiveX控件 转载保留

大家好,最近开始学习C++,由于工作原因需要维护和完善已有的ActiveX控件,本人对C++还是起步阶段,对开发ActiveX控件更是一无所知,于是把学习控件开发的经历记录下来,以便自己将来的温故和对...
  • cyebo
  • cyebo
  • 2015年02月02日 17:35
  • 390

使用ATL创建简单ActiveX控件(三) —— 添加连接点

创建过程以VS2010为例,分三篇(创建ATL项目、添加方法/属性和枚举、添加连接点)演示。本篇演示添加连接点。 传送门: 《使用ATL创建简单ActiveX控件(一) —— 创建ATL项目 》 ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用ATL开发AJAX控件即XMLHttpRequest控件的经验体会
举报原因:
原因补充:

(最多只允许输入30个字)