Прямое обращение к GAC через Wrapper к fusion.dll

К GAC'у можно обратиться менеджером mscorcfg.dll через классы Microsoft.CLRAdmin. Этот вариант обращения к которому лежит здесь, но теперь рассмотрим собственно прямое обращение к неуправляемому коду, манипулирующему GAC'ом.

Вот такой вот код:

00001:     Sub Main()
00002:         'System.Diagnostics.Process.Start("C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\gacutil.exe", "/l")
00003:         'Вместо вызова GacUtil манипулируем сборками в Гаке собственной интерфейсной библиотекой к Fusion.DLL
00004:         'Интерфейс ее описан тут - http://support.microsoft.com/default.aspx?scid=kb;en-us;317540 или тут ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.KB.v10.en/enu_kbnetframeworkkb/netframeworkkb/317540.htm
00005:         Dim x As New fusion_dll.AssemblyCacheEnum(Nothing)
00006:         Dim s1 As String = " "
00007:         While s1 <> ""
00008:             s1 = x.GetNextAssembly()
00009:             Console.WriteLine(s1)
00010:         End While
00011:           Console.ReadLine()
00012:     End Sub
Выдает мне при прогоне список всех моих 439 сборок:



На самом деле ситуация еще более запутанная, ибо GAC'а существует два типа (еще и тип ZAP) - Microsoft.CLRAdmin легко читает оба типа GAC'а. Можно это сделать и пямым обращением к неуправляему коду FUSION.DLL. Ну и вот собственно код управляемого Wrapper'а к неуправляемой библиотеке fusion.dll, сотворившей чудо на рисунках выше:

00001: Imports System.Runtime.InteropServices, System.Text
00002: 
00003: <ComImport(), _
00004:      InterfaceType(ComInterfaceType.InterfaceIsIUnknown), _
00005:      Guid("e707dcde-d1cd-11d2-bab9-00c04f8eceae")> _
00006:     Interface IAssemblyCache
00007: 
00008:     <PreserveSig()> _
00009:     Function UninstallAssembly(ByVal flags As Integer, ByVal assemblyName As String, ByVal refData As InstallReference, ByRef disposition As AssemblyCacheUninstallDisposition) As Integer
00010: 
00011:     <PreserveSig()> _
00012:     Function QueryAssemblyInfo(ByVal flags As Integer, ByVal assemblyName As String, ByRef assemblyInfo As AssemblyInfo) As Integer
00013: 
00014:     <PreserveSig()> _
00015:     Function Reserved(ByVal flags As Integer, ByVal pvReserved As IntPtr, ByRef ppAsmItem As Object, ByVal assemblyName As String) As Integer
00016: 
00017:     <PreserveSig()> _
00018:     Function Reserved(ByRef ppAsmScavenger As Object) As Integer
00019: 
00020:     <PreserveSig()> _
00021:     Function InstallAssembly(ByVal flags As Integer, ByVal assemblyFilePath As String, ByVal refData As InstallReference) As Integer
00022: End Interface    ' IAssemblyCache
00023: 
00024: <ComImport(), _
00025:  InterfaceType(ComInterfaceType.InterfaceIsIUnknown), _
00026:  Guid("CD193BC0-B4BC-11d2-9833-00C04FC31D2E")> _
00027: Interface IAssemblyName
00028: 
00029:     <PreserveSig()> _
00030:     Function SetProperty(ByVal PropertyId As Integer, ByVal pvProperty As IntPtr, ByVal cbProperty As Integer) As Integer
00031: 
00032:     <PreserveSig()> _
00033:     Function GetProperty(ByVal PropertyId As Integer, ByVal pvProperty As IntPtr, ByRef pcbProperty As Integer) As Integer
00034: 
00035:     <PreserveSig()> _
00036:     Function Finalize() As Integer
00037: 
00038:     <PreserveSig()> _
00039:     Function GetDisplayName(ByVal pDisplayName As StringBuilder, ByRef pccDisplayName As Integer, ByVal displayFlags As Integer) As Integer
00040: 
00041:     <PreserveSig()> _
00042:     Function Reserved(ByRef guid As Guid, ByVal obj1 As Object, ByVal obj2 As Object, ByVal string1 As String, ByVal llFlags As Int64, ByVal pvReserved As IntPtr, ByVal cbReserved As Integer, ByRef ppv As IntPtr) As Integer
00043: 
00044:     <PreserveSig()> _
00045:     Function GetName(ByRef pccBuffer As Integer, ByVal pwzName As StringBuilder) As Integer
00046: 
00047:     <PreserveSig()> _
00048:     Function GetVersion(ByRef versionHi As Integer, ByRef versionLow As Integer) As Integer
00049: 
00050:     <PreserveSig()> _
00051:     Function IsEqual(ByVal pAsmName As IAssemblyName, ByVal cmpFlags As Integer) As Integer
00052: 
00053:     <PreserveSig()> _
00054:     Function Clone(ByRef pAsmName As IAssemblyName) As Integer
00055: End Interface    ' IAssemblyName
00056: 
00057: <ComImport(), _
00058:  InterfaceType(ComInterfaceType.InterfaceIsIUnknown), _
00059:  Guid("21b8916c-f28e-11d2-a473-00c04f8ef448")> _
00060: Interface IAssemblyEnum
00061: 
00062:     <PreserveSig()> _
00063:     Function GetNextAssembly(ByVal pvReserved As IntPtr, ByRef ppName As IAssemblyName, ByVal flags As Integer) As Integer
00064: 
00065:     <PreserveSig()> _
00066:     Function Reset() As Integer
00067: 
00068:     <PreserveSig()> _
00069:     Function Clone(ByRef ppEnum As IAssemblyEnum) As Integer
00070: End Interface    ' IAssemblyEnum
00071: 
00072: <ComImport(), _
00073:  InterfaceType(ComInterfaceType.InterfaceIsIUnknown), _
00074:  Guid("582dac66-e678-449f-aba6-6faaec8a9394")> _
00075: Interface IInstallReferenceItem
00076: 
00077:     ' A pointer to a FUSION_INSTALL_REFERENCE structure. 
00078:     ' The memory is allocated by the GetReference method and is freed when 
00079:     ' IInstallReferenceItem is released. Callers must not hold a reference to this 
00080:     ' buffer after the IInstallReferenceItem object is released. 
00081:     ' This uses the InstallReferenceOutput object to avoid allocation 
00082:     ' issues with the interop layer. 
00083:     ' This cannot be marshaled directly - must use IntPtr 
00084:     <PreserveSig()> _
00085:     Function GetReference(ByRef pRefData As IntPtr, ByVal flags As Integer, ByVal pvReserced As IntPtr) As Integer
00086: End Interface    ' IInstallReferenceItem
00087: 
00088: <ComImport(), _
00089:  InterfaceType(ComInterfaceType.InterfaceIsIUnknown), _
00090:  Guid("56b1a988-7c0c-4aa2-8639-c3eb5a90226f")> _
00091: Interface IInstallReferenceEnum
00092: 
00093:     <PreserveSig()> _
00094:     Function GetNextInstallReferenceItem(ByRef ppRefItem As IInstallReferenceItem, ByVal flags As Integer, ByVal pvReserced As IntPtr) As Integer
00095: End Interface   ' IInstallReferenceEnum
00096: 
00097: Public Enum AssemblyCommitFlags
00098:     Default_ = 1
00099:     Force = 2
00100: End Enum    ' enum AssemblyCommitFlags
00101: 
00102: Public Enum AssemblyCacheUninstallDisposition
00103:     Unknown = 0
00104:     Uninstalled = 1
00105:     StillInUse = 2
00106:     AlreadyUninstalled = 3
00107:     DeletePending = 4
00108:     HasInstallReference = 5
00109:     ReferenceNotFound = 6
00110: End Enum
00111: 
00112: <Flags()> _
00113: Enum AssemblyCacheFlags
00114:     GAC = 2
00115: End Enum
00116: 
00117: Enum CreateAssemblyNameObjectFlags
00118:     CANOF_DEFAULT = 0
00119:     CANOF_PARSE_DISPLAY_NAME = 1
00120: End Enum
00121: 
00122: <Flags()> _
00123: Enum AssemblyNameDisplayFlags
00124:     VERSION = 1
00125:     CULTURE = 2
00126:     PUBLIC_KEY_TOKEN = 4
00127:     PROCESSORARCHITECTURE = 32
00128:     RETARGETABLE = 128
00129:     ALL = (VERSION _
00130:                 Or (CULTURE _
00131:                 Or (PUBLIC_KEY_TOKEN _
00132:                 Or (PROCESSORARCHITECTURE Or RETARGETABLE))))
00133: End Enum
00134: 
00135: <StructLayout(LayoutKind.Sequential)> _
00136: Public Class InstallReference
00137: 
00138:     Private cbSize As Integer
00139:     Private flags As Integer
00140:     Private a_guidScheme As Guid
00141: 
00142:     <MarshalAs(UnmanagedType.LPWStr)> _
00143:     Private a_identifier As String
00144: 
00145:     <MarshalAs(UnmanagedType.LPWStr)> _
00146:     Private a_description As String
00147: 
00148:     Public Sub New(ByVal guid As Guid, ByVal id As String, ByVal data As String)
00149:         MyBase.New()
00150:         cbSize = CType(((2 * IntPtr.Size) + (16 + ((id.Length + data.Length) * 2))), Integer)
00151:         flags = 0
00152:         ' quiet compiler warning 
00153:         If (flags = 0) Then
00154: 
00155:         End If
00156:         a_guidScheme = guid
00157:         a_identifier = id
00158:         a_description = data
00159:     End Sub
00160: 
00161:     Public ReadOnly Property GuidScheme() As Guid
00162:         Get
00163:             Return a_guidScheme
00164:         End Get
00165:     End Property
00166: 
00167:     Public ReadOnly Property Identifier() As String
00168:         Get
00169:             Return a_identifier
00170:         End Get
00171:     End Property
00172: 
00173:     Public ReadOnly Property Description() As String
00174:         Get
00175:             Return a_description
00176:         End Get
00177:     End Property
00178: End Class
00179: 
00180: <StructLayout(LayoutKind.Sequential)> _
00181: Structure AssemblyInfo
00182: 
00183:     Public cbAssemblyInfo As Integer        ' size of this structure for future expansion
00184:     Public assemblyFlags As Integer
00185:     Public assemblySizeInKB As Long
00186: 
00187:     <MarshalAs(UnmanagedType.LPWStr)> _
00188:     Public currentAssemblyPath As String
00189: 
00190:     Public cchBuf As Integer                'size of path buf.
00191: End Structure
00192: 
00193: <ComVisible(False)> _
00194: Public Class InstallReferenceGuid
00195: 
00196:     Public Shared UninstallSubkeyGuid As Guid = New Guid("8cedc215-ac4b-488b-93c0-a50a49cb2fb8")
00197:     Public Shared FilePathGuid As Guid = New Guid("b02f9d65-fb77-4f7a-afa5-b391309f11c9")
00198:     Public Shared OpaqueGuid As Guid = New Guid("2ec93463-b0c3-45e1-8364-327e96aea856")
00199:     ' these GUID cannot be used for installing into GAC.
00200:     Public Shared MsiGuid As Guid = New Guid("25df0fc1-7f97-4070-add7-4b13bbfd7cb8")
00201:     Public Shared OsInstallGuid As Guid = New Guid("d16d444c-56d8-11d5-882d-0080c847b195")
00202: 
00203:     Public Shared Function IsValidGuidScheme(ByVal guid As Guid) As Boolean
00204:         Return (guid.Equals(UninstallSubkeyGuid) _
00205:                     OrElse (guid.Equals(FilePathGuid) _
00206:                     OrElse (guid.Equals(OpaqueGuid) OrElse guid.Equals(guid.Empty))))
00207:     End Function
00208: End Class
00209: 
00210: <ComVisible(False)> _
00211: Public Class AssemblyCache
00212: 
00213:     Public Shared Sub InstallAssembly(ByVal assemblyPath As String, ByVal reference As InstallReference, ByVal flags As AssemblyCommitFlags)
00214:         If (Not (reference) Is Nothing) Then
00215:             If Not InstallReferenceGuid.IsValidGuidScheme(reference.GuidScheme) Then
00216:                 Throw New ArgumentException("Invalid reference guid.", "guid")
00217:             End If
00218:         End If
00219:         Dim ac As IAssemblyCache = Nothing
00220:         Dim hr As Integer = 0
00221:         hr = Utils.CreateAssemblyCache(ac, 0)
00222:         If (hr >= 0) Then
00223:             hr = ac.InstallAssembly(CType(flags, Integer), assemblyPath, reference)
00224:         End If
00225:         If (hr < 0) Then
00226:             Marshal.ThrowExceptionForHR(hr)
00227:         End If
00228:     End Sub
00229: 
00230:     ' assemblyName has to be fully specified name. 
00231:     ' A.k.a, for v1.0/v1.1 assemblies, it should be "name, Version=xx, Culture=xx, PublicKeyToken=xx".
00232:     ' For v2.0 assemblies, it should be "name, Version=xx, Culture=xx, PublicKeyToken=xx, ProcessorArchitecture=xx".
00233:     ' If assemblyName is not fully specified, a random matching assembly will be uninstalled. 
00234:     Public Shared Sub UninstallAssembly(ByVal assemblyName As String, ByVal reference As InstallReference, ByRef disp As AssemblyCacheUninstallDisposition)
00235:         Dim dispResult As AssemblyCacheUninstallDisposition = AssemblyCacheUninstallDisposition.Uninstalled
00236:         If (Not (reference) Is Nothing) Then
00237:             If Not InstallReferenceGuid.IsValidGuidScheme(reference.GuidScheme) Then
00238:                 Throw New ArgumentException("Invalid reference guid.", "guid")
00239:             End If
00240:         End If
00241:         Dim ac As IAssemblyCache = Nothing
00242:         Dim hr As Integer = Utils.CreateAssemblyCache(ac, 0)
00243:         If (hr >= 0) Then
00244:             hr = ac.UninstallAssembly(0, assemblyName, reference, dispResult)
00245:         End If
00246:         If (hr < 0) Then
00247:             Marshal.ThrowExceptionForHR(hr)
00248:         End If
00249:         disp = dispResult
00250:     End Sub
00251: 
00252:     ' See comments in UninstallAssembly
00253:     Public Shared Function QueryAssemblyInfo(ByVal assemblyName As String) As String
00254:         If (assemblyName = Nothing) Then
00255:             Throw New ArgumentException("Invalid name", "assemblyName")
00256:         End If
00257:         Dim aInfo As AssemblyInfo = New AssemblyInfo
00258:         aInfo.cchBuf = 1024
00259:         ' Get a string with the desired length
00260:         aInfo.currentAssemblyPath = New String(Microsoft.VisualBasic.ChrW(92), aInfo.cchBuf)
00261:         Dim ac As IAssemblyCache = Nothing
00262:         Dim hr As Integer = Utils.CreateAssemblyCache(ac, 0)
00263:         If (hr >= 0) Then
00264:             hr = ac.QueryAssemblyInfo(0, assemblyName, aInfo)
00265:         End If
00266:         If (hr < 0) Then
00267:             Marshal.ThrowExceptionForHR(hr)
00268:         End If
00269:         Return aInfo.currentAssemblyPath
00270:     End Function
00271: End Class
00272: 
00273: <ComVisible(False)> _
00274: Public Class AssemblyCacheEnum
00275: 
00276:     Private m_AssemblyEnum As IAssemblyEnum = Nothing
00277:     Private done As Boolean
00278: 
00279:     ' null means enumerate all the assemblies
00280:     Public Sub New(ByVal assemblyName As String)
00281:         MyBase.New()
00282:         Dim fusionName As IAssemblyName = Nothing
00283:         Dim hr As Integer = 0
00284:         If (Not (assemblyName) Is Nothing) Then
00285:             hr = Utils.CreateAssemblyNameObject(fusionName, assemblyName, CreateAssemblyNameObjectFlags.CANOF_PARSE_DISPLAY_NAME, IntPtr.Zero)
00286:         End If
00287:         If (hr >= 0) Then
00288:             hr = Utils.CreateAssemblyEnum(m_AssemblyEnum, IntPtr.Zero, fusionName, AssemblyCacheFlags.GAC, IntPtr.Zero)
00289:         End If
00290:         If (hr < 0) Then
00291:             Marshal.ThrowExceptionForHR(hr)
00292:         End If
00293:     End Sub
00294: 
00295:     Public Function GetNextAssembly() As String
00296:         Dim hr As Integer = 0
00297:         Dim fusionName As IAssemblyName = Nothing
00298:         If done Then
00299:             Return Nothing
00300:         End If
00301:         ' Now get next IAssemblyName from m_AssemblyEnum
00302:         hr = m_AssemblyEnum.GetNextAssembly(CType(0, IntPtr), fusionName, 0)
00303:         If (hr < 0) Then
00304:             Marshal.ThrowExceptionForHR(hr)
00305:         End If
00306:         If (Not (fusionName) Is Nothing) Then
00307:             Return GetFullName(fusionName)
00308:         Else
00309:             done = True
00310:             Return Nothing
00311:         End If
00312:     End Function
00313: 
00314:     Private Function GetFullName(ByVal fusionAsmName As IAssemblyName) As String
00315:         Dim sDisplayName As StringBuilder = New StringBuilder(1024)
00316:         Dim iLen As Integer = 1024
00317:         Dim hr As Integer = fusionAsmName.GetDisplayName(sDisplayName, iLen, CType(AssemblyNameDisplayFlags.ALL, Integer))
00318:         If (hr < 0) Then
00319:             Marshal.ThrowExceptionForHR(hr)
00320:         End If
00321:         Return sDisplayName.ToString
00322:     End Function
00323: End Class
00324: 
00325: ' class AssemblyCacheEnum
00326: Public Class AssemblyCacheInstallReferenceEnum
00327: 
00328:     Private refEnum As IInstallReferenceEnum
00329: 
00330:     Public Sub New(ByVal assemblyName As String)
00331:         MyBase.New()
00332:         Dim fusionName As IAssemblyName = Nothing
00333:         Dim hr As Integer = Utils.CreateAssemblyNameObject(fusionName, assemblyName, CreateAssemblyNameObjectFlags.CANOF_PARSE_DISPLAY_NAME, IntPtr.Zero)
00334:         If (hr >= 0) Then
00335:             hr = Utils.CreateInstallReferenceEnum(refEnum, fusionName, 0, IntPtr.Zero)
00336:         End If
00337:         If (hr < 0) Then
00338:             Marshal.ThrowExceptionForHR(hr)
00339:         End If
00340:     End Sub
00341:
00342:     Public Function GetNextReference() As InstallReference
00343:         Dim item As IInstallReferenceItem = Nothing
00344:         Dim hr As Integer = refEnum.GetNextInstallReferenceItem(item, 0, IntPtr.Zero)
00345:         If (CType(hr, UInteger) = -2147024637) Then
00346:             ' ERROR_NO_MORE_ITEMS
00347:             Return Nothing
00348:         End If
00349:         If (hr < 0) Then
00350:             Marshal.ThrowExceptionForHR(hr)
00351:         End If
00352:         Dim refData As IntPtr
00353:         Dim instRef As InstallReference = New InstallReference(Guid.Empty, String.Empty, String.Empty)
00354:         hr = item.GetReference(refData, 0, IntPtr.Zero)
00355:         If (hr < 0) Then
00356:             Marshal.ThrowExceptionForHR(hr)
00357:         End If
00358:         Marshal.PtrToStructure(refData, instRef)
00359:         Return instRef
00360:     End Function
00361: End Class
00362: 
00363: Class Utils
00364:     Friend Declare Function CreateAssemblyEnum Lib "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\fusion.dll" (ByRef ppEnum As IAssemblyEnum, ByVal pUnkReserved As IntPtr, ByVal pName As IAssemblyName, ByVal flags As AssemblyCacheFlags, ByVal pvReserved As IntPtr) As Integer
00365:     Friend Declare Function CreateAssemblyNameObject Lib "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\fusion.dll" (ByRef ppAssemblyNameObj As IAssemblyName, ByVal szAssemblyName As String, ByVal flags As CreateAssemblyNameObjectFlags, ByVal pvReserved As IntPtr) As Integer
00366:     Friend Declare Function CreateAssemblyCache Lib "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\fusion.dll" (ByRef ppAsmCache As IAssemblyCache, ByVal reserved As Integer) As Integer
00367:     Friend Declare Function CreateInstallReferenceEnum Lib "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\fusion.dll" (ByRef ppRefEnum As IInstallReferenceEnum, ByVal pName As IAssemblyName, ByVal dwFlags As Integer, ByVal pvReserved As IntPtr) As Integer
00368: End Class


Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23
Link to this page: //www.vb-net.com/windows/WinDump/FusionWrapper_VB.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <CHAT ME>  <ABOUT ME>  < THANKS ME>