4

I posted this question two days ago in Microsoft Community. I got some good ideas and did some experiments, but still failed. For more help, I decide to post this question here. (The original post: Is it possible for a process to load two dll with different versions?)

I developed a word all-in application which is a dll that can be loaded by word and some word-compatible applications (in this question, I call it word-like app, they use the same ooxml standard). My add-in uses the CEF .net binding cefglue (which in turn uses CEF (chromium embedding framework)) to present some web contents. Here are some details in my add-in project.

This add-in's platform target is Any CPU, loaded by this word-like app. When starting up, I check if this add-in is loaded in a 32-bit environment or 64-bit environment by calling Environment.Is64BitProcess. After that, I set the appropriate library path for libcef.dll and other chromium libraries which depends on the application that loads my add-in dll is 64-bit or 32-bit. For example, in 64-bit word, my add-in loads the 64-bit libcef.dll. Some details using pseudocode:

// Files in cef library folder
// locales/
// swiftshader/
// cef.pak
// cef_100_percent.pak
// cef_200_percent.pak
// cef_extensions.pak
// chrome_elf.dll
// d3dcompiler_47.dll
// devtools_resources.pak
// icudtl.dat
// libcef.dll
// libEGL.dll
// libGLESv2.dll
// ...

private _cefPath;
    
void FindLibraryPath() {
  bool is64BitEnv = Environment.Is64BitProcess;
  SetLibraryAndResourcePath(is64BitEnv); // set _cefPath and other path here
}
    
void InitializeCef() {
  // Load cef library
  // this method use LoadLibraryEx with the flag
  // LOAD_WITH_ALTERED_SEARCH_PATH to load libcef.dll
  CefRuntime.Load(_cefPath);
  // other statements for cef initialization
  ...
}

private void ThisAddIn_Startup(object sender, System.EventArgs e) {
  FindLibraryPath();
  InitializeCef();
}

This works well in Microsoft Word, but unluckily, this arises some problems in that word-like app. Here is why:
That word-like app also has its own cef library to load its web contents (some online cover styles, page number styles, and so on, which are ready to be used in the current document). If I opened my add-in in this word-like app, then click some buttons that trigger the word-like app to load its web contents, this word-like app crashed. For analyzing the cause, I should give some facts:

Libraries my addin loads

myaddin.dll(.net) -> cefglue.dll(.net) -> libcef.dll (native dll, version 67) -> other chromium native dll

Libraries word-like app loads

|-> myaddin.dll(.net) -> cefglue.dll(.net) -> libcef.dll (native dll, version 67) -> other chromium native dll
|-> (when loading its own web contents) -> ... -> libcef.dll(native dll, version 87) -> other chromium native dll (in its installation directory)

(-> stands for loads, | stands for an independent possible path to load dlls)

I load libcef.dll using absolute path, if I load this library first, that word-like app won't load its own libcef.dll (the built-in rule of LoadLibraryEx?), it plans to use my libcef.dll then crash, after all it need the version 87. If the word-like app loads libcef.dll first, my add-in won't load the version 67 libcef.dll, then I get the version mismatch exception.

All in all, what I need is to isolate the same name but different version libcef.dll from that word-like app's, making it doesn't perceive the same name dlls loaded by my add-in. Some ideas? Thanks.

Eugene Astafiev
  • 47,483
  • 3
  • 24
  • 45
Lucas
  • 222
  • 3
  • 9
  • I suppose the question is not related to the Word add-in, so the issue is related to using chromium in .net based applications, am I right? – Eugene Astafiev May 26 '22 at 13:35
  • @EugeneAstafiev yes. in fact, it have no related to word add-in. just a question how to load two different version dll in a process. – Lucas May 26 '22 at 13:58
  • @EugeneAstafiev At very start, I didn't know why this error arised, now I can understand why. After making a lot of mistakes, I conceived a solution now (make an experiment, haven't finished the whole codes), use `LoadLibrary` (not `LoadLibraryEx`) to load `my.dll`, in `my.dll` loads `libcef.dll` (`libcef.dll` will load other dlls like `chrome_elf.dll`, if I understand the loading sequence rightly). In `my.dll` I use `GetProcAddress` to search the cef functions, which in turn are used in my add-in. `my.dll` is an abstract layer between my add-in and `libcef.dll`. – Lucas May 26 '22 at 14:01

1 Answers1

3

This is impossible to implement, since libcef.dll has other DLLs in dependencies and you do not control their loading. See Dynamic-Link Library Search Order for details. The important parts of that page is:

  • If a DLL with the same module name is already loaded in memory, the system checks only for redirection and a manifest before resolving to the loaded DLL, no matter which directory it is in. The system does not search for the DLL.
  • If a DLL has dependencies, the system searches for the dependent DLLs as if they were loaded with just their module names. This is true even if the first DLL was loaded by specifying a full path.

The only working solution is making your add-in strictly dependent on another add-in version and building your add-in with using CEF framework with the exact same version. It perhaps will not work if another plug-in is using a custom built CEF framework.

273K
  • 29,503
  • 10
  • 41
  • 64
  • Your words poured cold water on my expectation :) – Lucas May 26 '22 at 15:15
  • I thought I could use `LoadLibrary` then `GetProcAddress` to locate functions. Although I set different current directory before loading library, the handles returned by the two-time `LoadLibrary` are equal. :( – Lucas May 26 '22 at 15:27
  • This is the exact behaviour described on the linked page, if you have not renamed libcef.dll. If you rename it, further loading other CEF libraries will return equal handles. – 273K May 26 '22 at 15:29
  • Thanks for pointing out that, I cannot build this program again that `libcef.dll` installed by the word-like app, or it will make my program fragile. Who knows if the word-like app will change its own `libcef.dll` tomorrow. I have to turn to webview2. – Lucas May 26 '22 at 15:32
  • On your add-in start you can check md5/sha1 of the loaded cef module to be sure it's official and continue run normally. If the checksum is different then show an error about incompatibility with the 3rd add-in. – 273K May 26 '22 at 15:37
  • that's a good idea. that `cefglue.dll` have implemented this idea. If api_hash mismatched, it will pop up a messagebox to show the error message. – Lucas May 26 '22 at 15:43
  • btw, I heard of the concept `activation context`, `manifest` or `sxs`. I don't know its exact meaning, it seems that in c++ we can load a library using a non-default activation contenxt, so that even if other library or executable uses the same name library with mine, they also can load their own version. Do you know this idea? Is it can also be used in C#? If I can use this idea in C++, maybe I can load my `libcef.dll` by another dll, which provides the cef interfaces for my add-in to use. – Lucas May 26 '22 at 15:47
  • You still waste time. You can solve the issue for libcef.dll, but the issues with its dependencies and 3rd add-in are unsolvable. – 273K May 26 '22 at 15:53
  • yeah, I may just be delusional. I can control `libcef.dll`, but not the other libraries loaded by it. Ok, i won't waste time. Tomorrow I plan to migrate this add-in to webview2. thanks for help. – Lucas May 26 '22 at 16:00
  • finally, i sovled this problem using another idea. out-of-process. using another process to load libraries, then create cross-process window and communication by IPC. – Lucas Jun 06 '22 at 15:23