开发者

A call to PInvoke function 'Test!DllCall::initDll' has unbalanced the stack

Bit of an unusual question.

I have worked out that the error is only thrown when running the program via visual studio. If I compile the application and run the compiled program it works fine. Any ideas what would cause this?

I have a C# class that calls a method in a Java DLL ( compiled through excelsior jet ) via JNI.

When I compile and run the C# class an an executable everything works fine. Now I have built the C# class as a DLL and am trying to call it from another class.

At this point I get the followign error message: A call to PInvoke function 'Test!DllCall::initDll' 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.

Could anyone explain why Im getting this and how to fix it?

Please let me know if you need anymore code/information

Heres the C# code:

    using System;
    using System.Runtime.InteropServices;
    using System.Text;

        public class DllCall
        {
            [DllImport("Stubs")]
            public static extern int  initDll(String userDllName);

            [DllImport("Stubs")]
            public static extern void finalizeDll();

            [DllImport("Stubs")]
            public static extern UInt32 newClassInstance();

            [DllImport("Stubs")]
            public static extern int  invokeStaticMethod();

            [DllImport("Stubs")]
            public static extern String  request(UInt32 hClassInst, String input);

            [DllImport("Stubs")]
            public static extern void  close();

            [DllImport("Stubs")]
            public static extern void  voidtest(UInt32 hClassInst);


        }


        public class Test
        {
            public UInt32 hClass;


            public Test()
            {
                    //when compiled as a DLL this line throws the error. 
                int rc = DllCall.initDll("dllClass.dll");
                Console.Write("---> initDll() rc = {0}\n", rc);

                hClass = DllCall.newClassInstance();
                Console.Write("---> hClass = {0}\n", hClass);
            }

            // When compiled as an executable this method runs fine.
            public static void Main(string[] args)
            {
                int rc = DllCall.initDll("dllClass.dll");
                string rs;
                Console.Write("---> initDll() rc = {0}\n", rc);

                UInt32 hClass = DllCall.newClassInstance();
                Console.Write("---> hClass = {0}\n", hClass);

                rs = DllCall.request(hClass, "moo");
                Console.Write("---> request() rs = {0}\n", rs);

                DllCall.close();

                DllCall.finalizeDll();
            }



            public string request( string xmlInput )
            {
                string rs;
                rs = DllCall.request(hClass, xmlInput);
                Console.Write("---> request() rs = {0}\n", rs);
                return rs;
            }

            public void finalizeDll()
            {
                DllCall.finalizeDll();
            }

            public void closeConnection()
            {
                DllCall.close();
            }
        }

I know this is a lot of code but as requested heres the code in the C Dll.....

#include <jni.h>
#include <windows.h>

JNIEnv  *env;
JavaVM  *jvm;
HANDLE  hUserDll;
jclass  jClass;
char*  dllname;

/*
 * Load dll.
 */
HANDLE loadDll(char* name)
{
    HANDLE hDll = LoadLibrary (name);

    if (!hDll) {
        printf ("Unable to load %s\n", name);
        exit(1);
    }

    printf ("%s loaded\n", name);

    return hDll;
}

jint (JNICALL * JNI_GetDefaultJavaVMInitArgs_func) (void *args);
jint (JNICALL * JNI_CreateJavaVM_func) (JavaVM **pvm, void **penv, void *args);



/*
 * Initialize JET run-time.
 */
void initJavaRT(HANDLE myDllHandle, JavaVM** pjvm, JNIEnv** penv)
{
    int            result;
    JavaVMInitArgs args;

    JNI_GetDefaultJavaVMInitArgs_func = 
             (jint (JNICALL *) (void *args))
             GetProcAddress (myDllHandle, "JNI_GetDefaultJavaVMInitArgs");

    JNI_CreateJavaVM_func =
             (jint (JNICALL *) (JavaVM **pvm, void **penv, void *args))
             GetProcAddress (myDllHandle, "JNI_CreateJavaVM");

    if(!JNI_GetDefaultJavaVMInitArgs_func) {
        printf ("%s doesn't contain public JNI_GetDefaultJavaVMInitArgs\n", dllname);
        exit (1);
    }

    if(!JNI_CreateJavaVM_func) {
        printf ("%s doesn't contain public JNI_CreateJavaVM\n", dllname);
        exit (1);
    }

    memset (&args, 0, sizeof(args));
    args.version = JNI_VERSION_1_2;

    result = JNI_GetDefaultJavaVMInitArgs_func(&args);
    if (result != JNI_OK) {
        printf ("JNI_GetDefaultJavaVMInitArgs() failed with result %d\n", result);
        exit(1);
    }

    /*
     * NOTE: no JVM is actually created
     * this call to JNI_CreateJavaVM is intended for JET RT initialization
     */
    result = JNI_CreateJavaVM_func (pjvm, (void **)penv, &args);
    if (result != JNI_OK) {
        printf ("JNI_CreateJavaVM() failed with result %d\n", result);
        exit(1);
    }

    printf ("JET RT initialized\n");
    fflush (stdout);
}


/*
 * Look for class.
 */
jclass lookForClass (JNIEnv* env, char* name)
{
    jclass clazz = (*env)->FindClass (env, name);

    if (!clazz) {
        printf("Unable to find class %s\n", name);
        exit(1);
    }

    printf ("Class %s found\n", name);
    fflush (stdout);

    return clazz;
}


int initDll(char* userDllName) 
{
  jClass = NULL;
  hUserDll = loadDll(userDllName); 
  dllname = userDllName;
  initJavaRT(hUserDll, &jvm, &env); 
  jClass = lookForClass(env, "mooMain/mooGeminiX3/mooGeminiX3IFX");
  return jClass ? 1 : 0;
}

/** finalizeDll() - stop Java VM
 */
void finalizeDll ()
{
    (*jvm)->DestroyJavaVM (jvm);
    FreeLibrary((HMODULE)hUserDll);
    hUserDll = NULL;
    jClass   = NULL;
}


jobject newClassInstance()
{

    jmeth开发者_运维知识库odID MID_init;
    jobject obj;
    jstring name;
    jobjectArray ret;
    jclass sclass;
    jobjectArray arr;

    MID_init = (*env)->GetMethodID (env, jClass, "<init>", "([Ljava/lang/String;)V");
    if (!MID_init) {
        printf("Error: dllClass.<init>() not found\n");
        return NULL;
    }
    sclass = (*env)->FindClass(env, "java/lang/String");
    arr = (*env)->NewObjectArray(env, 6, sclass, NULL);


    name = (*env)->NewStringUTF(env,"@C:\\Users\\Ash\\Desktop\\moo-Test\\moo-Test\\mooRoot.cfg");
    (*env)->SetObjectArrayElement(env,arr,0,name);  
    name = (*env)->NewStringUTF(env,"-cfg");
    (*env)->SetObjectArrayElement(env,arr,1,name);
    name = (*env)->NewStringUTF(env,"C:\\Users\\Ash\\Desktop\\moo-CVS\\moo-PCB\\Application\\Configuration\\Linear\\Application\\moo.cfg");
    (*env)->SetObjectArrayElement(env,arr,2,name);
    name = (*env)->NewStringUTF(env,"-startupLog");
    (*env)->SetObjectArrayElement(env,arr,3,name);  
    name = (*env)->NewStringUTF(env,"C:\\Users\\Ash\\Desktop\\moo-Test\\moo-Test\\Log\\mooStartup.log"); 
    (*env)->SetObjectArrayElement(env,arr,4,name);
    name = (*env)->NewStringUTF(env,"-geminiX3"); 
    (*env)->SetObjectArrayElement(env,arr,5,name);












    obj = (*env)->NewObject(env, jClass, MID_init, arr);
    if (!obj) {
        printf("Error: failed to allocate an object\n");
        return NULL;
    }
    return obj;
}

const char* request(jobject obj, char* input )
{
    jstring inputString;
    jstring outputString;
    const char *nativeString;


    jmethodID mID = (*env)->GetMethodID (env, jClass, "request", "(Ljava/lang/String;)Ljava/lang/String;");
    if (!mID){
        printf("\nError: dllClass.request() not found\n");
        return 0;
    }
    printf("here"); fflush(stdout);
    inputString = (*env)->NewStringUTF(env, input);
    printf("here2"); fflush(stdout);

    outputString = (*env)->CallObjectMethod(env, obj, mID, inputString);    

    nativeString = (*env)->GetStringUTFChars(env, outputString, 0); 


    return nativeString;
}

void voidtest(jobject obj )
{/*
    jmethodID mID = (*env)->GetMethodID (env, jClass, "request", "([Ljava/lang/String;)[Ljava/lang/String;");

    if (!mID){
        printf("\nError: dllClass.request() not found\n");
        return 0;
    }

    char inputString[] = (*env)->NewStringUTF(env, "Moo");

    (*env)->CallVoidMethod(env, obj, mID, inputString);*/
}   

void close()
{
    jmethodID mID = (*env)->GetMethodID (env, jClass, "close", "()V");
    if (!mID){
        printf("\nError: dllClass.close() not found\n");
    }

    (*env)->CallVoidMethod(env,jClass, mID);
}


int invokeStaticMethod()
{
    jmethodID MID_init;
    jobject obj;
    jstring name;
    jobjectArray ret;
    jclass sclass;
    jobjectArray arr;
    jmethodID mID = (*env)->GetStaticMethodID(env, jClass, "start", "([Ljava/lang/String;)V");

    if (!mID){
        printf("\nError: dllClass.sfstart() not found\n");
        return 0;
    }

    sclass = (*env)->FindClass(env, "java/lang/String");
    arr = (*env)->NewObjectArray(env, 5, sclass, NULL);


    name = (*env)->NewStringUTF(env,"@C:\\Users\\Ash\\Desktop\\moo-Test\\moo-Test\\mooRoot.cfg");
    (*env)->SetObjectArrayElement(env,arr,0,name);  
    name = (*env)->NewStringUTF(env,"-cfg");
    (*env)->SetObjectArrayElement(env,arr,1,name);
    name = (*env)->NewStringUTF(env,"C:\\Users\\Ash\\Desktop\\moo-CVS\\moo-PCB\\Application\\Configuration\\Linear\\Application\\moo.cfg");
    (*env)->SetObjectArrayElement(env,arr,2,name);
    name = (*env)->NewStringUTF(env,"-startupLog");
    (*env)->SetObjectArrayElement(env,arr,3,name);  
    name = (*env)->NewStringUTF(env,"C:\\Users\\Ash\\Desktop\\moo-Test\\moo-Test\\Log\\mooStartup.log"); 
    (*env)->SetObjectArrayElement(env,arr,4,name);



    (*env)->CallStaticVoidMethod(env,jClass, mID, arr);
    printf("\nGot to here\n");

    return 1;
}

Kind Regards

Ash


This usually happens when you have an incorrect parameter list or mismatching calling convention.

You really ought to know what calling convention the other DLL is. If it is cdecl then you change your P/invoke to:

[DllImport("Stubs", CallingConvention=CallingConvention.Cdecl)]

You need to do this for all imports.

The other thing to check is that your parameter lists match. You only showed one side of the boundary so we can't check that for you. If you added the other side then we may be able to spot something.


Updated following addition of C code

I have the following comments on your code:

The parameters for the C# declaration of initDll match the C declaration so I'm pretty confident that the issue is that your C code uses cdecl calling convention. The C# P/invoke defaults to stdcall. Change the calling convention in one or the other, but not both!

You are matching jobject with UInt32. I'm not sure about this since I don't know JNI. However, I suspect you should be returning jobject* and matching with IntPtr. It looks to me as though jobject is a class type and not something that you can marshal to C#.

Finally, one of your methods returns a string. That just won't work. The C# marshaller will attempt to deallocate it with a call to CoTaskMemFree. That will leak or bomb, dependent on which Windows version you have. You should return an IntPtr and use Marshal.PtrToStringAnsi to marshal it into a C# string. Then you need to deallocate the memory returned by the JNI code. Not sure how you plan to do that. Of course, if your strings are really UTF-8 then you would need to copy to a byte array and then use Encoding.UTF8 to convert to a C# string.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜