Я пытаюсь вызвать некоторый С++, который я написал с некоторого С# (также мой код), и у меня возникают проблемы с Interop/PInvoke, возвращающим заполненный int[]
обратно. Есть ли способ просто добавить ссылку времени компиляции на проект С++ из проекта С# и вызвать функции внутри него, как если бы это была просто еще одна библиотека классов С#?
У меня есть базовый пример, иллюстрирующий проблему с массивом. Это подпись C# для функции C++, которую я вызываю.
[DllImport("CPlusPlusTargetLibrary.dll", CallingConvention = CallingConvention.StdCall)]
private static extern void Accumulate
(
int input,
int accumulationFactor,
int numberOfAccumulations,
[In, Out, MarshalAs(UnmanagedType.LPArray)]
int[] accumulationsPointer
);
Вот как это вызывается из C#:
var numberOfAccumulations = 3;
var accumulations = new int[numberOfAccumulations];
Accumulate(-8, 1, numberOfAccumulations, accumulations);
Это его объявление в заголовочном файле C++:
__declspec(dllexport) const void __stdcall Accumulate
(
const signed long input,
const signed long accumulationFactor,
const signed long numberOfAccumulations,
signed long* accumulationsPointer
);
А это его реализация на C++:
__declspec(dllexport) const void __stdcall Accumulate
(
const signed long input,
const signed long accumulationFactor,
const signed long numberOfAccumulations,
signed long* accumulationsPointer
)
{
for (auto index = 0; index < numberOfAccumulations; index++, accumulationsPointer++)
{
auto accumulation = input * ((index + 1) * accumulationFactor);
accumulationsPointer = &accumulation;
}
}
Массив accumulations
просто возвращается как трехэлементный массив всех 0
- точно так же, как он был передан. Вместо этого он должен был вернуться, содержащий -8
, -16
и -24
.
Я следовал документации в MSDN для маршалинга int[]
, и, согласно ей, мне не нужно было маршалировать вручную (но даже удаление атрибута MarshalAs
не решило проблему): https://docs.microsoft.com/en-us/dotnet/framework/interop/marshaling-other-types-of-arrays
Я надеялся, что если я смогу напрямую ссылаться на проект C++, то мне не придется иметь дело со всеми ошибками времени выполнения, связанными с типами.
long
в C++ равенint
в C#: displayfusion.com/Discussions/View/converting-c-data-types-to-c/long
в C# на самом делеlong long
в C++! - person Matt Arnold   schedule 12.01.2021long
наint
из любопытства (я не знал, чтоint
также был 32-битнымint
в C ++), но результат все равно был прежним. - person Matt Arnold   schedule 12.01.2021accumulationsPointer = &accumulation;
не должен быть*accumulationsPointer = accumulation;
? - person apple apple   schedule 12.01.2021accumulationsPointer
- person apple apple   schedule 12.01.2021accumulationsPointer[index] = accumulation
, безaccumulationsPointer++
) - person apple apple   schedule 12.01.2021accumulationsPointer* = accumulation
и получал ошибку компилятораexpected an expression
, поэтому я предполагал, что значения указателя доступны только для чтения в C++. Теперь я возвращаю ожидаемые значения с вашим предложением. Я с радостью отмечу это как ответ на мою проблему, хотя я не знаю, должен ли я теперь изменить название вопроса, чтобы помочь другим в будущем прийти к этому. - person Matt Arnold   schedule 12.01.2021