App.path - equivalent - in an interop DLL

  • Thread starter Thread starter Ellen
  • Start date Start date
E

Ellen

Hi --

I'm writing a class library that needs to access files in the same
folder where the DLL will be installed.

I'm having problems retrieving that folder.

I have my DLL in c:\test\mytest.dll that exposes Class1, and a method
FindMe() that returns a string.

I have a console app to test it, which is c:\test\TestApp\TestApp.EXE.
It references mytest.dll. It instantiates a Class1 object and calls
FindMe().

In my DLL, all the System.Reflection.Assembly methods I try keep
returning c:\test\TestApp, rather than c:\test.

It gets even worse if I try to make a test from VB6 (using
CreateObject()), because then the path returned by FindMe() references
the GAC rather than c:\test1.

Are there *any* methods that will return the path where my DLL actually
lives?

Thanks in advance.
 
You should be calling
Assembly.GetExecutingAssembly().Location;
in Class1 of the mytest.dll.

Also, remember that if your running both projects in a solution, the mytest.dll will be copied to the \bin directory of the startup
project.

ChrisG
 
Chris said:
You should be calling
Assembly.GetExecutingAssembly().Location;
in Class1 of the mytest.dll.

I've been doing that. It always returns c:\test\testApp. No doubt due to
the fact that my test app is in the same solution as my DLL, as you
mentioned.
Also, remember that if your running both projects in a solution, the mytest.dll will be copied
to the \bin directory of the startup project.

I think it's the fact of it copying my DLL to the \bin of the startup
project that's throwing me. Is there any way to stop that from
happening? I think I'm just too used to ActiveX DLLs, which can live
(and stay put) wherever you put them.



On a second, related point: I want this to work with COM interop too, so
I can hook it into some existing VB6 apps. AFAIK, part of registering a
..NET DLL for use with interop is registering it into the GAC with
gacutil. Is that strictly necessary?

Because it seems that when I do *that*, the path that gets returned from
VB6 code like:

dim o as object
set o = CreateObject("MyTest.Class1")
msgbox o.FindMe


is c:\windows\assembly\gac\test\1.0.1599.14565__d78c501879e5dc01\mytest.dll


So it seems gacutil really throws things off. I guess it's because
that's actually the executing assembly. Is there any way to trace that
back to its original path (i.e. c:\test\mytest.dll)?


TIA.
 
Chris,

You can specify where the output file (dll) ends up. I put all my dlls in a single directory (...\Build\Bin) and also specify in each references properties that it should not copy the DLL (click on a reference and look at the properties).

To specify an output directory for a VB project, pull up the properties for the project, then click on "Configuration Properties", "Build" and you will see a setting for output path.

C# is a little different, but it is still in the project properties.

Lisa

**********************************************************************
Sent via Fuzzy Software @ http://www.fuzzysoftware.com/
Comprehensive, categorised, searchable collection of links to ASP & ASP.NET resources...
 
Ellen,

I may be a little off on this explanation as far as the details (and I welcome any/all corrections) but the gist of what I'll say
should be accurate...
..NET assemblies by default do not rely on the Registry for calling applications to identify their location so that they can be
loaded in the calling program's process space. They look to the calling progam's executing location. (not sure, but they may also
look to your environmental variable PATH).

So if the dll isn't in the same location as the exe, there's no way for the exe to know where that dll resides so that it can be
loaded.

Enter the GAC. The GAC allows you to install .net assemblies in a common location so that essentially the assembly can be shared.
There's a lot more to the GAC as I've purposely over-simplified my description. (I'll leave it to others to provide any needed
detail). Making an assembly available for COM Interop requires registration in the GAC.

In a nutshell, the behaviour you're seeing is by design.

HTH,

ChrisG
 
[I know it's lame to answer myself, but I figured someone else might
come looking for this later.]
I want this to work with COM interop too, so
I can hook it into some existing VB6 apps. AFAIK, part of registering a
.NET DLL for use with interop is registering it into the GAC with
gacutil. Is that strictly necessary?

To answer my own question: No. The alternative:

1) Make sure you have a public interface available, and make sure Class1
implements it.
2) set project properties to "Register for COM Interop" = True
3) in AssemblyInfo.cs, add attributes:
[assembly: ComVisible(true)]
[assembly: ClassInterface(ClassInterfaceType.None)]
4) generate guids for the interface and the class to keep binary
compatibility (so you can use early binding in your VB6 project).

Beware though, .NET insists on copying the damn thing into C:\Documents
and Settings\{profile}\etc etc... and working from that copy *WHILE
YOU'RE IN THE IDE*. Which is retarded, IMHO, since the final
COM-registered copy does in fact end up where you thought you were
working. But hey.

So comment out all that stuff while you're working on it and uncheck the
Register for Interop property. Set it back when you're ready to
"publish" it to COM.


Because it seems that when I do *that*, the path that gets returned from
VB6 code like:

dim o as object
set o = CreateObject("MyTest.Class1")
msgbox o.FindMe


is c:\windows\assembly\gac\test\1.0.1599.14565__d78c501879e5dc01\mytest.dll


So it seems gacutil really throws things off. I guess it's because
that's actually the executing assembly. Is there any way to trace that
back to its original path (i.e. c:\test\mytest.dll)?

See above. If you don't use the GAC, then
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) will
return the path to the DLL.
 
Chris said:
Ellen,

I may be a little off on this explanation as far as the details (and I welcome any/all corrections) but the gist of what I'll say
should be accurate...
.NET assemblies by default do not rely on the Registry for calling applications to identify their location so that they can be
loaded in the calling program's process space. They look to the calling progam's executing location. (not sure, but they may also
look to your environmental variable PATH).

So if the dll isn't in the same location as the exe, there's no way for the exe to know where that dll resides so that it can be
loaded.

<nods vigorously>. I've just been playing with ActiveX DLLs for so long
that *everything* looks like one :) Still coming up to speed.

Enter the GAC. The GAC allows you to install .net assemblies in a common location so that essentially the assembly can be shared.
There's a lot more to the GAC as I've purposely over-simplified my description. (I'll leave it to others to provide any needed
detail). Making an assembly available for COM Interop requires registration in the GAC.

In a nutshell, the behaviour you're seeing is by design.

I'm getting that :)

Nasty, tricksy GAC! The good news is that I don't need the gac for
interop, which I thought I did, and that misunderstanding was really the
root of my troubles.

I just sent another post outlining exactly what works (for posterity and
closure), but basically, with the right attribute decorations you don't
need to register it in the GAC and suddenly All Is Groovy.

Thanks for the feedback though, it helped clarify my thinking A LOT.

Ellen
 
wrote:
Chris,

You can specify where the output file (dll) ends up. I put all my dlls in a single directory (...\Build\Bin) and also specify in each references properties that it should not copy the DLL (click on a reference and look at the properties).

To specify an output directory for a VB project, pull up the properties for the project, then click on "Configuration Properties", "Build" and you will see a setting for output path.

C# is a little different, but it is still in the project properties.

I *have to* get that ActiveX thinking behind me. The registry is legacy!

If my DLL is in C:\test, and my testapp is in c:\test\testapp, I can
point the build for the DLL to ".\", and for the testapp to "..\", which
puts both output files into the same folder and voila...
 
Glad to have helped.

Your final post enlightened me a bit also. All my interop to date has been in the other direction; a bit simplier.

Also thanks to the above suggestion about setting the dump location for your builds. <DOH!>

ChrisG
 
Back
Top