如何修复CoCreateInstance读取访问冲突?

时间:2018-12-27 09:26:17

标签: javascript c++ mfc

我使用了C ++ MFC activex脚本来调用javascript函数, 可以正常编译,但是使用init函数运行到public JSONArray getMergeJson(ArrayList<JSONArray> abc){ JSONArray result=null; JSONObject obj= new JSONObject(); obj.put("key",result); for(JSONArray tmp:abc){ for(int i=0;i<tmp.length();i++){ obj.append("key", tmp.getJSONObject(i)); ; } } return obj.getJSONArray("key"); } ,从而导致读取访问冲突(此0x4)。 如何解决这个问题?

下面是我的代码:

// BasicScriptHost.cpp

CoCreateInstance

// BasicScriptHost.h

#include "stdafx.h"
#include "DTCfg.h"
#include "BasicScriptHost.h"
#include <atlbase.h>
#include <string>
#include <atlfile.h>
using namespace std;

HRESULT BasicScriptHost::Init() {
    CLSID clsJS;
    HRESULT hr = ::CLSIDFromProgID(L"javascript", &clsJS);
    if (FAILED(hr))
    {
        return SETERROR(hr);
    }

    hr = ::CoCreateInstance(clsJS,NULL, CLSCTX_INPROC_SERVER, 
IID_IActiveScript, (void**)&m_pEngine);//Error  read access violation 
    if (FAILED(hr))
    {
        return SETERROR(hr);
    }

hr = m_pEngine.QueryInterface(&m_pEngineParse);
if (FAILED(hr))
{
    return SETERROR(hr);
}

hr = m_pEngineParse->InitNew();
if (FAILED(hr))
{
    return SETERROR(hr);
}

hr = m_pEngine->SetScriptSite(this);
if (FAILED(hr))
{
    return SETERROR(hr);
}

hr = m_pEngine->SetScriptState(SCRIPTSTATE_STARTED);
if (FAILED(hr))
{
    return SETERROR(hr);
}

hr = m_pEngine->SetScriptState(SCRIPTSTATE_CONNECTED);
if (FAILED(hr))
{
    return SETERROR(hr);
}

return S_OK;
}

HRESULT BasicScriptHost::Close()
{
    HRESULT hr = m_pEngine->SetScriptState(SCRIPTSTATE_DISCONNECTED);
    if (FAILED(hr))
    {
        return SETERROR(hr);
    }

    hr = m_pEngine->SetScriptState(SCRIPTSTATE_CLOSED);
    if (FAILED(hr))
    {
        return SETERROR(hr);
    }
    return S_OK;
}

HRESULT BasicScriptHost::AddScriptFile(string const& file)
{
    CAtlFile atlfile;
    HRESULT hr = atlfile.Create((LPCTSTR)file.c_str(), GENERIC_READ, 0, 
OPEN_EXISTING);
    if (FAILED(hr))
    {
        return SETERROR(hr);
    }

    ULONGLONG len;
    hr = atlfile.GetSize(len);
    if (FAILED(hr))
    {
        return SETERROR(hr);
    }

    LARGE_INTEGER li;
    li.QuadPart = len;
    CAutoVectorPtr<char> szData(new char[li.LowPart + 1]);
    if (!szData)
    {
        return SETERROR(E_OUTOFMEMORY);
    }

    DWORD dwBytesRead;
    hr = atlfile.Read(szData, li.LowPart, dwBytesRead);
    if (FAILED(hr))
    {
        return SETERROR(hr);
    }

    szData[dwBytesRead] = '\0';
    atlfile.Close();    USES_CONVERSION;
    wstring script = A2W(szData);    EXCEPINFO sEx;
    hr = m_pEngineParse->ParseScriptText(script.c_str(), NULL, NULL, 
NULL,
        1, 0, SCRIPTTEXT_ISVISIBLE | SCRIPTTEXT_ISPERSISTENT, NULL, 
&sEx);
    if (FAILED(hr))
    {
        return SETERROR(hr);
    }
    return S_OK;
 }

HRESULT BasicScriptHost::GetScriptDispatch(IDispatch** retval)
{
    HRESULT hr = m_pEngine->GetScriptDispatch(NULL, retval);
    if (FAILED(hr))
    {
        return SETERROR(hr);
    }
    return S_OK;
}

//调用功能部分

#define SETERROR(hr) hr
#include <string>
#include <vector>
#include <activscp.h>
#include <comdef.h>
#include <atlbase.h>

class BasicScriptHost : public IActiveScriptSite
{

    // IActiveScriptSite
    STDMETHOD(GetItemInfo)(LPCOLESTR /*pstrName*/, DWORD 
/*dwReturnMask*/,
        IUnknown **ppiunkItem, ITypeInfo **ppti)
    {
        *ppiunkItem = NULL;
        *ppti = NULL;
        return S_OK;
    }

    STDMETHOD(OnScriptError)(IActiveScriptError *pscripterror)
    {
        return S_OK;
     }

    STDMETHOD(GetLCID)(LCID *plcid)
    {
        *plcid = NULL;
        return E_NOTIMPL;
    }

    STDMETHOD(GetDocVersionString)(BSTR* pbstrVersion)
    {
        *pbstrVersion = NULL;
        return E_NOTIMPL;
    }

    STDMETHOD(OnScriptTerminate)(const VARIANT * /*pvr*/, const EXCEPINFO 
* /*pei*/)
    {
        return S_OK;
    }

    STDMETHOD(OnStateChange)(SCRIPTSTATE /*ssScriptState*/)
    {
        return S_OK;
    }

    STDMETHOD(OnEnterScript)()
    {
        return S_OK;
    }

    STDMETHOD(OnLeaveScript)()
    {
        return S_OK;
    }

public:
    HRESULT Init();

    HRESULT Close();

    HRESULT AddScriptFile(std::string const& file);

    HRESULT GetScriptDispatch(IDispatch** retval);

private:
    // Script Engine Wrapper Interfaces
    CComPtr<IActiveScript> m_pEngine;
    CComPtr<IActiveScriptParse> m_pEngineParse;
};

我认为这可能是因为::CoInitialize(NULL); BasicScriptHost* host=NULL; host->AddScriptFile("C:\\Users\\123.js"); host->Init(); CComPtr<IDispatch> pJs; host->GetScriptDispatch(&pJs); CComVariant var1(10); CComVariant var2(20); CComVariant ret; pJs.Invoke2((LPCOLESTR)"add", &var1, &var2, &ret); host->Close(); ::CoUninitialize(); 无效,但是我不知道如何初始化m_pEngine

1 个答案:

答案 0 :(得分:1)

在未初始化对象时访问类成员变量将捕获异常。您应该实现BasicScriptHost构造函数和IActiveScriptSite的一些抽象函数,以便正确初始化变量host

这是类声明的示例:

class BasicScriptHost : public IActiveScriptSite
{
    ULONG ref;
public:
    BasicScriptHost() : ref(1) {    }

    ULONG WINAPI AddRef() {
        return InterlockedIncrement(&ref);
    }

    ULONG WINAPI Release(){
        LONG refCount = InterlockedDecrement(&ref);
        if (!refCount)
            delete this;
        return refCount;
    }

    HRESULT WINAPI QueryInterface(REFIID iid, void **ppvObject){
        *ppvObject = 0;
        if (iid == IID_IUnknown)
            *ppvObject = (IUnknown*)(IActiveScriptSite*)this;
        else if (iid == IID_IActiveScriptSite)
            *ppvObject = (IActiveScriptSite*)this;
        else if (iid == IID_IActiveScriptSiteWindow)
            *ppvObject = (IActiveScriptSiteWindow*)this;
        else
            return E_NOINTERFACE;

        AddRef();
        return S_OK;
    }

    // ... your class body 
}

变量host应该首先初始化,然后在使用后释放:

::CoInitialize(NULL);
BasicScriptHost * host = new BasicScriptHost();

host->AddScriptFile("C:\\Users\\123.js");
host->Init();

CComPtr<IDispatch> pJs;
host->GetScriptDispatch(&pJs);
CComVariant var1(10);
CComVariant var2(20);
CComVariant ret;

pJs.Invoke2((LPCOLESTR)"add", &var1, &var2, &ret);
pJs.Release(); //release CComPtr after used.

host->Close();
host->Release(); //The pointer will be deleted here or the program has a memory leak

::CoUninitialize();