ActiveX多线程的问题,看了蒋晟老大的文章还是没明白,请各位高手指点,分数不够另开一贴再散!!!!!!!!!!!!!

phinecos 2008-12-26 05:55:03
先描述下功能:就是一个嵌入web页面的ActiveX控件,里面开启一个线程负责对本地的一个目录进行扫描,发现里面有文件后就通知web页面的javascript函数来响应
我的代码;
控件头文件:
#include <MsHTML.h>
class CMyActiveXCtrl : public COleControl
{
virtual void OnSetClientSite();
virtual void OnClose(DWORD dwSaveOption);
public:
CMainDialog m_MainDialog;
IWebBrowser2* pWebBrowser;
IHTMLDocument2* pHTMLDocument;
HANDLE threadHandle;//线程句柄
public:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
void OnReadSuccesful();
void OnReadFailed();
bool GetJScript(CComPtr<IDispatch>& spDisp);
bool GetJScripts(CComPtr<IHTMLElementCollection>& spColl);
bool CallJScript(const CString strFunc,CComVariant* pVarResult = NULL);
bool CallJScript(const CString strFunc,const CString strArg1,CComVariant* pVarResult = NULL);
bool CallJScript(const CString strFunc,const CString strArg1,const CString strArg2,CComVariant* pVarResult = NULL);
bool CallJScript(const CString strFunc,const CString strArg1,const CString strArg2,const CString strArg3,CComVariant* pVarResult = NULL);
bool CallJScript(const CString strFunc,const CStringArray& paramArray,CComVariant* pVarResult = NULL);
protected:
void FireParameterLoaded(void)
{
FireEvent(eventidParameterLoaded, EVENT_PARAM(VTS_NONE));
}
};

实现文件:

#define CHECK_POINTER(p)\
ATLASSERT(p != NULL);\
if(p == NULL)\
{\
return false;\
}
#define COMRELEASE(p)\
if(p != NULL)\
{\
p->Release();\
p=NULL;\
}

//线程代码
LONG ThreadProc(LPVOID pParam)
{
while (true)
{
CMyActiveXCtrl *pCtrl = (CMyActiveXCtrl*)pParam;
pCtrl->OnReadSuccesful();//就是简单的回调主线程中的方法去call页面的js函数
Sleep(3000); //simulate lengthy processing
}
return TRUE;
}
void CMyActiveXCtrl::OnDraw(
CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
if (!pdc)return;
DoSuperclassPaint(pdc, rcBounds);
m_MainDialog.MoveWindow(rcBounds, TRUE);
CBrush brBackGnd(TranslateColor(AmbientBackColor()));
pdc->FillRect(rcBounds, &brBackGnd);
}
void CMyActiveXCtrl::OnClose(DWORD dwSaveOption)
{
COMRELEASE(pWebBrowser);
COMRELEASE(pHTMLDocument);
COleControl::OnClose(dwSaveOption);
}
void CMyActiveXCtrl::OnSetClientSite()
{
HRESULT hr = S_OK;
IServiceProvider *isp, *isp2 = NULL;
if (!m_pClientSite)
{
COMRELEASE(pWebBrowser);
}
else
{
hr = m_pClientSite->QueryInterface(IID_IServiceProvider, reinterpret_cast<void **>(&isp));
if (FAILED(hr))
{
hr = S_OK;
goto cleanup;
}
hr = isp->QueryService(SID_STopLevelBrowser, IID_IServiceProvider, reinterpret_cast<void **>(&isp2));
if (FAILED(hr))
{
hr = S_OK;
goto cleanup;
}
hr = isp2->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, reinterpret_cast<void **>(&pWebBrowser));
if (FAILED(hr))
{
hr = S_OK;
goto cleanup;
}
::CoMarshalInterThreadInterfaceInStream(IID_IWebBrowser2,pWebBrowser,&pStream);
hr = pWebBrowser->get_Document((IDispatch**)&pHTMLDocument);
if(FAILED(hr))
{
hr = S_OK;
goto cleanup;
}
cleanup:
// Free resources.
COMRELEASE(isp);
COMRELEASE(isp2);
}
}

int CMyActiveXCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (COleControl::OnCreate(lpCreateStruct) == -1)
return -1;

// TODO: Add your specialized creation code here
m_MainDialog.Create(IDD_MAINDIALOG, this);
//创建线程
DWORD dwID;
threadHandle = CreateThread(NULL,NULL,
(LPTHREAD_START_ROUTINE)ThreadProc,
(LPVOID)this, NULL, &dwID);
return 0;
}
/////////////////////
//回调函数
/////////////////////////
void CMyActiveXCtrl::OnReadSuccesful()
{//读数据成功
FireParameterLoaded();//为了验证确实回调了,故意加个fire事件在这里
CString strOnLoaded("OnLoaded");
this->CallJScript(strOnLoaded);
}

void CMyActiveXCtrl::OnReadFailed()
{//读卡失败

}

bool CMyActiveXCtrl::GetJScript(CComPtr<IDispatch>& spDisp)
{
CHECK_POINTER(pHTMLDocument);
HRESULT hr = pHTMLDocument->get_Script(&spDisp);
ATLASSERT(SUCCEEDED(hr));
return SUCCEEDED(hr);
}

bool CMyActiveXCtrl::GetJScripts(CComPtr<IHTMLElementCollection>& spColl)
{
CHECK_POINTER(pHTMLDocument);
HRESULT hr = pHTMLDocument->get_scripts(&spColl);
ATLASSERT(SUCCEEDED(hr));
return SUCCEEDED(hr);
}

bool CMyActiveXCtrl::CallJScript(const CString strFunc,CComVariant* pVarResult)
{
CStringArray paramArray;
return CallJScript(strFunc,paramArray,pVarResult);
}

bool CMyActiveXCtrl::CallJScript(const CString strFunc,const CString strArg1,CComVariant* pVarResult)
{
CStringArray paramArray;
paramArray.Add(strArg1);
return CallJScript(strFunc,paramArray,pVarResult);
}

bool CMyActiveXCtrl::CallJScript(const CString strFunc,const CString strArg1,const CString strArg2,CComVariant* pVarResult)
{
CStringArray paramArray;
paramArray.Add(strArg1);
paramArray.Add(strArg2);
return CallJScript(strFunc,paramArray,pVarResult);
}

bool CMyActiveXCtrl::CallJScript(const CString strFunc,const CString strArg1,const CString strArg2,const CString strArg3,CComVariant* pVarResult)
{
CStringArray paramArray;
paramArray.Add(strArg1);
paramArray.Add(strArg2);
paramArray.Add(strArg3);
return CallJScript(strFunc,paramArray,pVarResult);
}

bool CMyActiveXCtrl::CallJScript(const CString strFunc, const CStringArray& paramArray,CComVariant* pVarResult)
{
CComPtr<IDispatch> spScript;
if(!GetJScript(spScript))
{
//ShowError("Cannot GetScript");
return false;
}
CComBSTR bstrMember(strFunc);
DISPID dispid = NULL;
HRESULT hr = spScript->GetIDsOfNames(IID_NULL,&bstrMember,1,
LOCALE_SYSTEM_DEFAULT,&dispid);
if(FAILED(hr))
{
//ShowError(GetSystemErrorMessage(hr));
return false;
}

const int arraySize = paramArray.GetSize();

DISPPARAMS dispparams;
memset(&dispparams, 0, sizeof dispparams);
dispparams.cArgs = arraySize;
dispparams.rgvarg = new VARIANT[dispparams.cArgs];

for( int i = 0; i < arraySize; i++)
{
CComBSTR bstr = paramArray.GetAt(arraySize - 1 - i); // back reading
bstr.CopyTo(&dispparams.rgvarg[i].bstrVal);
dispparams.rgvarg[i].vt = VT_BSTR;
}
dispparams.cNamedArgs = 0;

EXCEPINFO excepInfo;
memset(&excepInfo, 0, sizeof excepInfo);
CComVariant vaResult;
UINT nArgErr = (UINT)-1; // initialize to invalid arg

hr = spScript->Invoke(dispid,IID_NULL,0,
DISPATCH_METHOD,&dispparams,&vaResult,&excepInfo,&nArgErr);

delete [] dispparams.rgvarg;
if(FAILED(hr))
{
//ShowError(GetSystemErrorMessage(hr));
return false;
}

if(pVarResult)
{
*pVarResult = vaResult;
}
return true;
}
...全文
1361 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
未来的神话 2012-03-21
  • 打赏
  • 举报
回复
写的确实不错额,顶,但是创建隐藏窗口怎么创建呢?
吹雪 2008-12-31
  • 打赏
  • 举报
回复
总结不错,感谢分享。
wshcdr 2008-12-29
  • 打赏
  • 举报
回复
MK
phinecos 2008-12-29
  • 打赏
  • 举报
回复
我总结了这两个问题及其解决方案,请参考我这两篇blog
http://www.cnblogs.com/phinecos/archive/2008/12/29/1364675.html
http://www.cnblogs.com/phinecos/archive/2008/12/29/1364791.html
phinecos 2008-12-29
  • 打赏
  • 举报
回复
非常感谢jameshooo(胡柏华),帮我解决了这两个问题,结贴给分,
success000 2008-12-29
  • 打赏
  • 举报
回复
不懂,帮顶
蒋晟 2008-12-29
  • 打赏
  • 举报
回复
How to start a second thread in an MFC-based ActiveX control to fire events in Visual C++
http://support.microsoft.com/?scid=kb;en-us;157437&x=9&y=9
phinecos 2008-12-29
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 jiangsheng 的回复:]
How to start a second thread in an MFC-based ActiveX control to fire events in Visual C++
http://support.microsoft.com/?scid=kb;en-us;157437&x=9&y=9
[/Quote]

第一个问题已经解决了,现在就是如何动态调整控件大小的问题了
jameshooo 2008-12-27
  • 打赏
  • 举报
回复
另,param指定的参数只在控件初始化时发挥作用。
jameshooo 2008-12-27
  • 打赏
  • 举报
回复
无论是谁做的控件都一样,容器机制是完全相同的。控件肯定保存着IOleClientSite,这是容器传给控件保存的,从它查询出IOleInPlaceSite后再调用。
phinecos 2008-12-27
  • 打赏
  • 举报
回复
或者请指定另一种思路如何做,web页面里通过param指定控件大小,设置控件为指定的大小,我的控件是MFC ActiveX控件,代码应该是怎么样的呢?
phinecos 2008-12-27
  • 打赏
  • 举报
回复
或者请指定另一种思路如何做,web页面里通过param指定控件大小,点击按钮后,设置控件为指定的大小,我的控件是MFC ActiveX控件,代码应该是怎么样的呢?
phinecos 2008-12-27
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 jameshooo 的回复:]
改变控件大小要通知容器,由容器再反过来通知控件改变大小,不然没有任何效果。调用IOleInPlaceSite::OnPosRectChange即可。
[/Quote]
我这个控件不是ATL写的,是MFC ActiveX控件,怎么用你说的这个方法呢?是不是有其他的?
jameshooo 2008-12-27
  • 打赏
  • 举报
回复
改变控件大小要通知容器,由容器再反过来通知控件改变大小,不然没有任何效果。调用IOleInPlaceSite::OnPosRectChange即可。
phinecos 2008-12-27
  • 打赏
  • 举报
回复
谢谢楼上的,发消息是可以的,本来我不想这样做的,总觉得postmessage不好的,不过暂时就先这样吧,另外再问一个问题,点一下web页面上一个按钮,我要让ActiveX控件的大小变化为原来的1/4,就是想来控制ActiveX控件的大小,怎么弄呢?触发一个WM_SIZE消息让里面的控件去响应吗?那OnSiz()里面应该怎么写呢?多谢了
myy 2008-12-27
  • 打赏
  • 举报
回复
同意楼上,建隐藏窗口是最明智的做法。
jameshooo 2008-12-27
  • 打赏
  • 举报
回复
事件必须在控件创建时的线程中触发,在其他线程中触发需要理解相当多的原理和技巧。
建议控件在被创建时创建一个隐藏窗口,工作线程向该窗口发送一个消息,由窗口过程来触发事件。
phinecos 2008-12-26
  • 打赏
  • 举报
回复
我建的是MFC ActiveX Control项目,不是ATL
phinecos 2008-12-26
  • 打赏
  • 举报
回复
现在的问题是在ActiveX测试容器中是看到线程跑起来了,触发了ParameterLoaded事件,但web页面实际上没有任何反应,但web页面自己直接去调用OnReadSuccesful的话,是可以的,也就是说callJscript这个是对的,可线程的问题到底在呢?怎么能在子线程里去调用到web页面的脚本函数呢?或者说在子线程中触发事件让web页面能响应,
function OnLoaded()
{//用来供ActiveX回调的函数,理当在线程中被回调
alert("loaded");
}
</SCRIPT>

<SCRIPT FOR=MyActiveX1 EVENT=ParameterLoaded>
alert("loaded");
</SCRIPT>
拜请各位高手指点!!!!

3,245

社区成员

发帖
与我相关
我的任务
社区描述
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
社区管理员
  • ATL/ActiveX/COM社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧