Using Reflection with nested DLLs

  • Thread starter Thread starter News
  • Start date Start date
N

News

I'm using System.Reflection utility to load and execute a user written
DLL routine. This has worked well before.

I wrote two .NET DLLs. The first (let's call it DLL1) has a public
class (C1) with a public function (F1).

The second DLL also has a public class with a public function (DLL2, C2
and F2). The second DLL references the first. It creates an instance
of the first DLL class and executes the function.
From a test program everything works great. When I build the second
DLL it brings the first DLL along as a required component.

But when I call dynamically using the Reflaction utility it fails. The
primary exception message is :

"Exception has been thrown by the target of an invocation."

The more detailed inner exception is :

"File or assembly name DLL1, or one of its dependencies, was not
found."

Any idea why it can't find the referenced DLL, even though it is right
there in the same folder as the DLL begin invoked?

Mike Buchanan
 
Hi Mike,

Can you please post the code that loads and executes the DLL? Loading
assemblies with reflection can be tricky.
Also, you can use the Fusion Log Viewer tool (fuslogvw.exe) from the
Framework SDK to see where the loader probes for the DLL.
 
Dmytro,

For the moment I moved the function from the second DLL into the first DLL
and it's now working. I could do it this time but maybe not for all cases
in the future.

When someone wants to add a call to a new routine they add a new entry in
the db that gives two things; 1) the full file spec of the .DLL file and 2)
the name of the class.function to call. There are a standard set of
parameters that the function must use and I didn't make them include the
namespace.

The code that finds, loads and call the routine is:

const string routine_name = "PerformDLLRoutine";

bool ret_status;
Assembly theDLLFile;
object result;
int dotPosition;
string className;
string methodName;
Type classObj = null;
object classInstance;
string TypeFullName = "";
object[] args = new object[5];
object[] createArgs = new object[1];

//********************************************************
//* Break the inDLLRoutine into the Class and method.
//********************************************************
dotPosition = inDLLRoutine.IndexOf(".");
className = inDLLRoutine.Substring(0, dotPosition);
methodName = inDLLRoutine.Substring((dotPosition + 1),
(inDLLRoutine.Length - dotPosition - 1));

//********************************************************
//* Load the .NET DLL file.
//********************************************************
theDLLFile = System.Reflection.Assembly.LoadFile(inDLLFileSpec);

//********************************************************
//* Get list of public Classes and find the one with the
//* routine that we want to call.
//*
//* Note that there is a routine that will get a specific
//* Type object (in our case the class) but you need to specify
//* the full name, which is the namespace.className. I assume
//* that in most cases each DLL will only have one class so
//* getting the list and iterating through it should be quick
//* enough.
//********************************************************
Type[] types = theDLLFile.GetTypes();
foreach(Type type in types)
{
if (type.Name == className)
{
classObj = type;
TypeFullName = type.FullName;
break;
}
}

if (classObj == null)
{
outCompletionMsg = "Class \"" + className + "\" not found";
Trace.end_routine(
routine_name,
false,
outCompletionMsg);
return false;
}

//********************************************************
//* Need to create an instance of the class before you can
//* call a non-static method.
//********************************************************
createArgs[0] = true;

//************************************************************
//* Production. Default class constructor.
//************************************************************
classInstance = theDLLFile.CreateInstance(
TypeFullName,
true,
System.Reflection.BindingFlags.Default,
null,
null,
null,
null);

//********************************************************
//* Set the parameters to the method. The methods are all
//* required to take 3 input parameters and one output. In
//* addition the routine should return a boolean value.
//********************************************************
args[0] = inParam1;
args[1] = inParam2;
args[2] = inParam3;
args[3] = inParam4;
args[4] = ""; // this will be the completion msg

result = classInstance.GetType().InvokeMember(
methodName,
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
classInstance,
args);

ret_status = Convert.ToBoolean(result);
outCompletionMsg = args[4].ToString();
 
Before this thread dies I want to say that I still haven't figured this
out yet.

I should point out that the code I posted above seems to be OK since it
finds and loads the primary DLL just fine, which should be all you need
to do. When you load a DLL you shouldn't have to know, or care, what
other programs it references.

As I mentioned before when I moved the routine from the second DLL into
the first one it worked, so the reflection code is finding, loading and
executing the routine correctly. Another interesting thing is that the
DLL references at least one other DLL that I didn't write and they get
called OK, so there must be something about the way that I defined my
first DLL or referenced it that is causing this but I can't seem to see
anything.

Dmytro mentioned using the Fusion Log Viewer tool (fuslogvw.exe). I
found the program but am still trying to find some documentation. If
ran it but it doesn't show *anything*, which I assume means that
there's something I need to set up or enable.

Mike Buchanan
 
Back
Top