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 / Languages / C# / February 2008

Tip: Looking for answers? Try searching our database.

GAC hell

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Fredo - 25 Feb 2008 23:29 GMT
I'm writing a wrapper for the VBScript and JScript engines in .NET. I'm
trying to add a little uniformity where Microsoft has some divergence.

With the JScript engine, you can add references and provide a path to where
each DLL is. With the VBScript engine, you can't do that. For DLLs that
aren't in the GAC, you have to provide a directory where all the referenced
.DLLs are.

To keep the user of the wrapper from having to deal with this, for the
VBScript I want to add some code to copy all the references that aren't in
the GAC, to a temporary directory. The problem is, how would one
programmatically determine which ones are in the GAC and which ones aren't?
I know I can go snooping around in \Windows\assembly\GAC, but I wanted ot
know if there was a better way of doing this that doesn't require me digging
through directories, checking DLL versions and such. I don't know precisely
how .NET normally does this and unfortunately, I can't see how the VBScript
engine deals with it since that part of the framework code appears to be
unmanaged.

Thanks.
Willy Denoyette [MVP] - 26 Feb 2008 00:29 GMT
> I'm writing a wrapper for the VBScript and JScript engines in .NET. I'm
> trying to add a little uniformity where Microsoft has some divergence.
[quoted text clipped - 16 lines]
>
> Thanks.

The scripting engine is a COM client and COM uses the registry to locate the
COM server DLL(s) that contains the components as referred to by the
scripts.
Now, for .NET components you want to expose to COM clients, you have a
number of options when registering your assembly:
1. you can run regasm without the /codebase command line switch, and you
have to install the assembly in the GAC, or
2. you can run regasm with the /codebase switch, and you don't have to
install the assembly in the GAC, or
3. you can run regasm without the /codebase switch and install the assembly
in the same directory as the client.

Note that the COM client in your case is the scripting engine (cscript.exe)
which is found in %windir%\system32 (or %windir%\syswow64), so installing
the assemblies with the client is excluded, which leaves you with option 1
and 2. Installing in the GAC is
only a viable option if you have a small number of assemblies used by
different clients and client types. Option 2 is preferable when you have a
number of assemblies used by a single client (or a limited number of
clients). If your component is only used by scripting clients (well.. there
is only a single one) then you should definitely go for 2.

Willy.
Fredo - 26 Feb 2008 00:56 GMT
Willy,

Sorry, I think you're misunderstanding. I'm talking about the scripting
engines: Microsoft.JScript, Microsoft.Vsa, and Microsoft.VisualBasic.Vsa
managed engines, not the Windows scripting host or cscript.exe.

These engines work with managed objects, much in the way WSH works with COM
objects, but they're different engines, at least the JScript engine is. The
entire (or a vast majority of the) JScript interpreter is managed code. The
VBScript seems to be doing a lot of stuff in unmanaged code, so for all I
know, they're somehow using WSH underneath, but I doubt it since I don't see
how it would deal with managed objects.

So my question has to do with the resolution of referenced managed
assemblies, not COM components.

>> I'm writing a wrapper for the VBScript and JScript engines in .NET. I'm
>> trying to add a little uniformity where Microsoft has some divergence.
[quoted text clipped - 40 lines]
>
> Willy.
Willy Denoyette [MVP] - 26 Feb 2008 16:57 GMT
Hmm... So, you are talking about the CodeDom providers, right?  In that case
I don't see where "VBScript and WSH" comes from, there is no language
provider for unmanaged languages in the framework. All there is, are the
language providers for CSharp, VisualBasic, J#, C++ and JScript, but all are
producing pure managed CSharp, VB.NET, J#, C++ and JScript.NET code.
Also all CodeDom providers share a common interface, so I don't know exactly
what problem you have with "adding references".
Mind to give an example that illustrates your issue?

Willy.

> Willy,
>
[quoted text clipped - 56 lines]
>>
>> Willy.
Fredo - 26 Feb 2008 17:29 GMT
Willy,

What you're referring to are the CodeDom providers. What I'm talking about
is the scripting engines. These are different things as well.

Here's an article that discuesses VSA scripting:

http://www.developerfusion.co.uk/show/4675/

More specifically, adding references which is discussed on this page:

http://www.developerfusion.co.uk/show/4675/3/

There's a difference in the way VBScript and JScript handle assembly
references. JScript will allow you to pass a path to the assembly. VBScript
requires that all referenced assemblies that aren't in the GAC, be located
in a single directory and you then have to call
IVsaEngine.SetOption("AssemblyBase", referencesDirectory) to set the
directory.

So, my question is: I need to figure out which references are GAC references
and which ones aren't, so I can copy the ones that aren't GAC references
into a temporary directory for the script to access them.

> Hmm... So, you are talking about the CodeDom providers, right?  In that
> case I don't see where "VBScript and WSH" comes from, there is no language
[quoted text clipped - 67 lines]
>>>
>>> Willy.
Willy Denoyette [MVP] - 27 Feb 2008 09:49 GMT
Don't know what version of VS and the Framework you are using, but the
article you are referring to is old hat (the article was written back in
2002 and was based on v1.0 of the framework), the namespace the author is
talking about was deprecated a long time ago (since VS2005 and V2 of the
framework).
VSA was deprecated back in 2004 in favor of VSTA, something the author was
not aware of (see the articles FAQ).
The V2 way to script your application, that is generate/compile/run scripts,
is by using the CodeDom providers (included with the framework for C#,
managed C++, JS.NET and VB.NET). Other languages are supported through the
VSTA SDK, but this implies licensing the SDK and the Runtime.
The sample project included with the article from the same author here
http://www.123aspx.com/redir.aspx?res=32808 ,  compiles with a bunch of
warnings and doesn't run after the build.
Also, the author talks about a non existing language VBScript.NET, which he
dislikes (<quote ..I tended to dislike ..VBScript /quote>).
Take a look at the demo sample included with the article, the author
includes two (what he calls) script files (Scripts-DebugWrite.js and
Scripts-DebugWrite.vb), but both are *managed* language code , the .js code
being JScript.NET and the .vb code being VB.NET. Both have nothing in common
with VBScript or JScript, apart some of the syntaxes.

So, please if you have a small but complete sample that uses the (obsolete)
Microsoft.Vsa namespace to generate/compile/Run "VBScript" and "JScript"
scripting code (that is interpreted scripting code), feel free to post it
here.

Willy.

> Willy,
>
[quoted text clipped - 95 lines]
>>>>
>>>> Willy.
Fredo - 27 Feb 2008 13:33 GMT
Willy,

This is the engine I'm using. I'm aware it's deprecated. Be that as it may,
it's the one I'm choosing to use because it meets my needs on several
levels.

But we've gotten so far off topic here, we're nowhere near my original
question anymore, which had to do with determining which referenced
assemblies are in the GAC and which are not.

> Don't know what version of VS and the Framework you are using, but the
> article you are referring to is old hat (the article was written back in
[quoted text clipped - 127 lines]
>>>>>
>>>>> Willy.
Willy Denoyette [MVP] - 27 Feb 2008 16:53 GMT
The only way to get at the GAC is by calling into the unmanaged fusion
API's.
Following is a complete sample that illustrates how you can perform a name
lookup.
Beware that the GAC uses fully qualified assembly names to store assembly
references, because you don't know whether an assembly resides in the GAC,
you also don't have a FQAN, this may result in false positives!

Willy.

// Note that this requires V2 of the framework.
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace GacStuff
{
   internal class GacApi
   {
       [DllImport("fusion.dll")]
       internal static extern int CreateAssemblyCache(
               out IAssemblyCache ppAsmCache,
               int reserved);

   }
   // GAC Interfaces - IAssemblyCache. Non used vtable entries declared as
dummy.
   [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("e707dcde-d1cd-11d2-bab9-00c04f8eceae")]
   internal interface IAssemblyCache
   {
       int Dummy1();
       [PreserveSig()]
       int QueryAssemblyInfo(
                           int flags,
                           [MarshalAs(UnmanagedType.LPWStr)]
                           String assemblyName,
                           ref ASSEMBLY_INFO  assemblyInfo);
       int Dummy2();
       int Dummy3();
       int Dummy4();
   }
    [StructLayout(LayoutKind.Sequential)]
   internal struct ASSEMBLY_INFO
   {
       public int      cbAssemblyInfo;
       public int      assemblyFlags;
       public long     assemblySizeInKB;
       [MarshalAs(UnmanagedType.LPWStr)]
       public String   currentAssemblyPath;
       public int      cchBuf;
   }

   class Program
{
 static void Main()
 {
  Console.WriteLine(QueryAssemblyInfo("System"));
 }
       // If assemblyName is not fully specified, a random matching will be
returned!!!!
       public static String QueryAssemblyInfo(String assemblyName)
       {
           ASSEMBLY_INFO  assembyInfo = new ASSEMBLY_INFO ();
           assembyInfo.cchBuf = 512;
           assembyInfo.currentAssemblyPath = new String('\0',
assembyInfo.cchBuf) ;
           IAssemblyCache assemblyCache = null;
           // Get IAssemblyCache pointer
           int hr = GacApi.CreateAssemblyCache(out assemblyCache, 0);
           if (hr >= 0)
               hr = assemblyCache.QueryAssemblyInfo(1, assemblyName, ref
assembyInfo);
           else
               Marshal.ThrowExceptionForHR(hr);
           return assembyInfo.currentAssemblyPath;
       }
}
}
//-------------------------------

> Willy,
>
[quoted text clipped - 137 lines]
>>>>>>
>>>>>> Willy.
Fredo - 27 Feb 2008 20:27 GMT
Sweet! Thanks Willy.

> The only way to get at the GAC is by calling into the unmanaged fusion
> API's.
[quoted text clipped - 221 lines]
>>>>>>>
>>>>>>> Willy.

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.