问答1 问答5 问答50 问答500 问答1000
网友互助专业问答平台

如何动态加载ActiveX控件

提问网友 发布时间:2022-04-20 12:05
声明:本网页内容为用户发布,旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。
E-MAIL:1656858193@qq.com
2个回答
热心网友 回答时间:2022-04-26 18:27
  使用ON_EVENT_RANGE就足以满足需要了,不过,还是希望能够更灵活的实现动态的响应,所以又经过对MFC源码一番探查,发现还是可以的,而且应该也不是很复杂的,下面分别来说说这两种方法

  例程为Tdax,对话框程序,使用了Microsoft UpDown Control 6.0控件作为控件,添加了MouseDown事件

  第一种方法挺简单的:

  1.

  缺省的映射定义为

  BEGIN_EVENTSINK_MAP(CTdaxDlg, CDialog)

  //{{AFX_EVENTSINK_MAP(CTdaxDlg)

  ON_EVENT(CTdaxDlg, IDC_UPDOWN1, -605 /* MouseDown */, OnMouseDownUpdown1, VTS_I2 VTS_I2 VTS_I4 VTS_I4)

  //}}AFX_EVENTSINK_MAP

  END_EVENTSINK_MAP()

  现改为

  BEGIN_EVENTSINK_MAP(CTdaxDlg, CDialog)

  //{{AFX_EVENTSINK_MAP(CTdaxDlg)

  //}}AFX_EVENTSINK_MAP

  ON_EVENT_RANGE(CTdaxDlg, IDC_UPDOWN1, IDC_UPDOWN1+10, -605 /* MouseDown */, OnMouseDownUpdown1, VTS_I4 VTS_I2 VTS_I2 VTS_I4 VTS_I4)

  END_EVENTSINK_MAP()

  就是说,可以映射至少11个控件(请注意,这里用了至少,也就是说可以少于11个,甚至于1个也无所谓)

  a.这里建议把ON_EVENT_RANGE从

  //{{AFX_EVENTSINK_MAP(CTdaxDlg)

  ON_EVENT_RANGE(CTdaxDlg, IDC_UPDOWN1, IDC_UPDOWN1+10, -605 /* MouseDown */, OnMouseDownUpdown1, VTS_I4 VTS_I2 VTS_I2 VTS_I4 VTS_I4)

  //}}AFX_EVENTSINK_MAP

  对中拖出来,见上面例子,不拖出来不会对程序产生影响,但可能会影响后续的IDE操作,试试便知。

  b.最后的参数类型中要在前面加上VTS_I4,即从VTS_I2 VTS_I2 VTS_I4 VTS_I4变为VTS_I4 VTS_I2 VTS_I2 VTS_I4 VTS_I4,当然事件处理函数也将做相应调整,下面马上讲到。

  2.

  修改框架建立的事件处理函数

  void OnMouseDownUpdown1(short Button, short Shift, long x, long y);

  改为

  BOOL OnMouseDownUpdown1(UINT nID, short Button, short Shift, long x, long y);

  返回类型为void,应该也无所谓的,不过msdn上说是BOOL,咱就BOOL吧,但UINT nID这个参数是一定要加上的

  3.做一些于本案无关的工作

  a.在对话框编辑器中删掉原来的ID为IDC_UPDOWN1的控件

  b.加一个成员变量CObList m_oaUpdowns;

  c.在OnInitDialog中,加上

  UINT nID = IDC_UPDOWN1;

  CRect rect(10, 10, 20, 30);

  for(int i=0; i<11; i++){

  CUpDown* pupdown = new CUpDown;

  rect.OffsetRect(0, 20);

  pupdown->Create(NULL, WS_CHILD | WS_VISIBLE, rect, this, nID + i);

  m_oaUpdowns.Add(pupdown);

  }

  d.在OnDestroy中,加上

  for(int i=0; i<m_oaUpdowns.GetSize(); i++){

  delete m_oaUpdowns[i];

  }

  e.在OnMouseDownUpdown1中,加上

  CString str;

  str.Format("%d", nID);

  MessageBox(str);

  用来指示是否收到事件

  4.编译一下,可以发现,绝对OK

  下面,我们来看更多灵活的方法:

  观察MFC宏

  BEGIN_EVENTSINK_MAP,END_EVENTSINK_MAP和ON_EVENT,可以发现MFC将控件ID,事件ID和事件处理函数等等信息都放在AFX_EVENTSINKMAP_ENTRY这个结构,每个映射一个这种结构,所有的结构组成一数组放在AFX_EVENTSINKMAP结构中,本来以为动态修改这两个结构信息,不就可以实现动态映射控件事件了,可惜发现MFC定义了

  const AFX_EVENTSINKMAP_ENTRY theClass::_eventsinkEntries[] =

  {

  ...

  }

  可恶的const,只好另想它途了。

  继续观察MFC源码,发现它中间会有一个

  BOOL CCmdTarget::OnEvent(UINT idCtrl, AFX_EVENT* pEvent,

  AFX_CMDHANDLERINFO* pHandlerInfo)

  {

  ...

  }

  函数中有如下代码

  VARIANT var;

  AfxVariantInit(&var);

  DISPPARAMS dispparams;

  dispparams.rgvarg = NULL;

  if (bRange)

  {

  memcpy(&dispparams, pEvent->m_pDispParams, sizeof(DISPPARAMS));

  dispparams.rgvarg = new VARIANT[++dispparams.cArgs];

  memcpy(dispparams.rgvarg, pEvent->m_pDispParams->rgvarg,

  sizeof(VARIANT) * (dispparams.cArgs-1));

  VARIANT* pvarID成都高级办公软件培训班学习http://www.yingtaow.com?&dispparams.rgvarg[dispparams.cArgs-1];

  V_VT(pvarID) = VT_I4;

  V_I4(pvarID) = idCtrl;

  }

  hResult = CallMemberFunc(&pEntry->dispEntry, DISPATCH_METHOD, &var,

  (bRange ? &dispparams : pEvent->m_pDispParams), &uArgError);

  ASSERT(FAILED(hResult) || (V_VT(&var) == VT_BOOL));

  bHandled = V_BOOL(&var);

  if (bRange)

  delete [] dispparams.rgvarg;

  break;

  好了,切入口找到了,就用这个CallMemberFunc了,唯一的问题就是重新组织这个函数所需的参数了。

  开始:

  1.为避免干扰,干脆注释掉OnInitDialog上一例中添加的代码,再加入如下代码:

  UINT nID = 10004;

  CRect rect(10, 10, 20, 30);

  for(int i=0; i<11; i++){

  CUpDown* pupdown = new CUpDown;

  rect.OffsetRect(0, 20);

  pupdown->Create(NULL, WS_CHILD | WS_VISIBLE, rect, this, nID + i);

  m_oaUpdowns.Add(pupdown);

  }

  其实就改了一个nID,之所以改nID,是为了表示这个ID是可以你自己动态确定的,当然这里省事,将这些ID连在了一起,其实分开也是没问题的。

  2.注释掉事件映射

  BEGIN_EVENTSINK_MAP(CTdaxDlg, CDialog)

  //{{AFX_EVENTSINK_MAP(CTdaxDlg)

  //}}AFX_EVENTSINK_MAP

  // ON_EVENT_RANGE(CTdaxDlg, IDC_UPDOWN1, IDC_UPDOWN1+10, -605 /* MouseDown */, OnMouseDownUpdown1, VTS_I4 VTS_I2 VTS_I2 VTS_I4 VTS_I4)

  END_EVENTSINK_MAP()

  3.重载对话框的OnCmdMsg,加入代码如下:

  if(nCode == CN_EVENT && nID >= 10004 && nID <= 10014){

  AFX_EVENT* pEvent = (AFX_EVENT*)pExtra;

  if(pEvent != NULL && pEvent->m_dispid == -605){//根据dispid来判断是否正确的事件

  AFX_DISPMAP_ENTRY e;

  e.lpszName = _T("");

  e.lDispID = -605; //dispID,事件的dispID

  e.vt = VT_BOOL; //返回类型

  e.pfn = (AFX_PMSG)OnMouseDownUpdown1;//事件处理函数

  e.pfnSet = (AFX_PMSG)0;

  e.nPropOffset = 0;

  e.flags = afxDispCustom;

  //下面是参数类型,如果事件处理函数不加控件ID的话,应该改为VTS_I2 VTS_I2 VTS_I4 VTS_I4

  e.lpszParams = VTS_I4 VTS_I2 VTS_I2 VTS_I4 VTS_I4;

  UINT uArgError = (UINT)-1; // no error yet

  VARIANT var;

  AfxVariantInit(&var);

  //如果需要每个控件的ID信息,应该为框架生成的事件处理函数的参数最前面加上1个UINT nID参数,代码如下:

  DISPPARAMS dispparams;

  dispparams.rgvarg = NULL;

  memcpy(&dispparams, pEvent->m_pDispParams, sizeof(DISPPARAMS));

  dispparams.rgvarg = new VARIANT[++dispparams.cArgs];

  memcpy(dispparams.rgvarg, pEvent->m_pDispParams->rgvarg,

  sizeof(VARIANT) * (dispparams.cArgs-1));

  VARIANT* pvarID = &dispparams.rgvarg[dispparams.cArgs-1];

  pvarID->vt = VT_I4;

  pvarID->intVal = nID;

  CallMemberFunc(&e, DISPATCH_METHOD, &var,

  &dispparams, &uArgError);

  delete []dispparams.rgvarg;

  //如果不需要控件的ID信息,代码如下,不过函数就不用加上第1个参数(控件ID)了:

  /* CallMemberFunc(&e, DISPATCH_METHOD, &var,

  (pEvent->m_pDispParams), &uArgError);*/

  }

  return TRUE;

  }

  return CDialog::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);

  4.编译运行,OK了。

  例程为Tdax,对话框程序,使用了Microsoft UpDown Control 6.0控件作为控件,添加了MouseDown事件

  第一种方法挺简单的:

  1.

  缺省的映射定义为

  BEGIN_EVENTSINK_MAP(CTdaxDlg, CDialog)

  //{{AFX_EVENTSINK_MAP(CTdaxDlg)

  ON_EVENT(CTdaxDlg, IDC_UPDOWN1, -605 /* MouseDown */, OnMouseDownUpdown1, VTS_I2 VTS_I2 VTS_I4 VTS_I4)

  //}}AFX_EVENTSINK_MAP

  END_EVENTSINK_MAP()

  现改为

  BEGIN_EVENTSINK_MAP(CTdaxDlg, CDialog)

  //{{AFX_EVENTSINK_MAP(CTdaxDlg)

  //}}AFX_EVENTSINK_MAP

  ON_EVENT_RANGE(CTdaxDlg, IDC_UPDOWN1, IDC_UPDOWN1+10, -605 /* MouseDown */, OnMouseDownUpdown1, VTS_I4 VTS_I2 VTS_I2 VTS_I4 VTS_I4)

  END_EVENTSINK_MAP()

  就是说,可以映射至少11个控件(请注意,这里用了至少,也就是说可以少于11个,甚至于1个也无所谓)

  a.这里建议把ON_EVENT_RANGE从

  //{{AFX_EVENTSINK_MAP(CTdaxDlg)

  ON_EVENT_RANGE(CTdaxDlg, IDC_UPDOWN1, IDC_UPDOWN1+10, -605 /* MouseDown */, OnMouseDownUpdown1, VTS_I4 VTS_I2 VTS_I2 VTS_I4 VTS_I4)

  //}}AFX_EVENTSINK_MAP

  对中拖出来,见上面例子,不拖出来不会对程序产生影响,但可能会影响后续的IDE操作,试试便知。

  b.最后的参数类型中要在前面加上VTS_I4,即从VTS_I2 VTS_I2 VTS_I4 VTS_I4变为VTS_I4 VTS_I2 VTS_I2 VTS_I4 VTS_I4,当然事件处理函数也将做相应调整,下面马上讲到。

  2.

  修改框架建立的事件处理函数

  void OnMouseDownUpdown1(short Button, short Shift, long x, long y);

  改为

  BOOL OnMouseDownUpdown1(UINT nID, short Button, short Shift, long x, long y);

  返回类型为void,应该也无所谓的,不过msdn上说是BOOL,咱就BOOL吧,但UINT nID这个参数是一定要加上的

  3.做一些于本案无关的工作

  a.在对话框编辑器中删掉原来的ID为IDC_UPDOWN1的控件

  b.加一个成员变量CObList m_oaUpdowns;

  c.在OnInitDialog中,加上

  UINT nID = IDC_UPDOWN1;

  CRect rect(10, 10, 20, 30);

  for(int i=0; i<11; i++){

  CUpDown* pupdown = new CUpDown;

  rect.OffsetRect(0, 20);

  pupdown->Create(NULL, WS_CHILD | WS_VISIBLE, rect, this, nID + i);

  m_oaUpdowns.Add(pupdown);

  }

  d.在OnDestroy中,加上

  for(int i=0; i<m_oaUpdowns.GetSize(); i++){

  delete m_oaUpdowns[i];

  }

  e.在OnMouseDownUpdown1中,加上

  CString str;

  str.Format("%d", nID);

  MessageBox(str);

  用来指示是否收到事件

  4.编译一下,可以发现,绝对OK

  下面,我们来看更多灵活的方法:

  观察MFC宏

  BEGIN_EVENTSINK_MAP,END_EVENTSINK_MAP和ON_EVENT,可以发现MFC将控件ID,事件ID和事件处理函数等等信息都放在AFX_EVENTSINKMAP_ENTRY这个结构,每个映射一个这种结构,所有的结构组成一数组放在AFX_EVENTSINKMAP结构中,本来以为动态修改这两个结构信息,不就可以实现动态映射控件事件了,可惜发现MFC定义了

  const AFX_EVENTSINKMAP_ENTRY theClass::_eventsinkEntries[] =

  {

  ...

  }

  可恶的const,只好另想它途了。

  继续观察MFC源码,发现它中间会有一个

  BOOL CCmdTarget::OnEvent(UINT idCtrl, AFX_EVENT* pEvent,

  AFX_CMDHANDLERINFO* pHandlerInfo)

  {

  ...

  }

  函数中有如下代码

  VARIANT var;

  AfxVariantInit(&var);

  DISPPARAMS dispparams;

  dispparams.rgvarg = NULL;

  if (bRange)

  {

  memcpy(&dispparams, pEvent->m_pDispParams, sizeof(DISPPARAMS));

  dispparams.rgvarg = new VARIANT[++dispparams.cArgs];

  memcpy(dispparams.rgvarg, pEvent->m_pDispParams->rgvarg,

  sizeof(VARIANT) * (dispparams.cArgs-1));

  VARIANT* pvarID = &dispparams.rgvarg[dispparams.cArgs-1];

  V_VT(pvarID) = VT_I4;

  V_I4(pvarID) = idCtrl;

  }

  hResult = CallMemberFunc(&pEntry->dispEntry, DISPATCH_METHOD, &var,

  (bRange ? &dispparams : pEvent->m_pDispParams), &uArgError);

  ASSERT(FAILED(hResult) || (V_VT(&var) == VT_BOOL));

  bHandled = V_BOOL(&var);

  if (bRange)

  delete [] dispparams.rgvarg;

  break;

  好了,切入口找到了,就用这个CallMemberFunc了,唯一的问题就是重新组织这个函数所需的参数了。

  开始:

  1.为避免干扰,干脆注释掉OnInitDialog上一例中添加的代码,再加入如下代码:

  UINT nID = 10004;

  CRect rect(10, 10, 20, 30);

  for(int i=0; i<11; i++){

  CUpDown* pupdown = new CUpDown;

  rect.OffsetRect(0, 20);

  pupdown->Create(NULL, WS_CHILD | WS_VISIBLE, rect, this, nID + i);

  m_oaUpdowns.Add(pupdown);

  }

  其实就改了一个nID,之所以改nID,是为了表示这个ID是可以你自己动态确定的,当然这里省事,将这些ID连在了一起,其实分开也是没问题的。

  2.注释掉事件映射

  BEGIN_EVENTSINK_MAP(CTdaxDlg, CDialog)

  //{{AFX_EVENTSINK_MAP(CTdaxDlg)

  //}}AFX_EVENTSINK_MAP

  // ON_EVENT_RANGE(CTdaxDlg, IDC_UPDOWN1, IDC_UPDOWN1+10, -605 /* MouseDown */, OnMouseDownUpdown1, VTS_I4 VTS_I2 VTS_I2 VTS_I4 VTS_I4)

  END_EVENTSINK_MAP()

  3.重载对话框的OnCmdMsg,加入代码如下:

  if(nCode == CN_EVENT && nID >= 10004 && nID <= 10014){

  AFX_EVENT* pEvent = (AFX_EVENT*)pExtra

  4.编译运行,OK了。
热心网友 回答时间:2022-04-26 19:45
猩:QTJG。分开打。

本文如未解决您的问题请添加抖音号:51dongshi(抖音搜索懂视),直接咨询即可。

相关推荐
  • Vue框架下引入ActiveX控件的问题解决

    Vue框架下引入ActiveX控件的问题解决

    Vue框架下引入ActiveX控件的问题解决:最近参与了山东某一公司的呼叫中心系统的开发项目,我负责的模块是在公司已有的前端Vue框架下集成他们的软电话条功能。从开始到结束所遇到的几个问题如下: 1.如何将ActiveX控件引入Vue,并且在页面上成功渲染; 2.如何调用ActiveX已提供的方法; 3.如何监
    查看详情
怎么加载 ActiveX 控件啊? 如何用html或javascript 代码自动运行activeX插件... 打开html页面,提示在此页上的ActiveX控件和本页上... js调用activex时报的错误--对象不支持此属性或方... Html页中如何使用加载OCX控件详解 浏览器无法加载ActiveX控件 在html中使用ActiveX控件,如下图所示: 红框框中... 在IE浏览器下打开一个本地html页面,由于html页中... 如何html5导入我自己编写的ActiveX插件 html怎么调用ActiveX控件的方法? 怎样在HTML中添加ActiveX控件? html 怎么调用activex控件方法 如何在HTML页面中嵌入ACTIVE控件 请大神推荐一款好用、实用的压缩软件 一瞬间把几十... 我想把一些大的文件夹压缩,我用WINRAR压缩好象很... 压缩文件通常使用的软件是什么 目前最好的压缩软件是什么 什么压缩软件压缩比较大的文件夹效果好? 有没有比较好的用来压缩文件的软件啊 常用的文件压缩工具软件 如何提示浏览器加载activex控件 浏览器怎么加载activex控件 IE浏览器ActiveX控件加载失败如何解决? ActiveX控件在网页中无法显示为什么 请单击,以在此网页上运行activex控件怎么办 html中用Activex读取文件,每次都会弹出控件,请问... 西安落户政策2021最新 西安户口落户的新政策 西安人才引进落户政策2021 西安落户政策2020最新 2020西安落户政策是怎样的? 西安落户最新政策? 迁户口到西安需要什么条件? 西安本科户口转入三年才能买房吗 西安落户政策 户口迁移到西安需要什么条件? 西安落户有什么条件呢? 在西安落户的条件是什么? 户籍转入西安的规定和要求? 应届生大学生西安落户政策和办理流程是什么?
Top