実行中のアプリケーションにJava 7を挿入した方法、およびCランタイム用に発明しなければならなかったこと

画像



寒い冬に、何年も前から正常に機能していた古いC ++アプリケーションで、完全に機能するJava 6の代わりに新しいJavaランタイム7を挿入する必要がありました。



コードは一般的に明白で単純です-少しJNI で、ここでは-悪い歯です。 Windows専用のコードを提供します。 ケシの下でバランスを取ることの不思議は必要ありませんでした。







どうでしたか



何年も前に、標準的な方法で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時間半の間、次のことが判明しました。



  1. メインプログラムの以前のバージョンとそのためのJavaプラグインは、2003〜2008年のビジュアルスタジオ(MSVCR80.dll、MSVCR90.dllなど)、およびJava 6でそれぞれコンパイルされ、MSVCR71.dllの希少性がありました。
  2. 新しいJavaはMSVCR100.dllを使用してコンパイルされます(ええ、ええ)。 そして、顧客のプログラムのバージョンはMSVCR90.dllを使用します。 ロードされません。




グーグルは機能しませんでした-マニフェストを処方および削除すると、重量ごとにゼロが得られ、同じ結果になりました。



タンバリン



画像

そして、大きなファイルがポケットから引き出され小道具の別のモンスターが生まれました。 そして、1つのSetDllDirectoryの代わりに、これが起こったのです。



  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/



All Articles