Click to See Complete Forum and Search --> : Assembly references resolution in an In Process managed com server


roeeoz
June 27th, 2007, 09:42 AM
Hello All.

I have a managed InProc (in process) ATL COM server.
My ATL COM server is a shell property page which is loaded by Explorer.exe.

In this COM server I am using remoting to get data from a local “.net” exe server. I also have a project IprofInfoProvider which defines the interface of the remote server object. I added a reference to the IprofInfoProvider project into the COM server, and got a FileNotFoundException when Explorer loads my COM server.

Just to be sure my code is OK, I did it all without a reference, using only reflection, and it worked.

I now went to look at fuslogvw.exe output and saw that indeed Explorer.exe searches for the assembly in C:/WINDOWS/ (instead of the COM server build dir) and naturally, fails.

Can anybody know how to fix this? What I want is a way to tell the CLR to search for assemblies in the build directory of the COM server, not of the EXE it is loaded into.

Details:
Projects:
- PropPage : COM ATL InProc server, in managed C++ , loaded by explorer.exe
- IprofInfoProvider : “.net” interfaces only project.

The PropPage references the IprofInfoProvider.
When loading the PropPage, an exception is thrown saying the IprofInfoProvider was not found.

fuslogvw.exe output:
*** Assembly Binder Log Entry (27-Jun-07 @ 3:54:04 PM) ***

The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.

Assembly manager loaded from: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
Running under executable C:\WINDOWS\Explorer.EXE
--- A detailed error log follows.

=== Pre-bind state information ===
LOG: User = SECUREISLANDS\roee
LOG: DisplayName = IprofInfoProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
(Fully-specified)
LOG: Appbase = file:///C:/WINDOWS/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = Explorer.EXE
Calling assembly : (Unknown).
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/WINDOWS/IprofInfoProvider.DLL.
LOG: Attempting download of new URL file:///C:/WINDOWS/IprofInfoProvider/IprofInfoProvider.DLL.
LOG: Attempting download of new URL file:///C:/WINDOWS/IprofInfoProvider.EXE.
LOG: Attempting download of new URL file:///C:/WINDOWS/IprofInfoProvider/IprofInfoProvider.EXE.
LOG: All probing URLs attempted and failed.

roeeoz
July 1st, 2007, 07:48 AM
OK found a way to do it.

Wrote this class:
public ref class CAssemblyResolver
{
public:

static Assembly^ SIResolveEventHandler(Object^ sender, ResolveEventArgs^ args)
{
String^ path = Assembly::GetExecutingAssembly()->CodeBase;
array<Char>^ pathSep = {'\\','/'};
path = path->Substring(0, path->LastIndexOfAny(pathSep) + 1);
String^ file = args->Name->Substring(0, args->Name->IndexOf(L',')) + ".dll";
return Assembly::LoadFrom(path + file);
}


static void Init(void)
{
AppDomain::CurrentDomain->AssemblyResolve += gcnew ResolveEventHandler(SIResolveEventHandler);
}
};

Just include it in a cpp file in your In Process COM server, and call Init() before any assembly is trying to load