由于要做短信,买了一台GSM Modem,提一个C++的DLL开发接口,DLL文件名:sms.dll,这个dll用VC编译应用程序测试完全正常。
由于需要在Java里面调用,则要用VC按jni规范重新封装sms.dll成dll才能被java调用。在用VC重新封装sms.dll的dll中可以加载sms.dll,但用GetProcAddress取不到sms.dll函数中的入口地址,返回错误代码(126:找不到指定模块),用depends查看函数书写正确,就是找不到。问题要点:1.sms.dll用VC程序测试调用正常;
          2.sms.dll再封装成dll,在新dll中就找到调用函数的入口地址。真是奇了怪了,请高人帮忙。我的QQ:999975

解决方案 »

  1.   

    错误码126表示GetProcAddress的第1参数无效,也就是HMODULE无效,程序中这个参数是怎么来的?显式加载应该用LoadLibrary获得,如果是隐式加载也可以用GetModuleHandle获得。
      

  2.   

    代码如下:
    HINSTANCE hinstDLL=NULL;JNIEXPORT jint JNICALL Java_com_rhinofield_common_GsmModemInterface_sms_1LoadSmsDll
      (JNIEnv *env, jclass, jstring cls)
    {
    if(hinstDLL==NULL)
    {
    //加载DLL
    hinstDLL=LoadLibrary(_T("sms.dll"));
    if(hinstDLL==NULL)
    return 0;
    }
    return 1;
    }JNIEXPORT jint JNICALL Java_com_rhinofield_common_GsmModemInterface_sms_1UnloadSmsDll
      (JNIEnv *env, jclass cls)
    {
    if(hinstDLL!=NULL)
    {
    //卸载DLL
    FreeLibrary(hinstDLL);
    return 1;
    }
    return 0;
    }JNIEXPORT jstring JNICALL Java_com_rhinofield_common_GsmModemInterface_Sms_1Connection
      (JNIEnv *env, jclass cls, jstring copyRight, jint com_Port, jint com_BaudRate)
    {
    const char *cr=env->GetStringUTFChars(copyRight, NULL);
    //CString csCopyRight="";
    //csCopyRight.Format(_T("%s"),cr);
    //env->ReleaseStringUTFChars(copyRight, cr); //char *buffer2=(char *)(LPCTSTR)csCopyRight;
    //jstring result = env->NewStringUTF(buffer2);
    //env->ReleaseStringUTFChars(copyRight, cr);
    //return result; char *buffer2=NULL;
    //CString mobile_Type[256];
    if(hinstDLL==NULL)
    buffer2="1:hinstDLL=NULL";
    else
    {
    //typedef int(_stdcall *Sms_Connection)(int Com_Port,int Com_BaudRate,CString *Mobile_Type);
    //Sms_Connection Proc=(Sms_Connection)GetProcAddress(hinstDLL,"Sms_Connection");
    typedef int(_stdcall *Sms_NewFlag)();
    Sms_NewFlag Proc = (Sms_NewFlag)GetProcAddress(hinstDLL,"Sms_NewFlag");
    ************************在这个地方出错,Proc=NULL*********************
    if(Proc==NULL)
    {
    DWORD abc=GetLastError();
    buffer2=new char[10];
    _ultoa( abc, buffer2, 10 );
    //buffer2="2:Proc=NULL";
    }
    else
    {
    buffer2="3:Proc!=NULL";
    /*
    int rtnValue = Proc(com_Port,com_BaudRate,mobile_Type);
    if(rtnValue==0)
    buffer2="3:rtnValue=0";
    else
    {
    CString temp="1;"+*mobile_Type;
    buffer2=(char *)(LPCTSTR)temp;
    }
    */
    }
    }
    jstring result = env->NewStringUTF(buffer2); /*
    CString temp="";
    temp.Format(_T("%d"),rtnValue);
    if(rtnValue!=0)
    {
    temp=temp+";"+*mobile_Type;
    }
    buffer=(char *)temp.GetBuffer();
    jstring result = stoJstring(env,buffer);
    */
    //free(buffer);
    return result;
    }
      

  3.   

    那就是hinstDLL无效,你调试看看最初LoadLibrary得到的值是多少,执行到GetProcAddress时变量的值是否发生了变化,另外注意中间有没有FreeLibrary。
      

  4.   


    LoadLibrary最初值是1,GetProAddress时的值是119537664
    汗一个,是不是hinstDLL的状态没有保存?
      

  5.   

    LoadLibrary返回1?正常情况下LoadLibrary是不会返回1的,如果成功,应该是一个很大的值,如果失败,应该是0。你是不是用Release版调试的?要用Debug版来调,实在不行就用MessageBox把值显示出来,或者写到日志文件里面来看。
      

  6.   

    执行到DWORD abc=GetLastError()得到了126是吗?看看中间有没有FreeLibrary。
      

  7.   

    可以确认一点,DLL是成功被加载了的
      

  8.   


    中间肯定没有FreeLibrary
    java调用代码如下:        int value=sms_LoadSmsDll("");
            System.out.println("DLLHandle="+value);
            if(value!=0)
            {
                String rtnValue=Sms_Connection("Hello,world!",5,9600);
                if(rtnValue.length()<=1)
                {
                    System.out.println("Connection failed!");
                }
                else
                {
                    System.out.println("Connection success!Mobile_Type="+rtnValue.substring(0));
                }
            }
            else
            {
                System.out.println("Open sms.dll failed!");
            }
            value=sms_UnloadSmsDll();
            if(value==1)
                System.out.println("close sms.dll success!");
            else
                System.out.println("close sms.dll failed!");
            return 0;
      

  9.   


    是126,意思是找不到模块。我用depends看过,函数名称书写正确,况且在VC应用程序里面调用sms.dll是可以的,在DLL里面就出问题
      

  10.   

    这样试一下,在GetProcAddress之前再通过LoadLibrary重新获取HMODULE,调用完Proc之后再FreeLibrary。
      

  11.   


    这样是可以的,谢谢兄弟!但如果不用全程变量,哪么LoadLibrary只能放在函数里面,则每调用一次函数就要加载DLL,这样效率会很低,兄弟有没有其他解决办法?
      

  12.   

    这个DLL肯定是不知在什么时候被Free了,我不了解java调DLL的原理,有可能它是每次调用时Load,调用后立即Free的。其实这种做法只要不是频繁调用,是不会影响效率的。
    你可以试试在sms.dll的DllMain中的DLL_PROCESS_DETACH分支中加个断点,当执行到断点时,根据调用堆栈来看是哪里调用的FreeLibrary。
      

  13.   

    java就是混乱。不像c++,自己管理资源,多好。实在不行就每次LoadLibrary吧。
      

  14.   


    每调用一次函数就要加载DLL?这样啊?哪有这么囧的?不妨把所有要调用的函数设为全局成员变量,LoadLibrary后都GetProcAddress掉。建议可以弄个结构体数组,数组元素由函数名和函数地址2个元素组成,这样很方便
      

  15.   

    放心,Java再搓也不会一GetProcAddress就FreeLibrary的。
      

  16.   

    这个就能肯定是HMODULE被Free了
      

  17.   

    问题解决了,谢谢cnzdgs兄!解决办法:用VC6编译,hinstDLL全局变量没有问题
      

  18.   

    你的LoadLibrary()应该是失败的,而且错误码是126
      

  19.   

    你的LoadLibrary()应该是失败的,而且错误码是126
      

  20.   

    注意调用DLL时的参数传递。
    声明入口函数的时候加上Extern C