我用JNI去调用一个DLL,这个DLL使用了COM。我在DllMain里初始化COM:BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
 )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
::CoInitialize(NULL);
break; case DLL_PROCESS_DETACH: ::CoUninitialize();
break;
    }
    return TRUE;
}在一个DLL的导出函数connect里使用COM:JNIEXPORT void JNICALL Java_opcjni_connect(JNIEnv *e, jobject obj)
{
    //::CoInitialize(NULL);           //问题来了:如果注释这句
    HRESULT hr=::CoCreateInstance(cls,NULL,CLSCTX_ALL,IID_IServer,(void**)&pServer);
    _com_error err(hr);
    ::MessageBox(NULL,err.ErrorMessage(),"CoInitialize",0); //则报错:COM没有初始化
}而我用VC++写的程序去调同一个DLL,则没有问题。想了几天,一直没有解决这个问题,请教大家到底是哪有问题呢?

解决方案 »

  1.   

    CoInitialize是单线程的。
    用CoInitializeEx(COINIT_MULTITHREADED)可以初始化多线程的。
    case DLL_PROCESS_ATTACH: 
    ::CoInitializeEx(COINIT_MULTITHREADED); 
    break; case DLL_PROCESS_DETACH: ::CoUninitialize(); 或者,你在DllMain里对每个线程都初始化
    case DLL_THREAD_ATTACH: 
    ::CoInitialize(NULL); 
    break; 
    case DLL_THREAD_DETACH: 
    ::CoUninitialize(); 
      

  2.   

    sorry,刚看了一下MSDN.CoInitialize和CoInitializeEx都是初始化当前线程的,而且在DllMain里调用它们都是不可靠的。
      

  3.   

    主要问题是很明显没有错误的DLL代码,JNI去调这个DLL有问题,而VC写的DLL去调就没有问题。好像JNI去调的时候,出了某个函数,所有的已进行过的行为(如初始化COM)都无效了一样。
      

  4.   

    如果不考虑动态卸载相关的DLL资源,你就在JNI函数里调::CoInitialize应该就可以了。多次调用CoInitialize应该是没有什么问题的。
      

  5.   

    我感觉会不会是JNI调DLL的时候的线程管理的方式和VC程序调DLL的时候不一样。一个很简单的例子,我的目的是JNI通过调用DLL去异步读一个COM数据源的数据,读完以后再把数据返回给Java程序进行一些处理。在DLL里,一个函数connect连接数据源,一个函数readAsync通过出接口异步读数据,读完会自动调用一个实现了出接口的类的OnDataReadComplete函数,在这个OnDataReadComplete函数里只要一个简单的功能,::MessageBox读到的数据。我用VC程序去连这个DLL完全没有问题,在VC程序里,点击一个按钮实现以上过程,可以成功立刻MessageBox读到的数据,但是我用JNI去连这个DLL的时候,问题很奇怪,在Java程序里点击一个按钮实现以上过程,没有任何反应,但是关闭Java程序的时候,那个MessageBox框却出现了,而且数据也对,点了这个MessageBox框,整个程序才退出。实在搞不懂!核心代码在下面:DLL:JNIEXPORT void JNICALL Java_opcjni_connect(JNIEnv *e, jobject obj) 

        HRESULT hr=::CoCreateInstance(cls,NULL,CLSCTX_ALL,IID_IServer,(void**)&pServer); 
    } JNIEXPORT void JNICALL Java_opcjni_readAsync(JNIEnv *e, jobject obj)
    {
        IConnectionPoint *pCP=NULL;
        IConnectionPointContainer *pCPC=NULL;
        IDataRead *pIO=NULL;    IUnknown *pUnk;    pUnk->QueryInterface(IID_IConnectionPointContainer,(void**)&pCPC);
        pCPC->FindConnectionPoint(IID_IDataReadCompleted,&pCP);    IDataReadCompleted *pDRC=new CDataReadCompleted(e,obj);
        DWORD dwC;
        pCP->Advise(pDRC,&dwC);

        hr=pIO->Read();

        //::MessageBox(NULL,"1","caption",0);    //如果加这句,则java程序可以正确立刻调                                             //用::OnDataReadComplete 的MessageBox,如不加,                                             //则要到java程序关闭才会调用

    }类CDataReadCompletedSTDMETHODIMP CDataReadCompleted ::OnDataReadComplete (float f)
    {    char c[256];
        sprintf(c,"this %f",f);
        ::MessageBox(NULL,c,"caption",0);    return S_OK);
    }
      

  6.   

    提醒你:所有UI操作都是线程相关的,即使是MessageBox;Java UI操作和Windows UI操作是不兼容。
    具体原因你要自己分析了。
    你把MessageBox改成printf或System.out.println看看能否正确输出。
      

  7.   

    我试了OutputDebugString问题还是一样。这个问题实在奇怪,我再看看。最近学习Java和COM的交互,流程基本明白了,主要目的是达到了。这个问题算是枝节小问题了,但是心里老是觉得有什么事没有完成一样。