Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

Is it possible to reference a C++ project from a C# project?

I'm trying to call some C++ I've written from some C# (also my code) and having troubles with Interop/PInvoke getting a populated int[] back. Is there a way I could just add a compile-time reference to the C++ project from the C# project and call the functions within it as though it were just another C# class library?

I have a basic sample to illustrate the problem with the array. This is the C# signature for the C++ function I'm calling.

    [DllImport("CPlusPlusTargetLibrary.dll", CallingConvention = CallingConvention.StdCall)]
    private static extern void Accumulate
    (
        int input,
        int accumulationFactor,
        int numberOfAccumulations,
        [In, Out, MarshalAs(UnmanagedType.LPArray)]
        int[] accumulationsPointer
    );

This is how it's called from C#:

        var numberOfAccumulations = 3;
        var accumulations = new int[numberOfAccumulations];

        Accumulate(-8, 1, numberOfAccumulations, accumulations);

This is its declaration in the C++ header file:

__declspec(dllexport) const void __stdcall Accumulate
(
    const signed long input,
    const signed long accumulationFactor,
    const signed long numberOfAccumulations,
    signed long* accumulationsPointer
);

And this is its implementation in 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;            
    }
}

The accumulations array just comes back as a 3-element array of all 0 - just as it was passed-in. Instead it should have come back containing -8, -16 and -24.

I followed the documentation on MSDN for marshaling int[] and according to it, I shouldn't have needed any manual Marshaling (but even taking out the MarshalAs attribute didn't resolve the issue): https://docs.microsoft.com/en-us/dotnet/framework/interop/marshaling-different-types-of-arrays

I had hoped if I could reference the C++ project directly then I wouldn't have to deal with all the type-related runtime failures.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

your code doesn't write to the content of accumulationsPointer but overwrite the pointer itself with address of accumulation


it should be something like this

for (auto index = 0; index < numberOfAccumulations; index++, accumulationsPointer++)
{
   auto accumulation = input * ((index + 1) * accumulationFactor);
   *accumulationsPointer = accumulation;
}

or like this, like in c#

for (auto index = 0; index < numberOfAccumulations; ++index)
{
   auto accumulation = input * ((index + 1) * accumulationFactor);   
   accumulationsPointer[index] = accumulation;            
}

btw, signed long* accumulationsPointer can also be written as signed long accumulationsPointer[], e.g.

void Accumulate
(
   const signed long input,
   const signed long accumulationFactor,
   const signed long numberOfAccumulations,
   signed long accumulations[]
)
{
   for (auto index = 0; index < numberOfAccumulations; ++index)
   {
      auto accumulation = input * ((index + 1) * accumulationFactor);
      accumulations[index] = accumulation;            
   }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...