八百里加急!本人用ATL和MFC混合写一控件,添加了两个ATL简单对象,一个Table,另一个Field,因些有了两个接口一个ITable,另一个IField,现在我想给ITable加一个方法(添加字段的方法):AddField(IField* newField),想像左边写的这个样,将另一个接口(字段)作为参数传进去,请问高手,我要怎么弄才能搞定?因为方法支持普通的类型作为参数,我知道普通的怎么弄,也知道数组怎么作为参数传进去,但就是自己写的类和结构、枚举还不知道咋作为方法的参数类型,还有属性的类型,请专家指点一二呀!!!!搞不定可能要死人了!!

解决方案 »

  1.   

    d:\Temp\StrongMap\StrongMap.idl(31): error MIDL2025 : syntax error : expecting a type specification near "IField"
    d:\Temp\StrongMap\StrongMap.idl(31): error MIDL2026 : cannot recover from earlier syntax errors; aborting compilation 
    这是什么错误呀?是编译时出现的,我就是将IField作为AddField方法参数的类型,看来还是不行呀!
      

  2.   

    我把代码贴出来,高手帮忙看看哪些地方出问题!
    [
    uuid(54971536-1A67-44E6-BF2F-7F3EB406AE1D),
    helpstring("Field Class")
    ]
    coclass Field
    {
    [default] interface IField;
    };[
    object,
    uuid(737E24EC-EBAA-4881-9AE9-CC4225BFD8D1),
    dual,
    nonextensible,
    helpstring("IField 接口"),
    pointer_default(unique)
    ]
    interface IField : IDispatch{
    };
    [
    object,
    uuid(D96063E8-F1E8-47CA-A276-2B4DF6F62E6D),
    dual,
    nonextensible,
    helpstring("ITable 接口"),
    pointer_default(unique)
    ]
    interface ITable : IDispatch{
    [id(1), helpstring("方法AddField")] HRESULT AddField([in] IField * Field);
    };
      

  3.   

    你的coclass Field为什么会放在interface定义之前呢?
      

  4.   

    这样AddField(IDispatch* newField)
      

  5.   

    http://www.vckbase.com/document/viewdoc/?id=1259原文出处:Passing C++ Object in ATL DLL简介
      几个星期以前,我拼命的寻找一个能够通过COM接口传递C++对象的例子,但是,没有找到.这就是我发表这篇文章的原因。  向ATL的DLL中传递一个C++对象参数并不是非常之难,但是,当然也会有点难度,也很有趣。  在开始一个工程以前,首先你得确信客户机和服务器组件都是适应C++的程序,其次,你必须知道怎样设置你的客户机和服务器。接口的局限性
      COM技术要求客户机和服务器高度的分离,这是通过接口实现的,但是问题出在:接口的方法中只提供了有限个参数数据类型,如果这个接口是基于IDispatch的,参数类型的可选范围就更加受到限制了,由于这些局限性,C++对象只有在满足以下条件时才能够传递:客户机和服务器都是由VC++编写。 
    它们必须共享对象的定义(比如 头文件)。 
    传递应用程序设计的简单的对象。 
    你的应用程序可能需要运行在一个分布式环境下。你希望COM的远程活动,本地/远程活动是透明的,安全的。 
    我建议,在开始工作之前,先顺序的看一下各个标题,现在,我列出实例,并作以下事情:创建一个ATL DLL服务器, 
    添加一个MFC类,从CObject类派生, 
    在类的头部使用 DECLARE_SERIAL 宏, 
    在类的中间使用 IMPLEMENT_SERI 宏, 
    覆盖Serialize() 方法, // 你的 CSimpleObj 类应该像这样:
    class CSimpleObj : public CObject
    {
      DECLARE_SERIAL( CSimpleObj )
    public:
    // 构造函数和析构函数
      CSimpleObj();
      virtual ~CSimpleObj();
    // 设置内部字符串数据
      void SetString( CString csData );
    // 用来向存档文件串行输入数据(序列化)
      virtual void Serialize(CArchive& ar);
    // 现实字符串数据
      void Show();
    private:
      CString m_strData;// 内部字符串数据
    };
    // 把这个数据对象写入到文档中
    void CSimpleObj::Serialize(CArchive& ar)
    {
      CObject::Serialize( ar );
    if (ar.IsLoading())
    {
    // 从档案文件提取数据
      ar >> m_strData;
    }
    else
    {
    // 把数据存入档案文件
      ar << m_strData;
    }
    }
    // 显示对象数据的方法
    void CSimpleObj::Show()
    {
      AfxMessageBox(m_strData);
    }
    //把字符串数据保存到一个变量中
    void CSimpleObj::SetString(CString csData)
    {
      m_strData = csData;
    }      
    现在,下一步就是用一个CArchive对象来进行序列化和反序列化(载入和存储对象),我用了一个叫CBlob的新类来实现的 class CBlob
    {
    public:
      CBlob() {};
      virtual ~CBlob() {};
    // 从一个 CObject对象中提取数据并载入到一个 SAFEARRAY对象中.
      SAFEARRAY* Load( CObject *pObj );
    // 重新创建一个SAFEARRAY对象
      BOOL Expand( CObject * &pObj, SAFEARRAY *pVar );
    private:
    };
    // 从一个 CObject对象中提取数据并用它构建一个 SAFEARRAY对象.
    SAFEARRAY* CBlob::Load( CObject *pObj)
    {
      CMemFile memfile; // 内存文件
    // 定义一个用来标记档案文件是读取还是存储的标志
      long lMode = CArchive::store | CArchive::bNoFlushOndelete;
    // 用内存文件创建档案文件
      CArchive ar(&memfile, lMode );
    // m_pDocument 不使用
      ar.m_pDocument = NULL;
    // 序列化对象到档案文件中
      ar.WriteObject(pObj);
    // 关闭档案文件--现在,数据在内存文件中
      ar.Close();
    // 取得内存文件的长度(以字节为单位)
      long llen = memfile.GetLength();
    // 释放缓冲区 关闭文件
      unsigned char *pMemData = memfile.Detach();
    // 设定safearray
      SAFEARRAY *psa;
    // 创建safearray对象存取流数据
      psa = SafeArrayCreateVector( VT_UI1, 0, llen );
    // 指向字节数组的指针
      unsigned char *pData = NULL;
    // 取得一个 safe array的指针. 锁定数组.
      SafeArrayAccessData( psa, (void**)&pData );
    // 拷贝内存文件到 safearray
      memcpy( pData, pMemData, llen );
    // 清理缓冲区
      delete pMemData;
    // 锁定对 safearray的访问
      SafeArrayUnaccessData(psa);
    // 返回一个在这分配的SAFEARRAY的指针
      return psa;
    }
    // 重新创建一个SAFEARRAY对象
    BOOL CBlob::Expand(CObject * &rpObj, SAFEARRAY *psa)
    {
      CMemFile memfile; // 反序列化的内存文件
      long lLength; // 字节数
      char *pBuffer; // 缓冲区指针
    // 锁定数组数据的访问
      SafeArrayAccessData( psa, (void**)&pBuffer );
    // 取得数组中元素个数. 是字节数
      lLength = psa->rgsabound->cElements;
    // 连接缓冲区到内存文件
      memfile.Attach((unsigned char*)pBuffer, lLength);
    // 从缓冲区头部开始
      memfile.SeekToBegin();
    // 创建一个连接到内存文件上的档案文件
      CArchive ar(&memfile, CArchive::load | CArchive::bNoFlushOndelete);
    // 不使用文档指针
      ar.m_pDocument = NULL;
    // 填充对象 取得指针
      rpObj = ar.ReadObject(0);
    // 关闭档案文件
      ar.Close();
    // 注意: 当SAFEARRAY被毁坏时 pBuffer 被释放
    // 释放缓冲区 关闭文件
      pBuffer = (char*) memfile.Detach();
    // 释放safearray 缓冲区
      SafeArrayUnaccessData( psa );
      return TRUE;
    }在这里 ,我使用SAFEARRAY是因为它对我们来说是最好的选择,它可以包含一些复杂的多维数组,但是,这个例子我们只使用了非常简单的数组,SAFEARRAY数据,有一个问题:MIDL认不出这个数据类型,在下一篇文章中我将讲述最简单的方法:使用 VARIANT数据类型。下一步如下:
    创建一个COM接口, 
    创建一个SAFEARRAY对象, 
    在IDL文件中定义: [helpstring("method SetArray")] 
    HRESULT SetArray([in]SAFEARRAY (unsigned char) pData);[helpstring("method GetArray")] 
    HRESULT GetArray([out/*,retval*/]SAFEARRAY(unsigned char) *pData); 
    创建一个基于MFC的客户机来测试该应用程序 你的IDL文件应该象这样: 
    interface IBolbData : IUnknown
    {
      [helpstring("method SetArray")] HRESULT SetArray([in]SAFEARRAY
        (unsigned char) pData);
      [helpstring("method GetArray")] HRESULT GetArray([out/*,retval*/]
        SAFEARRAY(unsigned char) *pData);
    };
    // 设定对象
    STDMETHODIMP CBolbData::SetArray(SAFEARRAY *pData)
    {
      AFX_MANAGE_STATE(AfxGetStaticModuleState())
    // 创建CSimpleObj的亚元指针
      CSimpleObj *dummy=NULL; 
    // 创建 blob 对象 用来填充、反序列化
      CBlob blob;
    // 使用 safearray 创建亚元对象
      blob.Expand( (CObject*&)dummy, pData );
      dummy->Show(); // 调用显示函数测试对象
      delete dummy; //删除指针
      return S_OK;
    }
    // 创建对象 并发送给客户机.
    STDMETHODIMP CBolbData::GetArray(SAFEARRAY **pData)
    {
      AFX_MANAGE_STATE(AfxGetStaticModuleState())
    // 创建对象并发送给服务器
      CSimpleObj *pMyOb = new CSimpleObj();
    //设定字符串数据
      pMyOb->SetString( "A SAFEARRAY from the server!" );
    // 创建blob来序列化对象
      CBlob blob;
    // 将对象载入blob
      *pData = blob.Load( pMyOb );
    // 删除pMyOb指针
      delete pMyOb;
      return S_OK;
    }
           
    最后,写一个有两个按钮的基于对话框的 MFC 应用程序 并添加如下代码:  void CClientDlg::OnOK()
    {
    // 从CLSID串创建COM智能指针
    try
    {
      IBolbDataPtr pI( "Server.BolbData.1" );
      SAFEARRAY *psa ;
    // 从服务器取得 safearray
      pI->GetArray( &psa );
    // 创建指针
      CSimpleObj *dummy=NULL;
    // blob 对象
      CBlob blob;
    //使用blob 扩展 safearray 到一个对象里
      blob.Expand( (CObject *&)dummy, psa );
    //通过调用一个对象的方法来测试它
      dummy->Show();
    // 删除对象
      delete dummy;
    }
    // 通过智能指针处理任意 COM 异常
    catch (_com_error e)
    {
    // 显示错误信息
      AfxMessageBox( e.ErrorMessage() );
    }
    }
    void CClientDlg::OnLoad()
    {
    try
    {
    // 从CLSID 串创建智能指针
      IBolbDataPtr pI( "Server.BolbData.1" );
      SAFEARRAY *psa ;
    // 创建送给服务器的对象
      CSimpleObj *pMyOb = new CSimpleObj();
    // 设置字符串数据
      pMyOb->SetString( "The client sent a SAFEARRAY!" );
    // 创建 blob 用来序列化对象
      CBlob blob;
    // 将对象载入到 blob
      psa = blob.Load( pMyOb );
    //删除对象
      delete pMyOb;
      pI->SetArray( psa );
    }
    catch (_com_error e)
    {
    // 显示错误信息
      AfxMessageBox( e.ErrorMessage() );
    }
    }      
    总结
      这篇文章包含了很多的主题:例如 怎样使用序列化,怎样使用 SAFEARRAY,和怎样通过接口传递C++对象。我要感谢William Rubin,他的文章对我帮助很大,我曾经计划把这个主题解释的更详细,但由于时间不足我无法完成,然而我会不断的更新这篇文章,在这期间,请不用客气的跟我联系。
      

  6.   

    看看徐颖的《COM编程精彩实例》
    在*.idl中先创建你要的类,struct,union等。在客户端可直接使用不再创建