Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Visual Studio.NET / Extensibility / September 2005

Tip: Looking for answers? Try searching our database.

Managing referenced assemblies for custom compiler?

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Sporky - 02 Sep 2005 01:20 GMT
Hello.  I'm trying to integrate my own compiler into VS 2005.  Pretty good
luck so far, but one thing is driving me nuts.  I need have some way of
reflecting on assemblies which are referenced by my project type.  I got this
to work using Assembly.LoadFrom(), but after the first time a build is
performed, the referenced DLLs (really the local copies) are locked,
presumably because they were loaded in to the appdomain for Visual Studio.

I thought I could get around this by just loading the assemblies into
another appdomain, but now I can't figure out how to get a reference to the
assembly object to perform reflection.  If I use a statement like this:

myAssembly = myAppDomain.Load(...);

the runtime apparently tries to load the assembly into VS's appdomain, which
causes an exception because it's not located under the VS application base
directory.  Note that the above statement without the assignment works fine.  
Same problem trying to call myAppDomain.GetAssemblies().  I guess this makes
sense given the isolation provided by appdomains, but I can't figure out how
to work around it.

Any other compiler-writers out there know how to reflect on a project's
references assemblies without locking the files, clogging up the VS
appdomain, etc?

Thanks.

Dave
Carlos J. Quintero [VB MVP] - 02 Sep 2005 10:05 GMT
Hi Dave,

Without another appdomain , I think to recall that someone suggested for
this problem to read a stream of bytes from the assembly (via IO) and then
load the assembly using the overloaded variation
System.Reflection.Assembly.Load(ByVal rawAssembly() As Byte). That should
not block the assembly on disk.

Signature

Best regards,

Carlos J. Quintero

MZ-Tools: Productivity add-ins for Visual Studio .NET, VB6, VB5 and VBA
You can code, design and document much faster.
Free resources for add-in developers:
http://www.mztools.com

> Hello.  I'm trying to integrate my own compiler into VS 2005.  Pretty good
> luck so far, but one thing is driving me nuts.  I need have some way of
[quoted text clipped - 29 lines]
>
> Dave
Sporky - 02 Sep 2005 14:30 GMT
Excellent solution, Carlos, thank you.  That solves the immediate problem.  

I'm still a little bothered about leaving the referenced assemblies loaded
into the VS appdomain.  Am I being too picky, or are there any potential
problems related to this?  For example, if a referenced project is rebuilt, a
different version of the assembly will be loaded.  Maybe it's not a problem,
but it would be nice to clean up.

BTW, I tried running the compiler in a different appdomain, but no success.  
A line such as below:

CodeGenerator generator =
                (CodeGenerator)(myAppDomain.CreateInstanceFromAndUnwrap( typeof(
CodeGenerator ).Assembly.Location, "Provisdom.ISharp.CodeGenerator" ));

throws an InvalidCastException, basically can't cast TransparentProxy to
CodeGenerator.  This must be something peculiar to how VS loades up my
assembly, since I think this ought to work.  Maybe the problem is that my
assembly is not located under the VS application base directory?

Dave

> Hi Dave,
>
[quoted text clipped - 3 lines]
> System.Reflection.Assembly.Load(ByVal rawAssembly() As Byte). That should
> not block the assembly on disk.
Carlos J. Quintero [VB MVP] - 02 Sep 2005 15:25 GMT
Yes, loading multiples copies can be a problem and it seems that VS.NET also
suffers it. See this thread:

http://groups.google.es/group/microsoft.public.dotnet.languages.vb/browse_frm/th
read/f2a0b4b3e22a2243/a0b6ab64938d7324?lnk=st&q=Quintero+memory+microsoft.public
&rnum=1&hl=es#a0b6ab64938d7324


I am not expert in appdomains, so I can only suggest these links:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/cs
harp05162002.asp


http://blogs.msdn.com/shawnfa/

Signature

Best regards,

Carlos J. Quintero

MZ-Tools: Productivity add-ins for Visual Studio .NET, VB6, VB5 and VBA
You can code, design and document much faster.
Free resources for add-in developers:
http://www.mztools.com

> Excellent solution, Carlos, thank you.  That solves the immediate problem.
>
[quoted text clipped - 20 lines]
>
> Dave
Dustin Campbell - 02 Sep 2005 17:41 GMT
>BTW, I tried running the compiler in a different appdomain, but no success.  
>A line such as below:
[quoted text clipped - 7 lines]
>assembly, since I think this ought to work.  Maybe the problem is that my
>assembly is not located under the VS application base directory?

The first parameter of AppDomain.CreateInstanceAndUnwrap asks for an
assembly name and not its location. Try using code like this:

CodeGenerator generator =
(CodeGenerator)(myAppDomain.CreateInstanceFromAndUnwrap(typeof(CodeGenerator).Assembly.GetName().Name,
"Provisdom.ISharp.CodeGenerator" ));

You'll need to make sure that CodeGenerator descends from
MarshalByRefObject and you need to ensure that it is visible to the
CLR assembly resolution logic. That means placing it in the GAC (best
solution IMO), in the VS app directory or one of the sub directories
that are specified in the private bin path (PrivateAssemblies and
PublicAssemblies).
--------
Best Regards,
Dustin Campbell
Developer Express, Inc
Sporky - 02 Sep 2005 19:15 GMT
I just discovered that this is only a partial solution.  Say assembly A
contains a type with a method whose signature references a type in assembly
B.  When the assemblies are loaded indirectly (disk->byte[]->AppDomain), then
reflecting on the method in assembly A causes a FileNotFound exception, since
it needs to load B to describe the method signature, and B isn't under the
app base directory.  Using Assembly.LoadFrom() avoids that problem, but then
we're right back where we started, because the DLLs get locked.

I feel like I'm missing something fundamental here.  Any compiler that
integrates with VS must deal with this issue of managing assemblies
referenced by the associated project.

Dave
Dave

> Hi Dave,
>
[quoted text clipped - 3 lines]
> System.Reflection.Assembly.Load(ByVal rawAssembly() As Byte). That should
> not block the assembly on disk.
Dustin Campbell - 02 Sep 2005 19:27 GMT
It's sounds like you're definitely in need of the unmanaged metadata
API that I mentioned that is included in the .NET Framework SDK. This
is designed for compilers to read and write metadata *without* using
the CLR.
--------
Best Regards,
Dustin Campbell
Developer Express, Inc
Dustin Campbell - 02 Sep 2005 19:39 GMT
My apologies, I mentioned the unmanaged metadata APIs in a different
thread. Check out the "Assembly References information" thread.
--------
Best Regards,
Dustin Campbell
Developer Express, Inc
Sporky - 03 Sep 2005 01:10 GMT
Thanks to everyone for their help and input.  I did come up with a solution,
via a combination of the info obtained here and some detective work.  I
managed to avoid (barely) the use of the unmanaged metadata APIs.  Let me go
over the solution, just in case somebody else runs into this issue in the
future.

First thing is to have your build task Execute() method make copies of the
non-GAC assemblies referenced by your project instance.  These should all be
under a common directory.  Then create an AppDomain which sets that directory
as its application base:

AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = fullPathToDirectoryContainingReferencedDllCopies;
AppDomain myAppDomain =
        AppDomain.CreateDomain("Compiler AppDomain", null, setup);

The compiler itself needs to run in that AppDomain, so that reflection can
properly resolve all type references for type resolution (note that the set
of referenced DLLs needs to be closed).  Thus, when A.dll references a type
in B.dll, when you reflect on A.dll the runtime can find B.dll.  Running the
compiler in the separate AppDomain requires that you use one of the
AppDomain.CreateInstance methods to make an instance of the compiler.  I used
CreateInstanceFromAndUnwrap, providing the full path to the compiler's
assembly, because that's the only way I could get it to work.  .  

Note that in order to be able to reference your remoted (cross AppDomain)
compiler instance from inside the VS process, the compiler DLLs and any
dependencies need to be somewhere under the VS app base directory.  I put
mine in <VS Install Dir>\Common7\IDE\PublicAssemblies.  This required a
post-build step to copy the VSPackage and its dependencies to that directory,
as well as redirect the RegPkg step to the appropriate dir.

The final piece of the puzzle was loading the project reference assemblies
into the compiler's AppDomain.  Recall that my original question had to do
with avoiding the lockup of those DLLs after the first build (they presumably
got locked because the VS AppDomain held a reference to them).  I tried just
loading the assemblies via Assembly.Load(), and then unloading the compiler
AppDomain when the build was done.  No luck - the files were still locked,
which seems weird (in fact VS showed the relevant modules as being unloaded
after tear-down of the AppDomain, but the files were still locked).  I next
tried Carlos' idea of first reading the assemblies to a byte array, and then
loading into the AppDomain.  That almost worked, except that when A.dll
referenced B.dll, B.dll get reloaded by the runtime, and then was locked
anyway.  Bleah.

The solution turned out to be using Assembly.ReflectionLoadOnly().  
Apparently this has some memory, so dependencies are also loaded as
ReflectionOnly, and the whole locking thing is avoided.

Thanks again to everyone for their help.

Dave

> Hello.  I'm trying to integrate my own compiler into VS 2005.  Pretty good
> luck so far, but one thing is driving me nuts.  I need have some way of
[quoted text clipped - 23 lines]
>
> Dave

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.