简体   繁体   中英

P/Invoke problem (unbalanced stack)

I am trying to make a wrapper for a native c++ .dll using P/Invoke.

The source code for the .dll has the following entry point specified:

// .h-file
CHROMAPRINT_API ChromaprintContext *chromaprint_new(int algorithm);

And the method implementation:

// .cpp-file
ChromaprintContext *chromaprint_new(int algorithm)
{
    ChromaprintContextPrivate *ctx = new ChromaprintContextPrivate();
    ctx->algorithm = algorithm;
    ctx->fingerprinter = new Fingerprinter(CreateFingerprinterConfiguration(algorithm));
    return (ChromaprintContext *)ctx;
}

The ChromaprintContextPrivate type is a structure:

>// .cpp-file
struct ChromaprintContextPrivate {
    int algorithm;
    Fingerprinter *fingerprinter;
    vector<int32_t> fingerprint;
};

My C# wrapper code:

// .cs-file
[System.Runtime.InteropServices.DllImportAttribute(
  "libchromaprint.dll", 
  EntryPoint = "chromaprint_new")]
private static extern System.IntPtr chromaprint_new(int algorithm);

public static IntPtr Chromaprint_New(ChromaprintAlgorithm algorithm)
{
    // Hardcoded parameter for testing
    return chromaprint_new(0); // (int)algorithm
}

Calling IntPtr ptr = Chromaprint_New(0); raises the following MDA exception:
A call to PInvoke function 'MyProject.ChromaprintWrapper!'MyProject.ChromaprintWrapper.LibChromaPrint::chromaprint_new' 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.

So I understand what the problem is (the number of entries on the stack isn't what is expected). I'm assuming the method parameter int algorithm is ok. I'm not sure about the return type though. Should it be a structure instead of a pointer?

I got the C# code above by running the .h-file through P/Invoke Interop Assistant . Is the return type wrong? what should it be?

What is the C# representation of vector<int32_t> fingerprint; ?
(See ChromaprintContextPrivate structure above.)

You most likely need to specify the calling convention.

Try the following:

[System.Runtime.InteropServices.DllImportAttribute("libchromaprint.dll", 
     EntryPoint = "chromaprint_new",
     CallingConvention=CallingConvention.Cdecl)]

By default, this uses Winapi (which is effectively StdCall) to make it easier to call into the Windows API, but this is not typically the default on most C++ libraries.

It's because of how the parameters are actually passed, the calling convention .

Try

[DllImport("libchromaprint.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr chromaprint_new(int algorithm);

您需要在dllimport属性上声明cdecl调用约定。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM