![]() |
![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
| Welcome to Windows Vista Forums. Our forum is dedicated to helping you find solutions with any problems, errors or issues you are experiencing with Windows Vista. The Vista forum also covers news and updates and has an extensive Windows Vista tutorial section that covers a wide range of tips and tricks. |
| |||||||
![]() |
| |
| | #1 (permalink) |
| | Using an interop assembly with interop dependencies Using TlbImp.exe, I have created an interop assembly for a COM DLL I am working with. This assembly has a dependency on MSXML2.dll, so I created an interop assembly for it, too. Both assemblies are in the same directory, and I have loaded them both using [Reflection.Assembly]::LoadFile(). When I try to use a type created from my assembly, I get an error saying that the MSXML2 assembly cannot be loaded, because the file cannot be found. After some experimentation, I was able to get everything to work by copying MSXML2 interop DLL to $PSHOME. I would rather not do that, if I don't have to. I also tried adding the two assemblies' directory to $env:Path, but that didn't work. Other than adding the MSXML2 assembly to the GAC, what are my options? Jeff |
My System Specs![]() |
| | #2 (permalink) |
| | Re: Using an interop assembly with interop dependencies On Oct 5, 6:56 am, Jeff <jeff.hill...@xxxxxx> wrote: Quote: > Using TlbImp.exe, I have created an interop assembly for a COM DLL I > am working with. This assembly has a dependency on MSXML2.dll, so I > created an interop assembly for it, too. Both assemblies are in the > same directory, and I have loaded them both using > [Reflection.Assembly]::LoadFile(). When I try to use a type created > from my assembly, I get an error saying that the MSXML2 assembly > cannot be loaded, because the file cannot be found. > > After some experimentation, I was able to get everything to work by > copying MSXML2 interop DLL to $PSHOME. I would rather not do that, if > I don't have to. I also tried adding the two assemblies' directory to > $env:Path, but that didn't work. Other than adding the MSXML2 > assembly to the GAC, what are my options? > > Jeff http://groups.google.ca/group/micros...9416d6e857ebb8 - Oisin |
My System Specs![]() |
| | #3 (permalink) |
| | Re: Using an interop assembly with interop dependencies On Oct 5, 10:04 pm, Oisin Grehan <ois...@xxxxxx> wrote: Quote: > > This is a large and complex topic; start here:http://groups.google.ca/group/micros...powershell/msg... > > - Oisin few new things this time around. Thanks for pointing them out again. I won't be able to try anything new until next week, but if I have any success, I will post back here. Thanks. Jeff |
My System Specs![]() |
| | #4 (permalink) |
| | Re: Using an interop assembly with interop dependencies On Oct 6, 6:39 am, Jeff <jeff.hill...@xxxxxx> wrote: Quote: > On Oct 5, 10:04 pm, Oisin Grehan <ois...@xxxxxx> wrote: > > > Quote: > > This is a large and complex topic; start here:http://groups.google.ca/group/micros...powershell/msg... Quote: > > - Oisin > I think I have read all of those articles in the past, but I learned a > few new things this time around. Thanks for pointing them out > again. > > I won't be able to try anything new until next week, but if I have any > success, I will post back here. > > Thanks. > > Jeff dealing with COM interop assemblies for me, as I do this sort of thing a lot. Here they are: $SdkPath = "C:\Program Files\Microsoft.NET\SDK\v2.0\Bin" function Create-InteropAssembly( [string] $progId = $(throw "You must specify a ProgId"), [string] $assemblyName = $(throw "You must specify a name"), [string] $path = ( Get-Location ) ) { $classes = "HKLM:\SOFTWARE\Classes" # find the path to the type library $clsid = ( Get-Item ` $classes\$progId\CLSID ).GetValue( "" ) $tlbPath = ( Get-Item ` $classes\CLSID\$clsid\InProcServer32 ).GetValue( "" ) # create a strong name key/value pair if ( !( Test-Path "$path\keyPair.snk" ) ) { & "$SdkPath\sn.exe" -q -k "$path\keyPair.snk" } # create the assembly & "$SdkPath\TlbImp.exe" /silent /keyfile:$path\keyPair.snk ` /out:$assemblyName $tlbPath # add the the path to the assembly to the pipeline "$path\$assemblyName" } function Gac-Assembly( [string] $assemblyPath ) { & "$SdkPath\gacutil.exe" /silent /i $assemblyPath } function UnGac-Assembly( [string] $assemblyName ) { & "$SdkPath\gacutil.exe" /silent /u $assemblyName } function Get-AppDomainedType( [string] $assemblyPath = $(throw "You must specify an assembly"), [string] $typeName = $(throw "You must specify a name") ) { # put the assembly in the GAC Gac-Assembly $assemblyPath # create a temporary AppDomain $appDomain = [System.AppDomain]::CreateDomain( "TempAppDomain" ) $appDomain.AppendPrivatePath( ( Get-ChildItem $assemblyPath ).DirectoryName ) # create a new AssemblyName $assemblyName = New-Object System.Reflection.AssemblyName $assemblyName.Name = ( Get-ChildItem $assemblyPath ).Name -replace ".dll" $assemblyName.CodeBase = $assemblyPath # load the assembly into the new AppDomain $assembly = $appDomain.Load( $assemblyName ) # create the type $type = $appDomain.CreateInstanceFromAndUnwrap( $assemblyPath, $typeName ) # put all the information about the type and AppDomain into # an object that can be used to clean up later $appDomainedTypeInfo = New-Object System.Object $appDomainedTypeInfo | Add-Member -MemberType NoteProperty ` -Name AppDomain ` -Value $appDomain $appDomainedTypeInfo | Add-Member -MemberType NoteProperty ` -Name AssemblyPath ` -Value $assemblyPath $appDomainedTypeInfo | Add-Member -MemberType NoteProperty ` -Name AssemblyName ` -Value $assemblyName.Name # add the type and the info object to the pipeline $type $appDomainedTypeInfo } function CleanUp-AppDomainedType( [PSObject] $appDomainedTypeInfo, [switch] $DeleteAssembly ) { # unload the temporary AppDomain [System.AppDomain]::Unload( $appDomainedTypeInfo.AppDomain ) # remove the assembly from the GAC UnGac-Assembly $appDomainedTypeInfo.AssemblyName if ( $DeleteAssembly ) { # delete the assembly Remove-Item $appDomainedTypeInfo.AssemblyPath } } Create-InteropAssembly uses the ProgId of a COM object to determine the location of a Type Library that can be used to generate an assembly using TlbImp. Get-AppDomainedType takes a path to an assembly and the name of a type. It puts the assembly in the GAC, creates a new AppDomain, loads the assembly into the new AppDomain, and uses AppDomain.CreateInstanceFromAndUnwrap() to get an instance of the specified type. Besides the created type, the function adds a custom object to the pipeline that can be used to clean up. CleanUp- AppDomainedType uses the custom object to unload the temporary AppDomain, remove the assembly from the GAC, and optionally delete the assembly. This how I use these functions: # create an interop dll, if it doesn't already exist if ( !( Test-Path "$( Get-Location )\InteropAssembly.dll" ) ) { Create-InteropAssembly "InteropAssembly.SomeClass" ` "InteropAssembly.dll" | Out-Null } if ( Test-Path "$( Get-Location )\InteropAssembly.dll" ) { # create a SomeClass in a temporary AppDomain $someObject, $appDomainedTypeInfo = Get-AppDomainedType ` "$( Get-Location )\InteropAssembly.dll" ` "InteropAssembly.SomeClass" # do some stuff with $someObject... # clean up the temporary AppDomain CleanUp-AppDomainedType $appDomainedTypeInfo -DeleteAssembly } This still has a problem: when the assembly containing the type is a COM interop assembly, the COM server continues to be locked up by powershell.exe even after the AppDomain is unloaded. The whole reason I started down this road was to try to use a COM server through an interop assembly without locking it up. I don't know what else to try. Jeff |
My System Specs![]() |
| | #5 (permalink) |
| | Re: Using an interop assembly with interop dependencies On Oct 8, 2:32 am, Jeff <jeff.hill...@xxxxxx> wrote: Quote: > On Oct 6, 6:39 am, Jeff <jeff.hill...@xxxxxx> wrote: > > > > > Quote: > > On Oct 5, 10:04 pm, Oisin Grehan <ois...@xxxxxx> wrote: Quote: Quote: > > > This is a large and complex topic; start here:http://groups.google.ca/group/micros...powershell/msg... Quote: Quote: > > > - Oisin Quote: > > I think I have read all of those articles in the past, but I learned a > > few new things this time around. Thanks for pointing them out > > again. Quote: > > I won't be able to try anything new until next week, but if I have any > > success, I will post back here. Quote: > > Thanks. Quote: > > Jeff > I ended up writing a few functions to take care of most of the work of > dealing with COM interop assemblies for me, as I do this sort of > thing a lot. > > Here they are: > > $SdkPath = "C:\Program Files\Microsoft.NET\SDK\v2.0\Bin" > > function Create-InteropAssembly( > [string] $progId = $(throw "You must specify a ProgId"), > [string] $assemblyName = $(throw "You must specify a name"), > [string] $path = ( Get-Location ) ) > { > $classes = "HKLM:\SOFTWARE\Classes" > > # find the path to the type library > $clsid = ( Get-Item ` > $classes\$progId\CLSID ).GetValue( "" ) > $tlbPath = ( Get-Item ` > $classes\CLSID\$clsid\InProcServer32 ).GetValue( "" ) > > # create a strong name key/value pair > if ( !( Test-Path "$path\keyPair.snk" ) ) > { > & "$SdkPath\sn.exe" -q -k "$path\keyPair.snk" > } > > # create the assembly > & "$SdkPath\TlbImp.exe" /silent /keyfile:$path\keyPair.snk ` > /out:$assemblyName $tlbPath > > # add the the path to the assembly to the pipeline > "$path\$assemblyName" > > } > > function Gac-Assembly( [string] $assemblyPath ) > { > & "$SdkPath\gacutil.exe" /silent /i $assemblyPath > > } > > function UnGac-Assembly( [string] $assemblyName ) > { > & "$SdkPath\gacutil.exe" /silent /u $assemblyName > > } > > function Get-AppDomainedType( > [string] $assemblyPath = $(throw "You must specify an assembly"), > [string] $typeName = $(throw "You must specify a name") ) > { > # put the assembly in the GAC > Gac-Assembly $assemblyPath > > # create a temporary AppDomain > $appDomain = [System.AppDomain]::CreateDomain( "TempAppDomain" ) > $appDomain.AppendPrivatePath( > ( Get-ChildItem $assemblyPath ).DirectoryName ) > > # create a new AssemblyName > $assemblyName = New-Object System.Reflection.AssemblyName > $assemblyName.Name = > ( Get-ChildItem $assemblyPath ).Name -replace ".dll" > $assemblyName.CodeBase = $assemblyPath > > # load the assembly into the new AppDomain > $assembly = $appDomain.Load( $assemblyName ) > > # create the type > $type = $appDomain.CreateInstanceFromAndUnwrap( $assemblyPath, > $typeName ) > > # put all the information about the type and AppDomain into > # an object that can be used to clean up later > $appDomainedTypeInfo = New-Object System.Object > > $appDomainedTypeInfo | Add-Member -MemberType NoteProperty ` > -Name AppDomain ` > -Value $appDomain > $appDomainedTypeInfo | Add-Member -MemberType NoteProperty ` > -Name AssemblyPath ` > -Value $assemblyPath > $appDomainedTypeInfo | Add-Member -MemberType NoteProperty ` > -Name AssemblyName ` > -Value $assemblyName.Name > > # add the type and the info object to the pipeline > $type > $appDomainedTypeInfo > > } > > function CleanUp-AppDomainedType( > [PSObject] $appDomainedTypeInfo, > [switch] $DeleteAssembly ) > { > # unload the temporary AppDomain > [System.AppDomain]::Unload( $appDomainedTypeInfo.AppDomain ) > > # remove the assembly from the GAC > UnGac-Assembly $appDomainedTypeInfo.AssemblyName > > if ( $DeleteAssembly ) > { > # delete the assembly > Remove-Item $appDomainedTypeInfo.AssemblyPath > } > > } > > Create-InteropAssembly uses the ProgId of a COM object to determine > the location of a Type Library that can be used to generate an > assembly using TlbImp. Get-AppDomainedType takes a path to an > assembly and the name of a type. It puts the assembly in the GAC, > creates a new AppDomain, loads the assembly into the new AppDomain, > and uses AppDomain.CreateInstanceFromAndUnwrap() to get an instance of > the specified type. Besides the created type, the function adds a > custom object to the pipeline that can be used to clean up. CleanUp- > AppDomainedType uses the custom object to unload the temporary > AppDomain, remove the assembly from the GAC, and optionally delete the > assembly. > > This how I use these functions: > > # create an interop dll, if it doesn't already exist > if ( !( Test-Path "$( Get-Location )\InteropAssembly.dll" ) ) > { > Create-InteropAssembly "InteropAssembly.SomeClass" ` > "InteropAssembly.dll" | Out-Null > > } > > if ( Test-Path "$( Get-Location )\InteropAssembly.dll" ) > { > # create a SomeClass in a temporary AppDomain > $someObject, $appDomainedTypeInfo = Get-AppDomainedType ` > "$( Get-Location )\InteropAssembly.dll" ` > "InteropAssembly.SomeClass" > > # do some stuff with $someObject... > > # clean up the temporary AppDomain > CleanUp-AppDomainedType $appDomainedTypeInfo -DeleteAssembly > > } > > This still has a problem: when the assembly containing the type is a > COM interop assembly, the COM server continues to be locked up by > powershell.exe even after the AppDomain is unloaded. The whole reason > I started down this road was to try to use a COM server through an > interop assembly without locking it up. I don't know what else to > try. > > Jeff- Hide quoted text - > > - Show quoted text - again, but this time add the /primary switch to tlbimp.exe, along with /keyfile. Then, register this assembly in the gac. Next, do NOT load this interop assembly directly. Instead, instantiate your com object with new-object directly, e.g. ps> $obj = new-object -COM myprogid.name The /primary switch marks the assembly with a special attribute (primary interop assembly attribute), which links that interop assembly to the com object by the typelib's guid. when you use new- object, the loader will automatically load your interop assembly into the default context (instead of probably into the loadfrom context which isolates your interop assembly from the default context which powershell sits in) and create your com object for you. additionally, if your com object is STA, new-object will ensure it is created in an STA for you. try this and let me know how you get on, - Oisin / x0n |
My System Specs![]() |
| | #6 (permalink) |
| | Re: Using an interop assembly with interop dependencies On Oct 10, 12:13 am, Oisin Grehan <ois...@xxxxxx> wrote: Quote: > Woah, getting hairy I see ;-) ok, try creating your interop assembly > again, but this time add the /primary switch to tlbimp.exe, along > with /keyfile. Then, register this assembly in the gac. Next, do NOT > load this interop assembly directly. Instead, instantiate your com > object with new-object directly, e.g. > > ps> $obj = new-object -COM myprogid.name > > The /primary switch marks the assembly with a special attribute > (primary interop assembly attribute), which links that interop > assembly to the com object by the typelib's guid. when you use new- > object, the loader will automatically load your interop assembly into > the default context (instead of probably into the loadfrom context > which isolates your interop assembly from the default context which > powershell sits in) and create your com object for you. additionally, > if your com object is STA, new-object will ensure it is created in an > STA for you. > > try this and let me know how you get on, > > - Oisin / x0n seem to make much of a difference. My COM DLL is still locked by powershell.exe after my script runs. The only other difference, other than not being able to use an enumeration, defined in the COM DLL, directly, since the assembly isn't loaded, is that the COM server seems to be the only file in the powershell process' Modules list that is related to what I am trying to do. When I load the interop assembly directly into the new AppDomain, there is also an entry in the Modules list for the assembly in the GAC: C:\WC:\WINDOWS\assembly\GAC_MSIL\...\InteropAssembly.dll This file isn't in the list when I create the object using New-Object - Com rather than AppDomain.CreateInstanceFromAndUnwrap(). Any other ideas? Jeff |
My System Specs![]() |
| | #7 (permalink) |
| | Re: Using an interop assembly with interop dependencies On Oct 9, 10:22 pm, Jeff <jeff.hill...@xxxxxx> wrote: Quote: > On Oct 10, 12:13 am, Oisin Grehan <ois...@xxxxxx> wrote: > > > > > Quote: > > Woah, getting hairy I see ;-) ok, try creating your interop assembly > > again, but this time add the /primary switch to tlbimp.exe, along > > with /keyfile. Then, register this assembly in the gac. Next, do NOT > > load this interop assembly directly. Instead, instantiate your com > > object with new-object directly, e.g. Quote: > > ps> $obj = new-object -COM myprogid.name Quote: > > The /primary switch marks the assembly with a special attribute > > (primary interop assembly attribute), which links that interop > > assembly to the com object by the typelib's guid. when you use new- > > object, the loader will automatically load your interop assembly into > > the default context (instead of probably into the loadfrom context > > which isolates your interop assembly from the default context which > > powershell sits in) and create your com object for you. additionally, > > if your com object is STA, new-object will ensure it is created in an > > STA for you. Quote: > > try this and let me know how you get on, Quote: > > - Oisin / x0n > Thanks for the help Oisin. Unfortunately, your suggestion doesn't > seem to make much of a difference. My COM DLL is still locked by > powershell.exe after my script runs. The only other difference, other > than not being able to use an enumeration, defined in the COM DLL, > directly, since the assembly isn't loaded, is that the COM server > seems to be the only file in the powershell process' Modules list that > is related to what I am trying to do. When I load the interop > assembly directly into the new AppDomain, there is also an entry in > the Modules list for the assembly in the GAC: > > C:\WC:\WINDOWS\assembly\GAC_MSIL\...\InteropAssembly.dll > > This file isn't in the list when I create the object using New-Object - > Com rather than AppDomain.CreateInstanceFromAndUnwrap(). > > Any other ideas? > Jeff- Hide quoted text - > > - Show quoted text - Ahhhh, when you said your "com server is locked up," I thought you meant frozen/unresponsive! I understand now that you meant the *physical DLL* is locked access-wise on disk. Sorry man, I was wandering down the wrong way completely (although the PIA stuff is still relevant). This is a different kettle of fish entirely... however: First off, *two* collections of the GC are needed to completely free up the COM reference after you've freed any psvariable references to it. Normally this should happen automatically (eventually), but regardless try calling [gc]::collect() explicitly twice and then checking to see if the com server dll has been unloaded - tbh, I'm not 100% sure if the .net interop layer will call FreeLibrary() for you (it should though, right people?). Perhaps someone from MSFT will chime in here. If this is not the case, you can probably call FreeLibrary yourself to unload the DLL from powershell.exe's process, but this is the filthiest of filthy hacks. Hope this helps, - Oisin / x0n |
My System Specs![]() |
| | #8 (permalink) |
| | Re: Using an interop assembly with interop dependencies On Oct 10, 11:36 pm, Oisin Grehan <ois...@xxxxxx> wrote: Quote: > On Oct 9, 10:22 pm, Jeff <jeff.hill...@xxxxxx> wrote: > > > Quote: > > On Oct 10, 12:13 am, Oisin Grehan <ois...@xxxxxx> wrote: Quote: Quote: > > > Woah, getting hairy I see ;-) ok, try creating your interop assembly > > > again, but this time add the /primary switch to tlbimp.exe, along > > > with /keyfile. Then, register this assembly in the gac. Next, do NOT > > > load this interop assembly directly. Instead, instantiate your com > > > object with new-object directly, e.g. Quote: Quote: > > > ps> $obj = new-object -COM myprogid.name Quote: Quote: > > > The /primary switch marks the assembly with a special attribute > > > (primary interop assembly attribute), which links that interop > > > assembly to the com object by the typelib's guid. when you use new- > > > object, the loader will automatically load your interop assembly into > > > the default context (instead of probably into the loadfrom context > > > which isolates your interop assembly from the default context which > > > powershell sits in) and create your com object for you. additionally, > > > if your com object is STA, new-object will ensure it is created in an > > > STA for you. Quote: Quote: > > > try this and let me know how you get on, Quote: Quote: > > > - Oisin / x0n Quote: > > Thanks for the help Oisin. Unfortunately, your suggestion doesn't > > seem to make much of a difference. My COM DLL is still locked by > > powershell.exe after my script runs. The only other difference, other > > than not being able to use an enumeration, defined in the COM DLL, > > directly, since the assembly isn't loaded, is that the COM server > > seems to be the only file in the powershell process' Modules list that > > is related to what I am trying to do. When I load the interop > > assembly directly into the new AppDomain, there is also an entry in > > the Modules list for the assembly in the GAC: Quote: > > C:\WC:\WINDOWS\assembly\GAC_MSIL\...\InteropAssembly.dll Quote: > > This file isn't in the list when I create the object using New-Object - > > Com rather than AppDomain.CreateInstanceFromAndUnwrap(). Quote: > > Any other ideas? > > Jeff- Hide quoted text - Quote: > > - Show quoted text - > Jeff, > > Ahhhh, when you said your "com server is locked up," I thought you > meant frozen/unresponsive! I understand now that you meant the > *physical DLL* is locked access-wise on disk. Sorry man, I was > wandering down the wrong way completely (although the PIA stuff is > still relevant). This is a different kettle of fish entirely... > however: > > First off, *two* collections of the GC are needed to completely free > up the COM reference after you've freed any psvariable references to > it. Normally this should happen automatically (eventually), but > regardless try calling [gc]::collect() explicitly twice and then > checking to see if the com server dll has been unloaded - tbh, I'm not > 100% sure if the .net interop layer will call FreeLibrary() for you > (it should though, right people?). Perhaps someone from MSFT will > chime in here. If this is not the case, you can probably call > FreeLibrary yourself to unload the DLL from powershell.exe's process, > but this is the filthiest of filthy hacks. > > Hope this helps, > > - Oisin / x0n be the best choice, and I guess I was right. Sorry for the confusion. I will try your latest suggestion and report back. Again, thanks for your time. Jeff |
My System Specs![]() |
| | #9 (permalink) |
| | Re: Using an interop assembly with interop dependencies On Oct 11, 6:49 am, Jeff <jeff.hill...@xxxxxx> wrote: Quote: > On Oct 10, 11:36 pm, Oisin Grehan <ois...@xxxxxx> wrote: > > > Quote: > > On Oct 9, 10:22 pm, Jeff <jeff.hill...@xxxxxx> wrote: Quote: Quote: > > > On Oct 10, 12:13 am, Oisin Grehan <ois...@xxxxxx> wrote: Quote: Quote: > > > > Woah, getting hairy I see ;-) ok, try creating your interop assembly > > > > again, but this time add the /primary switch to tlbimp.exe, along > > > > with /keyfile. Then, register this assembly in the gac. Next, do NOT > > > > load this interop assembly directly. Instead, instantiate your com > > > > object with new-object directly, e.g. Quote: Quote: > > > > ps> $obj = new-object -COM myprogid.name Quote: Quote: > > > > The /primary switch marks the assembly with a special attribute > > > > (primary interop assembly attribute), which links that interop > > > > assembly to the com object by the typelib's guid. when you use new- > > > > object, the loader will automatically load your interop assembly into > > > > the default context (instead of probably into the loadfrom context > > > > which isolates your interop assembly from the default context which > > > > powershell sits in) and create your com object for you. additionally, > > > > if your com object is STA, new-object will ensure it is created in an > > > > STA for you. Quote: Quote: > > > > try this and let me know how you get on, Quote: Quote: > > > > - Oisin / x0n Quote: Quote: > > > Thanks for the help Oisin. Unfortunately, your suggestion doesn't > > > seem to make much of a difference. My COM DLL is still locked by > > > powershell.exe after my script runs. The only other difference, other > > > than not being able to use an enumeration, defined in the COM DLL, > > > directly, since the assembly isn't loaded, is that the COM server > > > seems to be the only file in the powershell process' Modules list that > > > is related to what I am trying to do. When I load the interop > > > assembly directly into the new AppDomain, there is also an entry in > > > the Modules list for the assembly in the GAC: Quote: Quote: > > > C:\WC:\WINDOWS\assembly\GAC_MSIL\...\InteropAssembly.dll Quote: Quote: > > > This file isn't in the list when I create the object using New-Object - > > > Com rather than AppDomain.CreateInstanceFromAndUnwrap(). Quote: Quote: > > > Any other ideas? > > > Jeff- Hide quoted text - Quote: Quote: > > > - Show quoted text - Quote: > > Jeff, Quote: > > Ahhhh, when you said your "com server is locked up," I thought you > > meant frozen/unresponsive! I understand now that you meant the > > *physical DLL* is locked access-wise on disk. Sorry man, I was > > wandering down the wrong way completely (although the PIA stuff is > > still relevant). This is a different kettle of fish entirely... > > however: Quote: > > First off, *two* collections of the GC are needed to completely free > > up the COM reference after you've freed any psvariable references to > > it. Normally this should happen automatically (eventually), but > > regardless try calling [gc]::collect() explicitly twice and then > > checking to see if the com server dll has been unloaded - tbh, I'm not > > 100% sure if the .net interop layer will call FreeLibrary() for you > > (it should though, right people?). Perhaps someone from MSFT will > > chime in here. If this is not the case, you can probably call > > FreeLibrary yourself to unload the DLL from powershell.exe's process, > > but this is the filthiest of filthy hacks. Quote: > > Hope this helps, Quote: > > - Oisin / x0n > I was thinking as I was writing "locked up" that those words might not > be the best choice, and I guess I was right. Sorry for the > confusion. I will try your latest suggestion and report back. > > Again, thanks for your time. > > Jeff side effect of making the DLL unusable for the remainder of the session. I'm really not sure what is going on. If I try the whole process again, when I try to create the type, using either New-Object or AppDomain.CreateInstanceFromAndUnwrap(), I get this error: Exception calling "CreateInstanceFromAndUnwrap" with "2" argument(s): "Retrieving the COM class factory for component with CLSID {...} failed due to the following error: 80010105." 80010105 is the code for "Unknown OLE Error"; I didn't like that approach anyway. Calling [gc]::Collect() didn't seem to have an effect, but after trying a few other things, I'm not really sure what to think. I tried several different combinations of [gc]::Collect(), [System.Runtime.InteropServices.Marshal]::ReleaseComObject(), and CoFreeUnusedLibraries in ole32.dll, and eventually, the DLL would be freed. I was unable to consistently make it happen though, so I don't know which and in what order these need to be called. ReleaseComObject, Collect, and CoFreeUnusedLibraries makes the most sense to me, but that never seemed to work, at least not right away. It seems like a certain amount of waiting is also necessary, so one or more of these steps might not even be necessary, once the mysterious correct step is taken. If any of this raises any flags for you, please let me know. I would love to find a consistent resolution for this. Jeff |
My System Specs![]() |
![]() |
| Thread Tools | |
| |
Similar Threads | ||||
| Thread | Forum | |||
| Interop | .NET General | |||
| Microsoft.VirtualServer.Interop.dll and the Microsoft.VMRCClientControl.Interop.dll | Virtual Server | |||
| To Reference Interop.XXX.dll or XXX.dll | .NET General | |||
| Why can't I use Interop assembly instead of COM? | PowerShell | |||