ActiveX 多线程调用 javascript 回调例程中的问题

Posted

技术标签:

【中文标题】ActiveX 多线程调用 javascript 回调例程中的问题【英文标题】:Trouble in ActiveX multi-thread invoke javascript callback routine 【发布时间】:2011-12-29 09:04:46 【问题描述】:

每个人。 我在使用 ATL 进行 ActiveX 编程时遇到了一些麻烦。我尝试制作一个activex,它可以将文件从http服务器异步下载到本地文件夹,下载后它将调用javascript回调函数。 我的解决方案:运行一个线程M来监控下载线程D,当D完成工作时,M将自己终端并调用IDispatch接口来调用javascript函数。 **************** 有我的密码:****************

/* javascript code */
funciton download() 
   var xfm = new ActiveXObject("XFileMngr.FileManager.1");
   xfm.download(
    'http://somedomain/somefile','localdev:\\folder\localfile',function(msg)alert(msg););


/* C++ code */

// main routine
STDMETHODIMP CFileManager::download(BSTR url, BSTR local, VARIANT scriptCallback)

    CString csURL(url);
    CString csLocal(local);

    CAsyncDownload download;
    download.Download(this, csURL, csLocal, scriptCallback);

    return S_OK;


// parts of CAsyncDownload.h
typedef struct tagThreadData 
    CAsyncDownload* pThis;
 THREAD_DATA, *LPTHREAD_DATA;

class CAsyncDownload :
    public IBindStatusCallback

private:
    LPUNKNOWN pcaller;
    CString csRemoteFile;
    CString csLocalFile;
    CComPtr<IDispatch> spCallback;
public:
    void onDone(HRESULT hr);

    HRESULT Download(LPUNKNOWN caller, CString& csRemote, CString& csLocal, VARIANT callback);

    static DWORD __stdcall ThreadProc(void* param);
;
// parts of CAsyncDownload.cpp
void CAsyncDownload::onDone(HRESULT hr) 
    if(spCallback) 
        TRACE(TEXT("invoke callback function\n"));
        CComVariant vParams[1];
        vParams[0] = "callback is working!";

        DISPPARAMS params =  vParams, NULL, 1, 0 ;

        HRESULT hr = spCallback->Invoke(0,
            IID_NULL,
            LOCALE_USER_DEFAULT,
            DISPATCH_METHOD,
            &params, NULL, NULL, NULL);

        if(FAILED(hr)) 
            CString csBuffer;
            csBuffer.Format(TEXT("invoke failed, result value: %d \n"),hr);
            TRACE(csBuffer);
        else 
            TRACE(TEXT("invoke was successful\n"));
        
    


HRESULT CAsyncDownload::Download(LPUNKNOWN caller, CString& csRemote, CString& csLocal, VARIANT callback) 
    CoInitializeEx(NULL, COINIT_MULTITHREADED);

    csRemoteFile = csRemote;
    csLocalFile = csLocal;
    pcaller = caller;

    switch(callback.vt)
        case VT_DISPATCH:
        case VT_VARIANT:
            spCallback = callback.pdispVal;
        
        break;
        default:
            spCallback = NULL;
        
    

    LPTHREAD_DATA pData = new THREAD_DATA;
    pData->pThis = this;

    // create monitor thread M
    HANDLE hThread = CreateThread(NULL, 0, ThreadProc, (void*)(pData), 0, NULL);

    if(!hThread) 
        delete pData;
        return HRESULT_FROM_WIN32(GetLastError());
    

    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(hThread);

    CoUninitialize();

    return S_OK;



DWORD __stdcall CAsyncDownload::ThreadProc(void* param) 
    LPTHREAD_DATA pData = (LPTHREAD_DATA)param;

    // here, we will create http download thread D
    // when download job is finish, call onDone method;

    pData->pThis->onDone(S_OK);

    delete pData;

    return 0;

**************** 代码完成 **************** 好的,上面是我的部分源代码,如果我在子线程中调用onDone方法, 我将收到 OLE ERROR(-2147418113 (8000FFFF) 灾难性故障。)。 我错过了什么?请帮我弄清楚。

【问题讨论】:

【参考方案1】:

IE 的 JavaScript 引擎是单线程的,ATL 的事件引发代码也是如此。让子线程将消息发布到创建 ActiveX 的线程(例如,如果有,则发送到 ActiceX 窗口的句柄),然后引发事件。

【讨论】:

他打败了我... COM 通常在一个线程上工作。还有其他方法可以设置其他线程,以便您可以在它们上使用 COM,然后跨线程编组对象,但是这里提到的方法要简单得多(我实际上不知道如何做其他的,我只知道可以做到)。 谢谢,江。它是不可见的 ActiveX 对象,它会悄悄地与硬件通信,所以我创建了一个线程等待信号,如果有信号它会调用脚本回调函数,这就是我想要的。如果 ActiveX 主线程等待读取线程完成,它会阻塞浏览器响应,我想也许 IWebBrowser2(获取脚本调用接口)或 COM 连接点(COM 事件)会起作用,我会试试看。 我找到了一个话题:作者做了一个例子,在同一个线程中调用javascript,他说:CoMarshalInterface和CoUnmarshalInterface可以找出多线程脚本回调,和Taxilian的想法一样吗? 好的,伙计们。我使用 API CoMarshalInterface 和 CoUnmarshalInterface 解决了我的问题:创建 IStream 对象作为线程参数并在工作线程中检索 COM 接口并调用方法。它工作正常。

以上是关于ActiveX 多线程调用 javascript 回调例程中的问题的主要内容,如果未能解决你的问题,请参考以下文章

类中调用界面ActiveX控件报错当前线程不在单线程单元中因此无法实例化 ActiveX 控件的解决办法

Delphi调试activex

当activex与flash player在同一个页面时不能调用activex方法

C#调用Activex中串口电子秤的数据,并将电子秤的数据显示到前端页面

【急】js中调用ActiveX控件中的函数?

使用 Javascript ActiveX 对象触发 C# dll