现在手头有一个ocx控件,要调用其中的方法,写了如下代码:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
#include <dbt.h>
/*#import "c:/windows/system32/cryptocx.ocx" \
no_namespace no_smart_pointers raw_interfaces_only \
raw_native_types no_implementation named_guids*/
#import "c:/windows/system32/cryptocx.ocx" \
named_guids
//这个地方只加了一个named_guids的参数,因为如果写no_namespace会报“使用未声明标识符”的错误,加其他参数也会有其他不同问题using namespace CRYPTOCXLib;void main()
{
    try{
CoInitialize(NULL) ; 
         {
          if(1)
  {
           _DCryptOcx* pCrypt = 0 ;      
            HRESULT hr = CoCreateInstance(
            CLSID_CryptOcx,//Com对象标识符
            0,//指向接口IUnknown指针
            CLSCTX_ALL,//运行可执行代码上下文
            DIID__DCryptOcx,//Com对象接口标识符
            reinterpret_cast<void**>(&pCrypt)//用来接收指向Com对象接口地址指针变量 
            );
   assert( SUCCEEDED(hr) ) ;
   if(pCrypt){
pCrypt->OpenDevice(L"111111");
pCrypt->Release();
}
  }
         }  
         CoUninitialize() ;
    }
catch(_com_error *e)
{
MessageBoxA(NULL,e->ErrorMessage(),NULL,NULL);
}
}
这样子写直接debug,编译通过,程序执行之后,会弹出一个visual studio的messagebox,报错USBTest.exe 中的 0x7c812afb 处未处理的异常: Microsoft C++ 异常: 内存位置 0x0012fcd8 处的 _com_error。加断点逐步调试,是执行到pCrypt->OpenDevice(L"111111");这一句,这个方法再去调用其它的方法时,会报“CXX0030: 错误: 无法计算表达式的值”,因为ocx不是我写的,只是拿过来用,对方给的javascript的例子,就在网页载入了这个ocx,然后就直接可以调用opendevice方法,所以我也不知道现在是什么原因报错,请问我上面代码写的有问题么?本人c++菜鸟一个,请达人指教,谢谢

解决方案 »

  1.   

    //编译生成的cryptocx.tlh文件
    // Created by Microsoft (R) C/C++ Compiler Version 15.00.21022.08 (90773aaa).
    //
    // e:\project\usbtest\usbtest\debug\cryptocx.tlh
    //
    // C++ source equivalent of Win32 type library c:/windows/system32/cryptocx.ocx
    // compiler-generated file created 06/02/12 at 20:11:36 - DO NOT EDIT!#pragma once
    #pragma pack(push, 8)#include <comdef.h>namespace CRYPTOCXLib {//
    // Forward references and typedefs
    //struct __declspec(uuid("d8af0d68-bea9-457f-ae9f-ae2f2f127d6c"))
    /* LIBID */ __CRYPTOCXLib;
    struct __declspec(uuid("c79bac42-db91-4937-9d2d-887d792b9c95"))
    /* dispinterface */ _DCryptOcx;
    struct __declspec(uuid("eaf2ecb8-e7fa-46af-adf2-147605ab0de0"))
    /* dispinterface */ _DCryptOcxEvents;
    struct /* coclass */ CryptOcx;//
    // Smart pointer typedef declarations
    //_COM_SMARTPTR_TYPEDEF(_DCryptOcx, __uuidof(_DCryptOcx));
    _COM_SMARTPTR_TYPEDEF(_DCryptOcxEvents, __uuidof(_DCryptOcxEvents));//
    // Type library items
    //struct __declspec(uuid("c79bac42-db91-4937-9d2d-887d792b9c95"))
    _DCryptOcx : IDispatch
    {
        //
        // Wrapper methods for error-handling
        //    // Methods:
        _bstr_t OpenDevice (
            _bstr_t strPasswd );
        _bstr_t CloseDevice ( );
        _bstr_t VerifyPin (
            _bstr_t strPasswd );
        _bstr_t ChangePin (
            _bstr_t oldPass,
            _bstr_t newPass );
        _bstr_t ReadCert (
            _bstr_t certNo );
        _bstr_t ClientHello (
            _bstr_t dwFlags );
        _bstr_t ClientAuth (
            _bstr_t strServerHello,
            _bstr_t dwFlags );
        _bstr_t VerifyCert (
            _bstr_t CertFlags,
            _bstr_t Cert,
            _bstr_t VerifyFlags,
            _bstr_t OCSPIP );
        _bstr_t ReloadKeyPin (
            _bstr_t MasterPin,
            _bstr_t newpin );
        _bstr_t GetCKeyVerifyStatus ( );
        _bstr_t ParseCert (
            _bstr_t Cert,
            _bstr_t parseStr,
            _bstr_t base64Flag );
        _bstr_t VerifySignbyCert (
            _bstr_t Cert,
            _bstr_t sign,
            _bstr_t src );
        _bstr_t GetVersion ( );
        _bstr_t DigestData (
            _bstr_t strData,
            _bstr_t strAlgid );
        _bstr_t SignData (
            _bstr_t strData,
            _bstr_t strSignAlgid,
            _bstr_t strTime,
            _bstr_t dwFlags );
        _bstr_t VerifySign (
            _bstr_t strData,
            _bstr_t SignData,
            _bstr_t CertData,
            _bstr_t strSignAlgid,
            _bstr_t dwFlags );
        HRESULT AboutBox ( );
    };struct __declspec(uuid("eaf2ecb8-e7fa-46af-adf2-147605ab0de0"))
    _DCryptOcxEvents : IDispatch
    {};struct __declspec(uuid("18ed5d4d-446e-436a-a839-f21382dd1f77"))
    CryptOcx;
        // [ default ] dispinterface _DCryptOcx
        // [ default, source ] dispinterface _DCryptOcxEvents//
    // Named GUID constants initializations
    //extern "C" const GUID __declspec(selectany) LIBID_CRYPTOCXLib =
        {0xd8af0d68,0xbea9,0x457f,{0xae,0x9f,0xae,0x2f,0x2f,0x12,0x7d,0x6c}};
    extern "C" const GUID __declspec(selectany) DIID__DCryptOcx =
        {0xc79bac42,0xdb91,0x4937,{0x9d,0x2d,0x88,0x7d,0x79,0x2b,0x9c,0x95}};
    extern "C" const GUID __declspec(selectany) DIID__DCryptOcxEvents =
        {0xeaf2ecb8,0xe7fa,0x46af,{0xad,0xf2,0x14,0x76,0x05,0xab,0x0d,0xe0}};
    extern "C" const GUID __declspec(selectany) CLSID_CryptOcx =
        {0x18ed5d4d,0x446e,0x436a,{0xa8,0x39,0xf2,0x13,0x82,0xdd,0x1f,0x77}};//
    // Wrapper method implementations
    //#include "e:\project\usbtest\usbtest\debug\cryptocx.tli"} // namespace CRYPTOCXLib#pragma pack(pop)
      

  2.   

    后来看了msdn的一个帖子,又修改了代码如下:
    try{
        CoInitialize(NULL) ; 
        {
    if(1)
       {
    _DCryptOcxPtr pCrypt;
    HRESULT hr = pCrypt.CreateInstance(__uuidof(_DCryptOcx));
    if(pCrypt)
    {
    pCrypt->OpenDevice(L"");
                    pCrypt.Release();
    }
        }
        }  
        CoUninitialize() ;
    }
    这样写HRESULT hr那一步hr的返回结果就不是成功的了,然后到if(pCrypt)这里就直接跳过了,应该是因为pCrypt为空,请问这样写是什么原因创建实例失败了呢?谢谢
      

  3.   

    openDevice这个方法在tli中是这样写的:
    inline _bstr_t _DCryptOcx::OpenDevice ( _bstr_t strPasswd ) {
        BSTR _result = 0;
        _com_dispatch_method(this, 0x1, DISPATCH_METHOD, VT_BSTR, (void*)&_result, 
            L"\x0008", (BSTR)strPasswd);
        return _bstr_t(_result, false);
    }
    报错信息如下:
    - _result 0x00000000 <错误的指针> wchar_t *
    CXX0030: 错误: 无法计算表达式的值
      

  4.   

    既然是OCX文件,最好在视图里或对话框里,用右键选择"添加 ACTIVECONTROL"类似的选项,就是插入控件,然后再关联对应的变量和生成这个控件的消息函数就可以了.如果你的工程不方便用这种方法,就先生成一个对话框,在对话框里添加这个控件,生成关联变量和这个控件的消息函数,然后再把在添加这个控件时生成的类文件都考到你的工程里,并在你的工程里按照在对话框里的生成这个控件的关联变量和这个消息函数的格式及语法手工添加到你的工程里就行了
      

  5.   

    你好,请问先生成对话框是指自己先生成一个窗口么?我原本是有一个程序,监控本机的usb端口的设备改变情况的,可以用你说的这个方法么?如果可以的话,请问能否稍微详细的说一下,谢谢。实在没用c++做过东西
      

  6.   

    没明显错误, 建议进行更多的调试, 
    _com_dispatch_method(this, 0x1, DISPATCH_METHOD, VT_BSTR, (void*)&_result,  
      L"\x0008", (BSTR)strPasswd);
    你看看与0x1对应的函数是哪个, 然后在函数里面设置断点
      

  7.   

    你好,我查了一下0x1表示"操作的属性或者方法的编号,就是*.idl中方法或者属性前面的 id 属性,也可以通过GetIDsOfNames 来得到"
    不过我的项目中好像没有生成idl文件,请问这个我可以去哪里看0x1具体代表的函数含义呢?谢谢
      

  8.   

    CreateInstance已经写错了,参数必须是组件的CLSID,你填的是接口的IID
      

  9.   

    ls你好,请问是第四个参数需要修改么?我换成_DCryptOcx,编译时会报错,说error C2275: “CRYPTOCXLib::_DCryptOcx”: 将此类型用作表达式非法
    请问可以给我具体说一下哪个参数应该改为什么么?应该就是从tlh文件中找吧?谢谢
    CoCreateInstance(
                CLSID_CryptOcx,//Com对象标识符
               NULL,//指向接口IUnknown指针
                CLSCTX_ALL,//运行可执行代码上下文
                DIID__DCryptOcx,//Com对象接口标识符
                reinterpret_cast<void**>(&pCrypt)//用来接收指向Com对象接口地址指针变量 
                );
      

  10.   

    你导入类型库后,CLSID和IID等所有GUID都会生成对应的变量,直接用即可。你上面的CoCreateInstance的参数又错了,第一个参数是CLSID没错,但倒数第二个是IID,你填成了连接点接口(通常用DIID_开头),应该用IID_CryptOcx(如果没错的话应该有这个定义)。
    其实用你之前的代码就可以了:
    _DCryptOcxPtr pCrypt;
    HRESULT hr = pCrypt.CreateInstance(CLSID_CryptOcx);
    if(pCrypt)
      

  11.   

    用VC向导生成一个对话框程序,然后你在资源视图里会显示生成的对话框,再右键选择类似"添加 ACTIVITE CONTROL"的选项,然后再关联这个控件的变量,这时就会生成这个控件的类文件,这时你就可以把生成的类文件考到你的工程里,至于这个控件的消息函数的映射语法,也可以在对话框里生成,然后把相应的代码考到你的工程里,
      

  12.   

    redui您好,很奇怪我的tlh中没有生成IID_CryptOcx,直接使用编译会报错,说未声明。我现在倒数第二个参数是这么用的__uuidof(_DCryptOcx) 不过还是会报错。
    _DCryptOcxPtr pCrypt;
    HRESULT hr = pCrypt.CreateInstance(CLSID_CryptOcx);
    if(pCrypt)
    {
    std::cout << "checkUSB result is " 
                //<< checkUSB 
                << '\n' ;
    pCrypt->AddRef();
    BSTR bstrText=::SysAllocString(L"111111");
       
    pCrypt->OpenDevice(bstrText);
    ::SysFreeString(bstrText);
    pCrypt->GetVersion();
                pCrypt.Release();
    }
    这样子写确实pCrypt可以继续执行,执行AddRef()都没有问题,可是到了OpenDevice就会去执行下面这个方法,位于comutil.h
    inline _bstr_t::_bstr_t(const wchar_t* s) 
        : m_Data(new Data_t(s))
    {
        if (m_Data == NULL) {
            _com_issue_error(E_OUTOFMEMORY);
        }
    }
    接着就去执行下面的方法
    inline void* _bstr_t::Data_t::operator new(size_t sz) 
    {
        return ::operator new(sz);
    }
    再执行几步之后就有参数报指针错误和CXX0030错误,最后就会报内存异常。
    我这个项目是用ocx的接口去读usbkey的信息,有朋友说读usbkey不能使用debug调试,但如果我直接生成后去执行exe,到了opendevice这一步就直接报c++ runtime error,application terminate in an unusual way之类的,不知道到底问题出在哪里。感觉前面CreateInstance已经成功了,就是不知道为什么不能调用方法
      

  13.   

    晚上我尝试换了一种方法来调用方法
    HRESULT   hr   =   NULL;   
      IDispatch*   pIDispatch   =   NULL;     
      hr   =   ::CoInitialize(NULL);   
      hr   =   ::CoCreateInstance(CLSID_CryptOcx,   NULL,   CLSCTX_INPROC_SERVER,   IID_IDispatch,   (void**)&pIDispatch);   
     if   (SUCCEEDED(hr))   
      {   
      DISPID dispid;   
      LPOLESTR name=L"OpenDevice";
      hr=pIDispatch->GetIDsOfNames(IID_NULL,&name,1,::GetUserDefaultLCID(),&dispid);   
      if   (SUCCEEDED(hr))   
      {   
      UINT   iError   =   -1;   
      VARIANT rarg;   
      ::VariantInit(&rarg);   
      VARIANT var[1];     
      ::VariantInit(&var[0]);   
      var[0].vt=VT_BSTR;
      BSTR bstrText=::SysAllocString(L"111111");
      var[0].bstrVal=bstrText;       //参数值
      ::SysFreeString(bstrText);
      DISPPARAMS   param;   
      param.cArgs   =   1;   
      param.rgvarg   =   var;   
      param.cNamedArgs   =   0;   
      param.rgdispidNamedArgs   =   NULL;   
        
      hr   =   pIDispatch->Invoke(dispid,   IID_NULL,   GetUserDefaultLCID(),   DISPATCH_METHOD,   &param,   &rarg,   NULL,   &iError);   
     
      if   (SUCCEEDED(hr))   
      {   
      //调用成功  
     std::cout << "Device Open Successfully " 
                << '\n' ; 
      }   
      ::VariantClear(&rarg);   
      ::VariantClear(&var[0]);   
      } 
      else
      {
      ::MessageBox(NULL,"getIDsOfNames failed","Error",0x10010);
      }
      pIDispatch->Release();   
      }
    这样写一直执行到hr   =   pIDispatch->Invoke都是没问题的,但是Invoke这个方法的返回结果始终不成功,一直是E_UNEXPECTED,之前GetidsOfNames返回的dispid的值也是正确的,和tli里面定义的值一样,只不过tli中用的是16进制,程序中返回的是一个Long型,不知道是不是其他参数写的有问题?还望达人赐教,谢谢
      

  14.   

    hdg3707您好,感谢您的热心回复,不过您建议的方法我实在没有时间来实现,不好意思,还是很感谢
      

  15.   

    我也被这个问题困扰了好多天,后来发现是因为COleControl中的IsInvokeAllowed需要重载 令返回值为TRUE 就可可以了  希望这个答案能帮助你们及以后看到这个帖子的童鞋解决问题。