我用 ATL 创建了一个 ActiveX 控件, 实现了IActiveScriptSite 接口以及Connection Point。
脚本执行没有问题,能调我定义的接口方法,但是脚本不能响应事件通知。
但如果我编写一个HTML,在HTML 创建该ActiveX,事件响应又是正常的。
有人知道是什么地方出问题了吗?详细信息:
我在 ActiveX 中创建了 IActiveScript 对象 spAS
spAS->AddNamedItem( "Test", SCRIPTITEM_ISSOURCE  | SCRIPTITEM_ISVISIBLE  );
该 ActiveX 会定时触发一个OnTimer事件
我的VBScript脚本是这样编写的:
Sub Test_OnTimer( nID ) 弹出一个对话框End Sub 但这个对话框始终弹不出来

解决方案 »

  1.   

    这是我的IActiveScriptSite接口实现源码// MyScript.cpp : Implementation of CMyScript
    #include "stdafx.h"
    #include "MyScript.h"
    #include "psapi.h"
    #pragma comment(lib, "Psapi.lib")
    // CMyScript
    // IActiveScriptSite
    STDMETHODIMP CMyScript::GetLCID(/*[out]*/ LCID *plcid)
    {
    return E_NOTIMPL;
    }STDMETHODIMP CMyScript::GetItemInfo(/*[in]*/ LPCOLESTR pstrName,
       /*[in]*/ DWORD dwReturnMask,
       /*[out]*/ IUnknown **ppunkItem,
       /*[out]*/ ITypeInfo **ppTypeInfo)
    {
    if(ppTypeInfo)
    {
    *ppTypeInfo = NULL; if(dwReturnMask & SCRIPTINFO_ITYPEINFO)
    {
    CComPtr< ITypeLib > sptLib;
    ::LoadTypeLib( L"MyScriptProject.tlb", &sptLib ); //装载自身的类型库
    if( sptLib )
    {
    sptLib->GetTypeInfo( 0, ppTypeInfo );
    }
    }
    } if(ppunkItem)
    {
    *ppunkItem = NULL; if(dwReturnMask & SCRIPTINFO_IUNKNOWN)
    {
    if ( m_strObjName.Compare(pstrName ) == 0 )
    {
    ControlQueryInterface( IID_IUnknown, (LPVOID *)ppunkItem );
    }
    }
    } return S_OK;
    }STDMETHODIMP CMyScript::GetDocVersionString(/*[out]*/ BSTR *pbstrVersionString)
    {
    return E_NOTIMPL;
    }STDMETHODIMP CMyScript::OnScriptTerminate(/*[in]*/ const VARIANT *pvarResult, /*[in]*/ const EXCEPINFO *pexcepinfo)
    {
    return S_OK;
    }STDMETHODIMP CMyScript::OnStateChange(/*[in]*/ SCRIPTSTATE ssScriptState)
    {
    return S_OK;
    }STDMETHODIMP CMyScript::OnScriptError(/*[in]*/ IActiveScriptError *pase)
    {
    CComBSTR strErr;
    CComBSTR strMsg;
    HRESULT hr = pase->GetSourceLineText( &strErr );
    if( FAILED(hr) || !strErr.Length() )
    {
    strMsg = L"未知错误";
    }
    else
    {
    strMsg = L"语法错误: ";
    strMsg.AppendBSTR( strErr );
    }// Fire_ScriptErr( msg ); return S_OK;
    }STDMETHODIMP CMyScript::OnEnterScript(void)
    {
    return S_OK;
    }STDMETHODIMP CMyScript::OnLeaveScript(void)
    {
    return S_OK;
    }
    STDMETHODIMP CMyScript::ExecuteScript(BSTR bstrScript, VARIANT_BOOL* bSuccess)
    {
    // TODO: Add your implementation code here HRESULT hr = S_FALSE;
    *bSuccess = VARIANT_FALSE; try
    {
    if ( FAILED( CloseScript() ) )
    {
    throw ( L"CloseScript failed!" );
    }

    m_spAS.CoCreateInstance( L"JavaScript"); if ( m_spAS == NULL )
    {
    throw (L"Can not create instance of IActiveScript");
    }
    //
    m_spAS->SetScriptSite( this );

    if ( FAILED( m_spAS->AddNamedItem( m_strObjName, SCRIPTITEM_ISSOURCE | SCRIPTITEM_ISVISIBLE ) ) )
    {
    throw ( L"IActiveScript AddNamedItem failed!" );
    } CComQIPtr<IActiveScriptParse> spASP(m_spAS);
    if ( FAILED( spASP->InitNew() ) )
    {
    throw( L"IActiveScriptParse InitNew failed!" );
    } EXCEPINFO ei;
    if ( FAILED( spASP->ParseScriptText( bstrScript, m_strObjName, NULL, NULL, 0, 0, 0, NULL, &ei ) ) )
    {
    throw ( L"IActiveScriptParse ParseScriptText failed!" );
    } m_spAS->SetScriptState( SCRIPTSTATE_CONNECTED);
    *bSuccess = VARIANT_TRUE;
    hr = S_OK; }
    catch( LPCWSTR lpszDesc)
    {
    CString strDesc = lpszDesc;
    *bSuccess = VARIANT_FALSE;
    hr = S_FALSE;; }
    catch(...)
    {
    *bSuccess = VARIANT_FALSE;
    hr = S_FALSE; } return hr;
    }LRESULT CMyScript::OnTimer(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
    {
    // TODO: Add your message handler code here and/or call default return 0;
    }STDMETHODIMP CMyScript::CloseScript(void)
    {
    // TODO: Add your implementation code here if ( m_spAS == NULL )
    {

    }
    else
    {
    m_spAS->SetScriptState( SCRIPTSTATE_DISCONNECTED );
    m_spAS->Close();
    m_spAS.Release();
    }
    return S_OK;
    }STDMETHODIMP CMyScript::MyShowMsg(BSTR bstrText, BSTR bstrTitle, USHORT uType, LONG* bRet)
    {
    // TODO: Add your implementation code here
    *bRet = ::MessageBox( NULL, CString(bstrText), CString(bstrTitle), MB_OK ); return S_OK;
    }STDMETHODIMP CMyScript::MyProcessExist(BSTR bstrExepath, VARIANT_BOOL* bExist)
    {
    // TODO: Add your implementation code here * bExist = FALSE; DWORD aProcesses[1024], cbNeeded, cProcesses;
    unsigned int i = 0; if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
    {
    return S_FALSE;
    } // Calculate how many process identifiers were returned. cProcesses = cbNeeded / sizeof(DWORD); // Print the name of the modules for each process. for ( i = 0; i < cProcesses; i++ )
    {
    HANDLE hProcess = NULL; unsigned int k = 0; hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, aProcesses[i] );
    if ( NULL == hProcess)
    {
    continue;
    }
    WCHAR wBuffer[1024];
    ::ZeroMemory( wBuffer, sizeof(wBuffer) );
    int nCount = ::GetModuleFileNameEx ( hProcess, NULL, wBuffer, sizeof(wBuffer) - 2 );
    CloseHandle( hProcess );
    if ( nCount > 0 )
    {
    CString strPath = bstrExepath;
    if ( strPath.CompareNoCase(wBuffer) == 0 )
    {
    *bExist = TRUE;
    break;
    } } }
    return S_OK;
    }STDMETHODIMP CMyScript::MyCreateProcess(BSTR bstrExePath, VARIANT_BOOL* bSuccess)
    {
    // TODO: Add your implementation code here
    CString strPath = bstrExePath;
    *bSuccess = VARIANT_FALSE; STARTUPINFO si;
    PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );
    if( !CreateProcess( strPath,   // No module name (use command line)
    NULL,        // Command line
    NULL,           // Process handle not inheritable
    NULL,           // Thread handle not inheritable
    FALSE,          // Set handle inheritance to FALSE
    0,              // No creation flags
    NULL,           // Use parent's environment block
    NULL,           // Use parent's starting directory 
    &si,            // Pointer to STARTUPINFO structure
    &pi )           // Pointer to PROCESS_INFORMATION structure

    {
    return S_FALSE;
    } // Close process and thread handles. 
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );
    *bSuccess = VARIANT_TRUE;
    return S_OK;
    }
      

  2.   

    IActiveScript::SetScriptState的调用在哪里?
    重写OnStateChange,确认你的脚本引擎进入SCRIPTSTATE_CONNECTED状态。
    建议去microsoft.public.scripting.hosting新闻组讨论这个问题。
      

  3.   

    m_spAS.CoCreateInstance( L"JavaScript");老兄,你创建的是JAVASCRIPT引擎,怎么让它执行VBS代码呢?用VBScript试试
      

  4.   

    STDMETHODIMP CMyScript::GetItemInfo(/*[in]*/ LPCOLESTR pstrName,
                                   /*[in]*/ DWORD dwReturnMask,
                                   /*[out]*/ IUnknown **ppunkItem,
                                   /*[out]*/ ITypeInfo **ppTypeInfo)
    {
        if(ppTypeInfo)
        {    
            *ppTypeInfo = NULL;        if(dwReturnMask & SCRIPTINFO_ITYPEINFO)
            {
                CComPtr< ITypeLib > sptLib;
                ::LoadTypeLib( L"MyScriptProject.tlb", &sptLib );    //装载自身的类型库
                if( sptLib )
                {
                    sptLib->GetTypeInfo( 0, ppTypeInfo );
                }
            }
        }    if(ppunkItem)
        {    
            *ppunkItem = NULL;        if(dwReturnMask & SCRIPTINFO_IUNKNOWN)
            {
                if ( m_strObjName.Compare(pstrName ) == 0 )
                {
                    ControlQueryInterface( IID_IUnknown, (LPVOID *)ppunkItem );
                }
            }
        }    return S_OK;
    }
    可能是类型库信息不对