NILADRI SEN Ответов: 1

Как я могу анализировать и вызывать структурные поля 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 ("значение диапазона.");

1 Ответов

Рейтинг:
11

Sergey Alexandrovich Kryukov

То, что вы делаете, не имеет никакого смысла.

Это имело бы смысл, если бы вы использовали C++, ориентированный на неуправляемый код. Затем вы будете использовать P/Invoke для вызова не измененных функций.

Но вы используете C++/CLI, который я мог бы определить по gcnew :-). Скорее всего, ваш проект C++/CLI является проектом смешанного режима (управляемый + неуправляемый).

Но тогда вам не нужно ничего П / вызывать с помощью DLLImport Вместо этого вы должны просто использовать выходные данные вашего проекта C++ как обычно .Чистая сборка и прямая ссылка на нее с помощью вашей сборки C#. Конечно, вы должны выставить некоторые управляемые классы "ref" как public и в таких классах оберните все функции, которые вы хотите вызвать из ссылочной сборки.

Пожалуйста, смотрите: Вызов собственных функций из управляемого кода.

—СА