从C#到C ++的编组结构 [英] Marshalling Structure from C# to 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屋!