0
每個人。 我在ATL的ActiveX編程中遇到了一些麻煩。我嘗試製作一個可以從http服務器異步下載文件到本地文件夾的ActiveX,下載後它將調用JavaScript回調函數。 我的解決方案:運行一個線程M來監視下載線程D,當D完成工作時,M將自己終端並調用IDispatch接口來調用javascript函數。 * ** * ** * ** * ** * ** *有我的代碼:* ** * ** * ** * ** * ** *麻煩在ActiveX多線程調用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,
¶ms, 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;
}
** * ** * ** * ** * ** * *代號結束* ** * ** * ** * ** * ** * OK,上面是我的源代碼的一部分,如果我在子線程中調用onDone方法, 我會得到OLE ERROR(-2147418113(8000FFFF)災難性故障)。 我錯過了什麼嗎?請幫我弄明白。
他擊敗了我... COM通常在一個線程上工作。還有其他一些方法來設置其他線程,以便您可以在它們上使用COM,然後將線程中的對象編組在一起,但這裏提到的方法要簡單得多(並且我實際上不知道如何去做另一個線程,只是知道它可以完成)。 – taxilian
謝謝,江。它是不可見的ActiveX對象,它會靜靜地與硬件通信,所以我創建了一個線程來等待信號,如果有信號它會調用腳本回調函數,這是我想要的。如果ActiveX主線程等待讀線程完成,它會阻塞瀏覽器響應,我想也許IWebBrowser2(獲取腳本調用接口)或COM連接點(COM事件)將工作,我會嘗試它。 – code0tt
我找到了一個話題:作者做了一個例子在同一個線程中調用javascript,他說:CoMarshalInterface和CoUnmarshalInterface可以找出多線程腳本回調,這是否與Taxilian的想法一樣? – code0tt