Как я могу анализировать и вызывать структурные поля C++ из кода C#?
Ну, я намерен применить маршалинг между управляемыми и неуправляемыми кодами. То есть, чтобы получить результат из кода c++ в код c#. Я не собираюсь знать здесь определение управляемого и неуправляемого кода, скорее я готов найти правильный выход из этого.
Раздел: неуправляемый код
Файл: unmanaged_operation.cpp
#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; }
Раздел: управляемый код
Файл: 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. } } }
Допустим, что метод Do_Something_With_BSTR_Input_Value в unmanaged_operation.cpp быть:
BSTR* __stdcall Do_Something_With_BSTR_Input_Value(/* in */ BSTR* input) { return input; }
это только для целей тестирования, а не для цитирования оригинала. И я хотел напечатать то же самое значение для консоли, которое я передал в качестве параметра в методе Parse, Strip или Range в managed_operation. cs
Любое предложение с примером кода будет очень востребовано.
Что я уже пробовал:
Я использовал следующий код для тестирования в 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
[DllImport (@"unmanaged_operation.dll"), CallingConvention = CallingConvention.Нарушением соглашения о стандартном)]
частных статических недействительным Экстерн GetOperationPtr([выход] [помощью атрибута marshalas(unmanagedtype значение.Структура из Указателя IntPtr ПТР);
[STAThread]
публичный статический пустота главный(строка[] аргументы)
{
пробовать
{
Операция ВГД = новая операция ВГД();
Parse ("значение parse.");
Strip ("значение полосы.");
Range ("значение диапазона.");
Работать((Double)в 7.45);
IntPtr ptr;
GetOperationPtr(ПТР);
// Следующая строка вызывает исключение
операция = (IOperation) (Маршал.PtrToStructure(ptr, typeof(IOperation)));
// Приведенная выше строка вызывает исключение
Приставка.WriteLine("{0}", operation.parseValue);
Приставка.WriteLine ("{0}", операция.стаутпут);
}
catch (исключение e)
{
бросить е;
// Не удается маршалировать "параметр #1": недопустимая комбинация управляемого / неуправляемого типа
// (Int/UInt должен быть сопряжен с SysInt или SysUInt).
}
}
Снова я изменил IntPtr на object в определении GetOperationPtr следующим образом:
[DllImport (@"unmanaged_operation.dll"), CallingConvention = CallingConvention.Нарушением соглашения о стандартном)]
частных статических недействительным Экстерн GetOperationPtr([выход] [помощью атрибута marshalas(unmanagedtype значение.Структура] из объекта ПТР);
и в основном методе:
Объект ptr;
GetOperationPtr(ПТР);
что привело к тому, что приложение было немедленно прекращено без дальнейшего выполнения.
Опять же, когда я опустил атрибут MarshalAs из определения GetOperationPtr, parseValue
возвращает мусорное значение что-то вроде 䕃洭獥慳敧 или 옧ﺧ㲨ѹ㲨ѹ или rather, а скорее любой видимый результат.
Чтобы избавиться от этого, я добавил параметр Charset в атрибут DllImport для определения GetOperation, как:
[DllImport (@"unmanaged_operation.dll"), CallingConvention = CallingConvention.Нарушением Соглашения О Стандартном, Кодировка = Кодировка.Юникод)]
private static extern IntPtr GetOperation();
и использовал тот же код в основном методе, что и описанный ранее; который в таком случае
выходное значение для каждого экземпляра поля IOperation, как:
операция.parseValue вернулся "стоимость газа". метод Parse("значение анализа.");
операция.stripValue вернулся "диапазон значений". для метода прокладки("стоимость газа.");
operation. rangeValue возвращает "значение синтаксического анализа" для метода Range ("значение диапазона.");