寒い冬に、何年も前から正常に機能していた古いC ++アプリケーションで、完全に機能するJava 6の代わりに新しいJavaランタイム7を挿入する必要がありました。
コードは一般的に明白で単純です-少しJNI
どうでしたか
何年も前に、標準的な方法でjvm.dllにリンクされた簡単なDLLを作成し、その中の2つ半の関数をエクスポートし、動的に「引き出し」ました。 この耳のかすかなことは明らかです-Java自体がどこにあるのかを見つける必要があります。 この単純なプロキシは、このようなものと呼ばれていました
bool LoadJavaEngine(HANDLE& engHandle) { bool loadResult = false; do { ... // here we have auto variables, nothing interesting // first we need to find java CRegKey rk; if(rk.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.6", KEY_QUERY_VALUE) != ERROR_SUCCESS || rk.QueryValue(strBuf, L"RuntimeLib", &strBufSz) != ERROR_SUCCESS) break; WCHAR* backslashAddr = wcsrchr(strBuf, L'\\'); if(backslashAddr) BufLen = backslashAddr - strBuf; strBuf[BufLen] = L'\0'; // now C runtime knows where is jvm.dll located retnPWD = SetDllDirectoryW(strBuf); // ... nothing intersting - in the same manner we're looking for our proxy path in registry if((engHandle = LoadLibrary(strBuf))==NULL) break; // now try to initialize JVM by calling our proxy linked with jvm.dll CreateJavaVMFunPtr CreateJavaVM = (CreateJavaVMFunPtr)GetProcAddress(engHandle, "CreateJavaVM"); if(CreateJavaVM) loadResult = CreateJavaVM(needJNIProxy); } while(false); return loadResult; }
思いがけないレーキ
ご覧のとおり、コードは非常にシンプルで、一般に3行もかかります
SetDllDirectory LoadLibrary GetProcAddress
そして今-私たちは複雑です。 Java 6では、Java 7に移行しています。楽観的な予測はこのようなものでした。1行変更するだけですべてが機能します。
変更
if(rk.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.6",
に
if(rk.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.7",
そして
テレパシーセッション
手続きの1時間半の間、次のことが判明しました。
- メインプログラムの以前のバージョンとそのためのJavaプラグインは、2003〜2008年のビジュアルスタジオ(MSVCR80.dll、MSVCR90.dllなど)、およびJava 6でそれぞれコンパイルされ、MSVCR71.dllの希少性がありました。
- 新しいJavaはMSVCR100.dllを使用してコンパイルされます(ええ、ええ)。 そして、顧客のプログラムのバージョンはMSVCR90.dllを使用します。 ロードされません。
グーグルは機能しませんでした-マニフェストを処方および削除すると、重量ごとにゼロが得られ、同じ結果になりました。
タンバリン
そして、大きなファイルがポケットから引き出され
wcscat(strBuf, L"\\msvcr100.dll"); test = LoadLibraryW(strBuf); strBuf[BufLen] = L'\0'; wcscat(strBuf, L"\\client\\jvm.dll"); test = LoadLibraryW(strBuf); if(test == 0) { strBuf[BufLen] = L'\0'; wcscat(strBuf, L"\\server\\jvm.dll"); test = LoadLibraryW(strBuf); } strBuf[BufLen] = L'\0'; retnPWD = SetDllDirectoryW(strBuf);
つまり、MSVCR100.dllから開始して依存関係を手動でロードすると、検出されて機能します。 そうでなければ、悲しいかな。
免責事項:「新しいバージョンを顧客に提供する」オプションは適切ではありません。 メインアプリケーションはAdobe InDesign Server CS5で、ライセンスあたり$ 7kです。
有刺鉄線の詳細は、このトピックに関する以前の出版物に記載されています。
http://habrahabr.ru/post/122746/
http://habrahabr.ru/post/127574/