从C#到C ++的编组结构 [英] Marshalling Structure from C# to C++

查看:103
本文介绍了从C#到C ++的编组结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好我不熟悉C#和编组。

我的目标是:

用C#创建一个界面并在课堂上实现它。

方法之一将采用结构[如果不是一个好主意然后指向结构]

现在我尝试用原始数据类型填充结构。



生成一个dll和tlb。

现在,从C ++导入tlb并使用该方法。



我成功访问了C#类并访问了一个方法但是一个采用结构抛出了E_INVALIDARG异常。



这里是我的代码:

来自C#



 命名空间 ComTestCS 
{
[ComVisible( true )]
[Guid( F9386F04-2F38-4DF5-9C9C-544DF9354AAC)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IShCom
{
int getHello( int x);
void getCSObj( out CSStObj ob);
}

[
ComVisible( true ),
Guid( E2B721B2-5AEA-4AD7-BCC2-1DA51D0E9C79),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces ( typeof (IShCom)),
ProgId( ShCom

]

public class ShCom:IShCom
{
public int getHello( int x)
{
System.IO.TextWriter textWriter = System.Console.Out;
textWriter.WriteLine( getHello); // 其打印
return x + 2;
}

public void getCSObj( out CSStObj ob) // 根本不工作
{
System.IO.TextWriter textWriter = System.Console.Out;
textWriter.WriteLine( getCSObj);
ob = new CSStObj();
ob.intData = 45 ;
}
}

[
ComVisible( true ),
Guid( 93BA11B9-A89B-4CB4-8ACE-1CDFC42FA978),
StructLayout(LayoutKind.Sequential,CharSet = CharSet.Ansi)

]
public struct CSStObj
{
// [MarshalAs(UnmanagedType.I4)]
public int intData;
}





现在从C ++访问它



< pre lang =cs> #import ComTestCS.tlb named_guids
void main()
{

尝试 {

CoInitialize(NULL);
// regasm ComTestCS.dll / tlb:c:\bin\ComTestCS.dll / codebase
ComTestCS :: IShComPtr pShCom;
ComTestCS :: CSStObj * stObj = new ComTestCS :: CSStObj();
HRESULT hr = pShCom.CreateInstance(__ uuidof(ComTestCS :: ShCom));
if (hr == S_OK)
{
long ret ;
// 按预期返回10以及控制台消息msg
ret = pShCom - > getHello(8L);
pShCom-> getCSObj(stObj); // 此处异常
}
}
catch (_ com_error& ce)
{

cout<< ce.Error()<<(wchar_t *)ce.Description( ); // E_INVALIDARG
}

CoUninitialize();

}



请帮忙!

提前致谢

解决方案

如果使用原始数据类型,则可以通过强制转换使用直接内存访问。最好在使用它的进程/语言中创建内存,而不是在c#和C ++之间进行转换。如果要在C ++中使用C#对象,则需要在C ++中 CLR项目



查看我的文章,了解一种简单的工作方式那个问题。


嗨所有感谢您的回复,

实际上我必须使用非CLR C ++本机代码。



我得到了答案:

在这里

看到Native Exe调用Managed Dll



为了我的需要扭曲了一点



C#代码:



 使用系统; 
使用 System.Collections.Generic;
使用 System.Text;
使用 System.Runtime.InteropServices;
命名空间 CSDll
{
使用系统;

[
Guid( A2BDE14F-EC09-4E3C-9E39-A24B49352120
]
public struct CSStObj
{
// [MarshalAs(UnmanagedType.I4)]
public int intData;
[MarshalAs(UnmanagedType.BStr)]
public string strData;
}

[Guid( D4660088-308E-49fb-AB1A-77224F3FF851 )]
public interface IMyManagedInterface
{
int factorial( int arg);
void getCSObj( out CSStObj ob);
void getCSObjs([MarshalAs(UnmanagedType.SafeArray,SafeArraySubType = VarEnum.VT_USERDEFINED)] out CSStObj [] ob);
// void getCSObjs(out list< csstobj> ob);
}

/// < 摘要 >
/// Class1的摘要说明。
/// < / summary >
[Guid( 46A951AC-C2D9-48e0-97BE-91F3C9E7B065)]
public class Class1:IMyManagedInterface
{
public Class1()
{
}

public int factorial(< span class =code-keyword> int arg)
{
int 结果;

if (arg == 1
{
result = arg;
}
else
{
result = arg * factorial(arg - 1 );
}

返回结果;
}
public void getCSObj( out CSStObj ob)
{
System.IO.TextWriter textWriter = System.Console.Out;
textWriter.WriteLine( getCSObj);
ob.intData = 7 ;
ob.strData = hiCPP;
}

public void getCSObjs([MarshalAs(UnmanagedType。 SafeArray,SafeArraySubType = VarEnum.VT_USERDEFINED)] out CSStObj [] ob)
{
System.IO.TextWriter textWriter = System.Console.Out ;
textWriter.WriteLine( getCSObjs);


ob =
new CSStObj [] {
new CSStObj(){intData = 1 ,strData = 1},
new CSStObj(){intData = 2 ,strData = 2},
new CSStObj(){intData = 3 ,strData = 3}
};

}

}
} < / csstobj >









在Atl non clr项目中



 # include     stdafx.h 
#pragma once

#include windows.h
#include < stdio.h >
#importC:\ bin \\ \\ CSDll.tlbnamed_guids
// #importCSDll.tlbnamed_guids

int main( int argc, char * argv [])
{
尝试 {
HRESULT hRes = S_OK;
CoInitialize(NULL);


CSDll :: IMyManagedInterface * pManagedInterface = NULL;

hRes = CoCreateInstance(CSDll :: CLSID_Class1,NULL,CLSCTX_INPROC_SERVER,
CSDll :: IID_IMyManagedInterface,reinterpret_cast< void **>(& pManagedInterface));

if (S_OK == hRes)
{
long retVal = 0 ;
hRes = pManagedInterface-> raw_factorial( 4 ,& retVal);
printf( dll返回的值是%ld \ n,retVal );

CSDll :: CSStObj stObj;
pManagedInterface-> getCSObj(& stObj);
printf( getCSObj发送的是%ld%s \ n,stObj.intData ,stObj.strData);

SAFEARRAY * saValues(NULL);
pManagedInterface-> getCSObjs(& saValues);
/// /////////////////// //////////////////

CSDll :: CSStObj * pVals;
HRESULT hr = SafeArrayAccessData(saValues,( void **)& pVals); // 直接访问SA内存
if (SUCCEEDED(hr))
{
long lowerBound,upperBound; // 获取数组边界
SafeArrayGetLBound(saValues, 1 ,& lowerBound);
SafeArrayGetUBound(saValues, 1 ,& upperBound);

long cnt_elements = upperBound - lowerBound + 1 ;
for int i = 0 ; i< cnt_elements; ++ i) // 迭代返回值
{
CSDll :: CSStObj pVal = pVals [i];
printf( getCSObjs发送的Struct数组是%ld%s \ n, pVal.intData,pVal.strData);
}
SafeArrayUnaccessData(saValues);
}



SafeArrayDestroy(saValues);
saValues = NULL; // 将指针设置为NULL
/ // ////////////////////////////////// ////


pManagedInterface-> Release();
}


} catch (_ com_error& ce)
{

printf( Exception ::%d ||%s,ce.Error(),( wchar_t *)ce.Description());
}

CoUninitialize();
return 0 ;
}





我可以访问String,Structure,Array of Structure等所有我需要的东西。


Hi All I am new to C# and marshalling.
My objective is:
Creating an Interface in C# and implementing it in class.
One of method will take a structure [if not a good idea then pointer to structure]
For now I an try filling the structure with primitive datatype.

Generating a dll and tlb out of it.
Now, From C++ importing the tlb and use the method.

I succeeded till accessing the C# class and access one method but the one takes structure is throwing E_INVALIDARG exception.

here is my code:
From C#

namespace ComTestCS
{
   [ComVisible(true)]
   [Guid("F9386F04-2F38-4DF5-9C9C-544DF9354AAC")]
    [InterfaceType (ComInterfaceType.InterfaceIsIDispatch)]
    public interface IShCom
    {
       int getHello(int x);       
       void getCSObj(out CSStObj ob);
    }

     [
       ComVisible(true),
       Guid("E2B721B2-5AEA-4AD7-BCC2-1DA51D0E9C79"),   
       ClassInterface(ClassInterfaceType.None),
       ComSourceInterfaces (typeof(IShCom))    ,
       ProgId("ShCom")
       
   ]

   public class ShCom : IShCom
    {
       public int getHello(int x)
       {
           System.IO.TextWriter textWriter = System.Console.Out;
           textWriter.WriteLine("getHello");//its printing
           return x+2;       
       }
      
       public void getCSObj(out CSStObj ob)//not working at all
       {
           System.IO.TextWriter textWriter = System.Console.Out;
           textWriter.WriteLine("getCSObj");
           ob = new CSStObj();
           ob.intData= 45;              
       }
    }

    [
    ComVisible(true),
    Guid("93BA11B9-A89B-4CB4-8ACE-1CDFC42FA978"),
     StructLayout(LayoutKind.Sequential,CharSet= CharSet.Ansi) 
         
    ]
     public struct CSStObj
     {
        //[MarshalAs (UnmanagedType.I4)]
         public int intData;       
     }



Now Accessing it from C++

#import "ComTestCS.tlb"      named_guids
void main()
{

   try{

       CoInitialize(NULL);
       //regasm ComTestCS.dll /tlb: c:\bin\ComTestCS.dll /codebase
       ComTestCS::IShComPtr pShCom;
       ComTestCS::CSStObj *stObj = new ComTestCS::CSStObj();
       HRESULT hr= pShCom.CreateInstance(__uuidof(ComTestCS::ShCom));
       if(hr == S_OK)
       {
       long ret;
       //returning 10 as expected along with the console msg
       ret =pShCom->getHello(8L);
       pShCom->getCSObj(stObj);    //exception here   
   }
   }
    catch(_com_error& ce)
   {

      cout<<ce.Error()<<(wchar_t*)ce.Description();//E_INVALIDARG 
   }
  
   CoUninitialize();
  
}


Please help!
Thanks in advance

解决方案

If you are working with primitive data type you can use direct memory access via casting. It is better to create memory in the process/language where you used it and NOT transfer between c# and C++. If you want to use C# objects in C++ you need CLR project in C++.

Take a look at my article about an easy way to work with that issue.


Hi All thanks for the response ,
Actually I have to use non CLR C++ native code.

I got the answer from :
Here
see the Native Exe calling Managed Dll

Just twisted little bit for my need

C# code:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace CSDll
{
    using System;

    [
    Guid("A2BDE14F-EC09-4E3C-9E39-A24B49352120")
    ]
    public struct CSStObj
    {
        //[MarshalAs (UnmanagedType.I4)]
        public int intData;
        [MarshalAs(UnmanagedType.BStr)]
        public string strData;
    }

    [Guid("D4660088-308E-49fb-AB1A-77224F3FF851")]
    public interface IMyManagedInterface
    {
        int factorial(int arg);
        void getCSObj(out CSStObj ob);
        void getCSObjs([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_USERDEFINED)] out CSStObj[] ob);
      //  void getCSObjs(out List<csstobj> ob);
    }

    /// <summary>
    ///    Summary description for Class1.
    /// </summary>
    [Guid("46A951AC-C2D9-48e0-97BE-91F3C9E7B065")]
    public class Class1 : IMyManagedInterface
    {
        public Class1()
        {
        }

        public int factorial(int arg)
        {
            int result;

            if (arg == 1)
            {
                result = arg;
            }
            else
            {
                result = arg * factorial(arg - 1);
            }

            return result;
        }
        public void getCSObj(out CSStObj ob)
        {
            System.IO.TextWriter textWriter = System.Console.Out;
            textWriter.WriteLine("getCSObj");
            ob.intData = 7;
            ob.strData = "hiCPP";
        }

        public void getCSObjs([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_USERDEFINED)] out CSStObj[] ob)
        {
            System.IO.TextWriter textWriter = System.Console.Out;
            textWriter.WriteLine("getCSObjs");
    

            ob =
           new CSStObj[]{
                new CSStObj() { intData = 1, strData = "1" },
                new CSStObj() { intData = 2, strData = "2" },
                new CSStObj() { intData = 3, strData = "3" }
            };
            
        }

    }
}</csstobj>





In Atl non clr project

#include "stdafx.h"
#pragma once

#include "windows.h"
#include <stdio.h>
#import "C:\bin\CSDll.tlb"      named_guids 
//#import "CSDll.tlb" named_guids

int main(int argc, char* argv[])
{
   try{
    HRESULT hRes = S_OK;
    CoInitialize(NULL);
      
  
    CSDll::IMyManagedInterface *pManagedInterface = NULL;

    hRes = CoCreateInstance(CSDll::CLSID_Class1, NULL, CLSCTX_INPROC_SERVER, 
     CSDll::IID_IMyManagedInterface, reinterpret_cast<void**> (&pManagedInterface));

    if (S_OK == hRes)
    {
        long retVal =0;
        hRes = pManagedInterface->raw_factorial(4, &retVal);
        printf("The value returned by the dll is %ld\n",retVal);
		
		CSDll::CSStObj stObj;
      pManagedInterface->getCSObj(&stObj); 
	  printf("getCSObj sent is %ld %s\n",stObj.intData,stObj.strData);

     SAFEARRAY* saValues(NULL);
     pManagedInterface->getCSObjs(&saValues);
     ////////////////////////////////////////
     
      CSDll::CSStObj* pVals;
      HRESULT hr = SafeArrayAccessData(saValues, (void**)&pVals); // direct access to SA memory
      if (SUCCEEDED(hr))
      {
        long lowerBound, upperBound;  // get array bounds
        SafeArrayGetLBound(saValues, 1 , &lowerBound);
        SafeArrayGetUBound(saValues, 1, &upperBound);

        long cnt_elements = upperBound - lowerBound + 1; 
        for (int i = 0; i < cnt_elements; ++i)  // iterate through returned values
        {                              
          CSDll::CSStObj pVal = pVals[i];   
          printf("getCSObjs Array of Struct sent is %ld %s\n",pVal.intData,pVal.strData);
        }       
        SafeArrayUnaccessData(saValues);
     }

     
     
     SafeArrayDestroy(saValues);
     saValues = NULL; // set the pointer to NULL
     /////////////////////////////////////////
	  
	  
        pManagedInterface->Release();
    }


   } catch(_com_error& ce)
   {
      
      printf("Exception::%d||%s",ce.Error(),(wchar_t*)ce.Description());
   }

    CoUninitialize();
    return 0;
}



and I got access to String,Structure,Array of Structure etc all what I need in my next stage.


这篇关于从C#到C ++的编组结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆