Visual studio 2010 如何从c++;到c#?
我打算在托管代码和非托管代码之间应用编组。也就是说,将结果从C++代码检索到C代码。我不想在这里知道托管或非托管的定义,而是想找到正确的方法 节:非托管代码 文件:unmanaged_operation.cppVisual studio 2010 如何从c++;到c#?,visual-studio-2010,visual-c++,c++-cli,Visual Studio 2010,Visual C++,C++ Cli,我打算在托管代码和非托管代码之间应用编组。也就是说,将结果从C++代码检索到C代码。我不想在这里知道托管或非托管的定义,而是想找到正确的方法 节:非托管代码 文件:unmanaged_operation.cpp #pragma managed(push, off) typedef struct _IOperation { double stOutput; double* dblPtrValue; BSTR* parseValue; BSTR* even
#pragma managed(push, off)
typedef struct _IOperation
{
double stOutput;
double* dblPtrValue;
BSTR* parseValue;
BSTR* evenValue;
BSTR* oddValue;
BSTR* stripValue;
BSTR* contextValue;
BSTR* rangeValue;
} IOperation, *LPIOperation;
#pragma managed(pop)
#if (_MANAGED == 1) || (_M_CEE == 1)
#include <vcclr.h>
using namespace System;
using namespace System::Runtime::InteropServices;
#endif
// In unmanaged_operation.h file
extern __declspec(dllexport) LPIOperation operation;
// In unmanaged_operation.cpp file
__declspec(dllexport) LPIFactory factory = new IFactory();
extern "C" __declspec(dllexport) void __stdcall Parse(/* in */ BSTR* input)
{
BSTR* value = Do_Something_With_BSTR_Input_Value(input);
String^ _output = gcnew String(*value);
IntPtr ptr = Marshal::StringToBSTR(_output);
operation->parseValue = (BSTR*)ptr.ToPointer();
Marshal::FreeBSTR(ptr);
}
extern "C" __declspec(dllexport) void __stdcall Strip(/* in */ BSTR* input)
{
BSTR* value = Do_Something_With_BSTR_Input_Value(input);
String^ _output = gcnew String(*value);
IntPtr ptr = Marshal::StringToBSTR(_output);
operation->stripValue = (BSTR*)ptr.ToPointer();
Marshal::FreeBSTR(ptr);
}
extern "C" __declspec(dllexport) void __stdcall Range(/* in */ BSTR* input)
{
BSTR* value = Do_Something_With_BSTR_Input_Value(input);
String^ _output = gcnew String(*value);
IntPtr ptr = Marshal::StringToBSTR(_output);
operation->rangeValue = (BSTR*)ptr.ToPointer();
Marshal::FreeBSTR(ptr);
}
extern "C" __declspec(dllexport) void __stdcall Operate(/* in */ double input)
{
double output = Do_Something_With_Double_Input_Value(input);
operation->stOutput = output;
}
extern "C" __declspec(dllexport) LPIOperation GetOperation()
{
return operation;
}
假设unmanaged_operation.cpp中的Do_Something_With_BSTR_Input_Value方法为:
BSTR* __stdcall Do_Something_With_BSTR_Input_Value(/* in */ BSTR* input)
{
return input;
}
仅用于测试目的,而非引用原文。我想将相同的值打印到控制台,在managed_operation.cs的Parse、Strip或Range方法中作为参数传递
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct IOperation
{
/* MarshalAs(UnmanagedType.R8)] */
public double stOutput;
public double[] dblPtrValue;
/* MarshalAs(UnmanagedType.BStr)] */
public string parseValue;
};
Class Program
{
[DllImport(@"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void Parse([In] String input);
[DllImport(@"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void Strip([In] String input);
[DllImport(@"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void Range([In] String input);
[DllImport(@"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void Operate([In] Double input);
[DllImport(@"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetOperation();
[STAThread]
public static void Main(string[] args)
{
try
{
IOperation operation = new IOperation();
Parse("The parse value.");
Strip("The strip value.");
Range("The range value.");
Operate((double)2.45);
IntPtr ptr = GetOperation();
// The following line throws the exception
operation = (IOperation)(Marshal.PtrToStructure(ptr, typeof(IOperation)));
// The above line throws the exception
Console.WriteLine("{0}", operation.parseValue);
Console.WriteLine("{0}", operation.stOutput);
}
catch (Exception e)
{
throw e;
// Exception of type 'System.ExecutionEngineException' was thrown.
}
}
}
[DllImport(@"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void GetOperationPtr([Out] [MarshalAs(UnmanagedType.Struct] out IntPtr ptr);
[STAThread]
public static void Main(string[] args)
{
try
{
IOperation operation = new IOperation();
Parse("The parse value.");
Strip("The strip value.");
Range("The range value.");
Operate((double)7.45);
IntPtr ptr;
GetOperationPtr(ptr);
// The following line throws the exception
operation = (IOperation)(Marshal.PtrToStructure(ptr, typeof(IOperation)));
// The above line throws the exception
Console.WriteLine("{0}", operation.parseValue);
Console.WriteLine("{0}", operation.stOutput);
}
catch (Exception e)
{
throw e;
// Cannot marshal 'parameter #1': Invalid managed/unmanaged type combination
// (Int/UInt must be paired with SysInt or SysUInt).
}
}
我在unmanaged_operation.cpp中使用了以下代码进行测试:
extern "C" __declspec(dllexport) void GetOperationPtr(LPIOperation output)
{
operation->stOutput = (double)2;
operation->parseValue = (BSTR*)"The BSTR string";
*output = *operation;
// OR output = operation;
}
并在managed_operation.cs中使用以下代码
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct IOperation
{
/* MarshalAs(UnmanagedType.R8)] */
public double stOutput;
public double[] dblPtrValue;
/* MarshalAs(UnmanagedType.BStr)] */
public string parseValue;
};
Class Program
{
[DllImport(@"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void Parse([In] String input);
[DllImport(@"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void Strip([In] String input);
[DllImport(@"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void Range([In] String input);
[DllImport(@"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void Operate([In] Double input);
[DllImport(@"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetOperation();
[STAThread]
public static void Main(string[] args)
{
try
{
IOperation operation = new IOperation();
Parse("The parse value.");
Strip("The strip value.");
Range("The range value.");
Operate((double)2.45);
IntPtr ptr = GetOperation();
// The following line throws the exception
operation = (IOperation)(Marshal.PtrToStructure(ptr, typeof(IOperation)));
// The above line throws the exception
Console.WriteLine("{0}", operation.parseValue);
Console.WriteLine("{0}", operation.stOutput);
}
catch (Exception e)
{
throw e;
// Exception of type 'System.ExecutionEngineException' was thrown.
}
}
}
[DllImport(@"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void GetOperationPtr([Out] [MarshalAs(UnmanagedType.Struct] out IntPtr ptr);
[STAThread]
public static void Main(string[] args)
{
try
{
IOperation operation = new IOperation();
Parse("The parse value.");
Strip("The strip value.");
Range("The range value.");
Operate((double)7.45);
IntPtr ptr;
GetOperationPtr(ptr);
// The following line throws the exception
operation = (IOperation)(Marshal.PtrToStructure(ptr, typeof(IOperation)));
// The above line throws the exception
Console.WriteLine("{0}", operation.parseValue);
Console.WriteLine("{0}", operation.stOutput);
}
catch (Exception e)
{
throw e;
// Cannot marshal 'parameter #1': Invalid managed/unmanaged type combination
// (Int/UInt must be paired with SysInt or SysUInt).
}
}
我再次在GetOperationPtr定义中将IntPtr更改为object,如下所示:
[DllImport(@"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void GetOperationPtr([Out] [MarshalAs(UnmanagedType.Struct] out object ptr);
在主要方法中:
Object ptr;
GetOperationPtr(ptr);
这导致应用程序立即终止,而没有进一步执行
同样,当我从GetOperationPtr定义中省略MarshalAs属性时,parseValue
返回垃圾值,类似于䕃洭獥慳敧 或옧ﺧ㲨Ѹ㲨Ѹ或멄攓�ѵ�而不是任何可见的结果
为了解决这个问题,我将Charset参数添加到GetOperation定义的DllImport属性中,如下所示:
[DllImport(@"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
private static extern IntPtr GetOperation();
并在Main方法中使用与前面所述相同的代码;在这种情况下,会对IOOperation字段的每个实例的输出值进行洗牌,如下所示:
operation.parseValue returned "The strip value." for the method Parse("The parse value.");
operation.stripValue returned "The range value." for the method Strip("The strip value.");
operation.rangeValue returned "The parse value." for the method Range("The range value.");
任何关于代码示例的建议都将被高度征求。总体而言
看来,您的目标是从C++中调用一些C++代码。在这种情况下,通常最好写一个C++/CLI托管类(关键字<代码>公共REF类< /COD>),并直接从那里调用C++代码。您可以用正常的方式从C#访问托管类,只需添加一个.Net引用并用C#
new
实例化该类
具体问题
如果您正在访问托管类型(String^
),则它不是非托管代码
分配字符串的方式不正确。您正在StringToBSTR
中分配一个新的BSTR
对象,保存指向它的指针,然后释放BSTR
对象。您现在有一个指向解除分配/无效内存的指针!这种记忆可以在任何时候重复使用
public struct IOperation
不要从I
开始,除非它们是一个接口。这就是命名惯例,坚持下去
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct IOperation
{
/* MarshalAs(UnmanagedType.R8)] */
public double stOutput;
public double[] dblPtrValue;
/* MarshalAs(UnmanagedType.BStr)] */
public string parseValue;
};
如果要从非托管复制到托管,double数组有多大?它应该使用多种字符串表示形式中的哪一种
推荐
我推荐两件事中的一件:
<> LI>如果你是一个非托管库,你是作者,考虑把这个结构变成更容易的自动封送器处理。<李>
public ref class
),手动将所有内容转换为非托管结构,调用非托管函数,然后将所有内容复制回李>