- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
有点不寻常的问题。
我发现只有在通过 visual studio 运行程序时才会抛出错误。如果我编译应用程序并运行编译后的程序,它就可以正常工作。有什么想法会导致这种情况吗?
我有一个 C# 类,它通过 JNI 调用 Java DLL(通过 excelsior jet 编译)中的方法。
当我编译并运行 C# 类和可执行文件时,一切正常。现在我已经将 C# 类构建为 DLL,并试图从另一个类调用它。
此时我收到以下错误消息:对 PInvoke 函数“Test!DllCall::initDll”的调用使堆栈失衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。
谁能解释为什么我会收到这个问题以及如何解决它?
如果您需要更多代码/信息,请告诉我
这是 C# 代码:
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();
}
}
我知道这是很多代码,但根据要求,这是 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()
{
jmethodID 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;
}
亲切的问候
灰
最佳答案
当您的参数列表不正确或调用约定不匹配时,通常会发生这种情况。
你真的应该知道另一个 DLL 是什么调用约定。如果它是 cdecl
那么您将 P/invoke 更改为:
[DllImport("Stubs", CallingConvention=CallingConvention.Cdecl)]
您需要为所有导入执行此操作。
要检查的另一件事是您的参数列表是否匹配。您只显示了边界的一侧,因此我们无法为您检查。如果您添加了另一面,那么我们可能会发现一些东西。
在添加 C 代码后更新
我对您的代码有以下评论:
initDll
的 C# 声明的参数与 C 声明相匹配,因此我非常确信问题在于您的 C 代码使用了 cdecl
调用约定。 C# P/invoke 默认为 stdcall
。更改其中一个调用约定,但不能同时更改两个调用约定!
您正在将 jobject
与 UInt32
匹配。我不确定这一点,因为我不知道 JNI。但是,我怀疑您应该返回 jobject*
并与 IntPtr
匹配。在我看来,jobject
是一种类类型,而不是您可以编码为 C# 的类型。
最后,您的方法之一返回一个字符串
。那是行不通的。 C# 编码器将尝试通过调用 CoTaskMemFree
来释放它。这会泄漏或爆炸,具体取决于您拥有的 Windows 版本。您应该返回一个 IntPtr
并使用 Marshal.PtrToStringAnsi
将其编码为 C# 字符串。然后您需要释放 JNI 代码返回的内存。不确定你打算如何做到这一点。当然,如果您的字符串确实是 UTF-8,那么您需要复制到字节数组,然后使用 Encoding.UTF8 转换为 C# 字符串。
关于c# - 对 PInvoke 函数 'Test!DllCall::initDll' 的调用使堆栈失衡,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7567590/
出于好奇 - 我知道有 LAMP - Linux、Apache、MySQL 和 PHP。但是还有哪些其他 Web 堆栈替代方案的缩写呢?像 LAMR - Linux、Apache、MySQL Ruby
我有以下代码。 var stackMapIn = []; var stackMapOut = []; var stackBack = []; stackMapOut.push("m1"); $scop
我遇到了导致我的堆栈无法恢复的情况,我别无选择,只能将其删除。使用完全相同的模板,我继续创建了另一个同名的堆栈。 The following resource(s) failed to create:
这是我第一次查看 Node 堆栈,自从我学习使用 Ruby on Rails 进行 Web 开发以来,我对一些基本的东西有点困惑。我了解 Rails 目录是什么样的。 demo/ ..../app .
本文实例讲述了C语言使用深度优先搜索算法解决迷宫问题。分享给大家供大家参考,具体如下: 深度优先搜索 伪代码 (Pseudocode)如下: ?
我正在按照指南 here ,它告诉我: The stack setup will download the compiler if necessary in an isolatedlocation (
同时 trying to debug a different question ,我安装了一个似乎与我安装的其他一些软件包冲突的软件包。 我跑了 $ stack install regex-pcre-
我花了几个小时创建了一个方法,该方法将从堆栈 s1 中获取 null 元素,并将它们放入 s2 中。然后该类应该打印堆栈。方法如下 import net.datastructures.ArraySta
我有一个类Floor,它有一个Stack block ,但我不知道如何初始化它。我曾尝试过这样的: public class Floor { private Stack stack;
我知道这个问题已经问过很多次了,但搜索一个小时后我仍然遇到问题。 我想使用一个 lifo 堆栈,它可以存储最大数量的元素。达到最大数量后,首先删除该元素并将其替换为新元素,这样在第一次弹出时我可以获取
我需要编写一个方法,压缩以执行以下操作; 目标compress方法是从栈s1中移除所有null元素。剩余(非空)元素应按其初始顺序保留在 s1 上。辅助堆栈 s2 应用作s1 中元素的临时存储。在该方
我正在尝试验证以下代码发生的顺序。 function square(n) { return n * n; } setTimeout(function(){ console.log("H
我需要一个字符数组,其中包含基于特定文件夹中文件数量的动态数量的字符数组。我能够通过初始化 char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LENGTH
我正在编写一些日志逻辑并想要进行一些缩进。了解是否存在任何函数调用或某个函数是否已完成的最简单方法是查看堆栈/帧的当前地址。让我们假设堆栈颠倒增长。然后,如果 log() 调用中的堆栈地址小于前一次调
所以内存分段在x86-64中被放弃了,但是当我们使用汇编时,我们可以在代码中指定.code和.data段/段,并且还有堆栈指针寄存器。 还有堆栈段、数据段和代码段寄存器。 代码/数据/堆栈的划分是如何
void main() { int x = 5; // stack-allocated Console.WriteLine(x); } 我知道 x 是堆栈分配的。但是关于 x 的堆栈中
这是我关于 SO 的第一个问题。这可能是一个愚蠢的问题,但到目前为止我还没弄明白。 考虑下面的程序 Reader.java: public class Reader { public
java中有没有一种快速的方法来获取嵌套/递归级别? 我正在编写一个函数来创建组及其成员的列表。成员也可以是团体。我们最终可能会得到一组循环的组/成员。 我想在某个任意级别停止。 我知道我可以将变量保
考虑以下代码: struct A{...}; A a[100]; A* pa = new A[100]; delete[] pa; a/pa 元素的销毁顺序是由标准定义的还是实现定义的(对于第二种情况
我在下面有一些代码。此代码是一个基本的压入/弹出堆栈类,我将其创建为模板以允许某人压入/弹出堆栈。我有一个家庭作业,我现在要做的是创建一个具有多个值的堆栈。 所以我希望能够创建一个基本上可以发送三个整
我是一名优秀的程序员,十分优秀!