views:

485

answers:

3

I have written a C DLL and some C# code to test including this DLL and executing functions from it. I am not too familiar with this process, and am receiving a PInvokeStackImbalance exception whenever my DLL function is called from the C# source code. The code is as follows (I have commented most code out to isolate this problem):

C# Inclusion code:

using System;
using System.Runtime.InteropServices;
using System.IO;

namespace TestConsoleGrids
{
    class Program
    {

        [DllImport("LibNonthreaded.dll", EntryPoint = "process")]
            public unsafe static extern void process( long high, long low);

        static void Main(string[] args)
        {
            System.Console.WriteLine("Starting program for 3x3 grid");

            process( (long)0, (long)0 );

            System.Console.ReadKey();
        }
    }
}

C++ DLL Function Code

extern "C" __declspec(dllexport) void process( long high, long low );

void process( long high, long low )
{
    // All code commented out
}

Visual Studio generated dllmain code (I do not understand this construct, so I am including it)

// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
      )
{
 switch (ul_reason_for_call)
 {
 case DLL_PROCESS_ATTACH:
 case DLL_THREAD_ATTACH:
 case DLL_THREAD_DETACH:
 case DLL_PROCESS_DETACH:
  break;
 }
 return TRUE;
}

The details of the exception are:

A call to PInvoke function 'TestConsoleGrids!TestConsoleGrids.Program::process' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

+1  A: 

In C++ a long is 32 bit. In C# it's 64 bit. Use int in your C# declaration.

You could also try adding __stdcall to the C++ function. See: http://stackoverflow.com/questions/297654/what-is-stdcall

Daniel Earwicker
Alright fantastic insight, and you must be correct about the parameters as removing them completely resolves the problem. Simply declaring them as int in C# does not though.
Mason Blier
See update.....
Daniel Earwicker
A: 

in C# long means 64 bit int while in C++ long means 32 bit int, you need to change your pinvoke declaration to

 [DllImport("LibNonthreaded.dll", EntryPoint = "process")]
     public unsafe static extern void process( int high, int low);

You could also try changing your C++ declaration to stdcall, that's the calling convention used by most exported functions in the Windows environment.

 __stdcall  __declspec(dllexport) void process( long high, long low );
John Knoeller
Unfortunate this does not resolve the problem. Thank you for directing me to Type Marshalling however, I am researching this now.
Mason Blier
+2  A: 

The calling convention is wrong. If removing the int arguments doesn't trip the MDA then it is Cdecl:

 [DllImport("LibNonthreaded.dll", CallingConvention = CallingConvention.Cdecl)]
 public static extern void process(int high, int low);

This isn't the standard calling convention for exported DLL functions, you might consider changing it in the C/C++ code, if you can.

Hans Passant