none
Invoking an Interop Toolkit form from VBA with registration free com (SxS)

    Question

  • My employer has a legacy system running in MS Access (yes, I know). We have used the Interop Forms Toolkit to add functionality to this software. All well and good, but we have a troublesome client.

    The core of the problem is this. This client runs our software in a Citrix session. We are not allowed access to the machines that are part of the system in order to install our software normally. Instead, when a user logs on, it copies the Access file and supporting files to a certain location, and runs it. The users don't have the required registry access to register our .Net COM component normally. We're currently getting around the restriction by manually entering the COM information into HKEY_CURRENT_USER, but this definitely has a 'house of cards' feel to it, particularly seeing as there doesn't seem to be a way to automate the TLB registration.

    It seems to me that Registration Free COM using the Activation Context API would be a good solution to the problem. However, I have been unable to get it to work. Specifically, I can't get loading the assemblies from a specific directory to work. Obviously I can't use the normal options of placing the assemblies in the GAC or the executable directory, as users lack write access to the GAC, and I wouldn't want to put them in the MS Office directory even if I could.

    Private Declare Function CreateActCtx Lib "kernel32" Alias "CreateActCtxA" (ByRef pActCtx As ACTCTX_) As Long
    Private Declare Sub ReleaseActCtx Lib "kernel32" (ByVal hActCtx As Long)
    
    Private Declare Function ActivateActCtx Lib "kernel32" (ByVal hActCtx As Long, ByRef lpCookie As Long) As Boolean
    Private Declare Function DeactivateActCtx Lib "kernel32" (ByVal dwFlags As Long, ByRef ulCookie As Long) As Boolean
    
    Private Type ACTCTX_
        cbSize As Long
        dwFlags As Long
        lpSource As String
        wProcessorArchitecture As Integer
        wLangId As Integer
        lpAssemblyDirectory As String
        lpResourceName As String
        lpApplicationName As String
        hModule As Long
    End Type
        Dim actctx As ACTCTX_
        Dim res As Boolean
        
        actctx.cbSize = Len(actctx)
        actctx.dwFlags = 4
        actctx.lpAssemblyDirectory = Application.CurrentProject.path
        actctx.lpSource = Application.CurrentProject.path & "\root.manifest"
        
        actHandle = CreateActCtx(actctx)
        
        res = ActivateActCtx(actHandle, actCookie)

    I realise I should be checking actHandle, but I'll worry about that once I have the code actually working.

    As an aside, when I try to clean up after myself, Access crashes at the first line of the following block:

        Call DeactivateActCtx(0, actCookie)
        Call ReleaseActCtx(actHandle)

    The API documentation does mention the function may throw an exception, but I don't think any of the conditions under which it might do this are occurring, and I'm not sure how I should catch an exception in MS Access, anyway. I'm sure On Error Goto won't help if Access itself is crashing.

    I've seen numerous places (such as here) suggesting that lpAssemblyDirectory is ignored if you declare your COM classes in the manifest pointed to by lpSource, so I have tried creating a root manifest that does nothing but pull in another manifest containing the actual definitions. I've also tried embedding the manifest with the definitions into the .Net assembly in question. In all cases, I have observed using Process Monitor that the assembly is always being searched for in the GAC and Office directories, and not the directory I specified.

    sxstrace output:

    =================
    Begin Activation Context Generation.
    Input Parameter:
    	Flags = 0
    	ProcessorArchitecture = Wow32
    	CultureFallBacks = en-US;en
    	ManifestPath = D:\Work\External\ARTC\root.manifest
    	AssemblyDirectory = D:\Work\External\ARTC
    	Application Config File = 
    -----------------
    INFO: Parsing Manifest File D:\Work\External\ARTC\root.manifest.
    	INFO: Manifest Definition Identity is (null).
    	INFO: Reference: BridgeAsyst.MaintenancePlanner.InteropSharp,processorArchitecture="msil",publicKeyToken="400bedca77b57754",version="1.0.0.2"
    INFO: Resolving reference BridgeAsyst.MaintenancePlanner.InteropSharp,processorArchitecture="msil",publicKeyToken="400bedca77b57754",version="1.0.0.2".
    	INFO: Resolving reference for ProcessorArchitecture msil.
    		INFO: Resolving reference for culture Neutral.
    			INFO: Applying Binding Policy.
    				INFO: No publisher policy found.
    				INFO: No binding policy redirect found.
    			INFO: Begin assembly probing.
    				INFO: Did not find the assembly in WinSxS.
    				INFO: Attempt to probe manifest at C:\Windows\assembly\GAC_MSIL\BridgeAsyst.MaintenancePlanner.InteropSharp\1.0.0.2__400bedca77b57754\BridgeAsyst.MaintenancePlanner.InteropSharp.DLL.
    				INFO: Attempt to probe manifest at D:\Work\External\ARTC\BridgeAsyst.MaintenancePlanner.InteropSharp.DLL.
    				INFO: Attempt to probe manifest at D:\Work\External\ARTC\BridgeAsyst.MaintenancePlanner.InteropSharp.MANIFEST.
    				INFO: Manifest found at D:\Work\External\ARTC\BridgeAsyst.MaintenancePlanner.InteropSharp.MANIFEST.
    			INFO: End assembly probing.
    INFO: Resolving reference BridgeAsyst.MaintenancePlanner.InteropSharp.mui,language="*",processorArchitecture="msil",publicKeyToken="400bedca77b57754",version="1.0.0.2".
    	INFO: Resolving reference for ProcessorArchitecture msil.
    		INFO: Resolving reference for culture en-US.
    			INFO: Applying Binding Policy.
    				INFO: No publisher policy found.
    				INFO: No binding policy redirect found.
    			INFO: Begin assembly probing.
    				INFO: Did not find the assembly in WinSxS.
    				INFO: Attempt to probe manifest at C:\Windows\assembly\GAC_MSIL\BridgeAsyst.MaintenancePlanner.InteropSharp.mui\1.0.0.2_en-US_400bedca77b57754\BridgeAsyst.MaintenancePlanner.InteropSharp.mui.DLL.
    				INFO: Did not find manifest for culture en-US.
    			INFO: End assembly probing.
    		INFO: Resolving reference for culture en.
    			INFO: Applying Binding Policy.
    				INFO: No publisher policy found.
    				INFO: No binding policy redirect found.
    			INFO: Begin assembly probing.
    				INFO: Did not find the assembly in WinSxS.
    				INFO: Attempt to probe manifest at C:\Windows\assembly\GAC_MSIL\BridgeAsyst.MaintenancePlanner.InteropSharp.mui\1.0.0.2_en_400bedca77b57754\BridgeAsyst.MaintenancePlanner.InteropSharp.mui.DLL.
    				INFO: Did not find manifest for culture en.
    			INFO: End assembly probing.
    INFO: Parsing Manifest File D:\Work\External\ARTC\BridgeAsyst.MaintenancePlanner.InteropSharp.MANIFEST.
    	INFO: Manifest Definition Identity is BridgeAsyst.MaintenancePlanner.InteropSharp,processorArchitecture="msil",publicKeyToken="400bedca77b57754",version="1.0.0.2".
    INFO: Activation Context generation succeeded.
    End Activation Context Generation.
    

    root.manifest:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    	<dependency>
    		<dependentAssembly>
    			<assemblyIdentity name="BridgeAsyst.MaintenancePlanner.InteropSharp" 
    							  version="1.0.0.2" 
    							  publicKeyToken="400bedca77b57754" 
    							  processorArchitecture="msil">
    			</assemblyIdentity>
    		</dependentAssembly>
    	</dependency>
    </assembly>

    BridgeAsyst.MaintenancePlanner.InteropSharp.manifest:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    	<assemblyIdentity name="BridgeAsyst.MaintenancePlanner.InteropSharp" 
    					  version="1.0.0.2" 
    					  publicKeyToken="400bedca77b57754" 
    					  processorArchitecture="msil">
    	</assemblyIdentity>
    	<clrClass clsid="{63C02978-67EB-3A45-B7EC-E6A7B7C6ED1A}" 
    			  progid="BridgeAsyst.MaintenancePlanner.InteropSharp.SimpleEventHandler" 
    			  threadingModel="Both" 
    			  name="BridgeAsyst.MaintenancePlanner.InteropSharp.SimpleEventHandler" 
    			  runtimeVersion="v2.0.50727">
    	</clrClass>
    	<clrClass clsid="{D53E20B1-CA46-324B-AF81-0EF8B6FE4795}" 
    			  progid="BridgeAsyst.MaintenancePlanner.InteropSharp.OpenByIdRequestHandler" 
    			  threadingModel="Both" 
    			  name="BridgeAsyst.MaintenancePlanner.InteropSharp.OpenByIdRequestHandler" 
    			  runtimeVersion="v2.0.50727">
    	</clrClass>
    	<clrClass clsid="{103EF228-3610-494F-A4EA-77E435B96F73}" 
    			  progid="BridgeAsyst_MaintenancePlanner.InteropMaintenancePlanner" 
    			  threadingModel="Both" 
    			  name="Interop.InteropMaintenancePlanner" 
    			  runtimeVersion="v2.0.50727">
    	</clrClass>
    	<file name="BridgeAsyst.MaintenancePlanner.InteropSharp.dll" hashalg="SHA1">
    	</file>
    </assembly>
    
    Any suggestions would help.
    • Moved by Shanks Zen Friday, June 15, 2012 2:55 AM To provide better support (From:Visual Basic Interop and Upgrade)
    Wednesday, June 13, 2012 6:39 AM

All replies

  • Hi T Dixon,

    According to your description, this issue is more relevant to VBA. I'll move it to VBA forum for better support. Thanks for your understanding!

    Best regards,


    Shanks Zen
    MSDN Community Support | Feedback to us

    Friday, June 15, 2012 2:54 AM
  • Honestly, I think it's more of an API question, but I couldn't find a section for that.
    Friday, July 06, 2012 2:19 AM
  • Hi T Dixon,

    have a look at

    http://social.msdn.microsoft.com/Forums/de-DE/dotnetframeworkde/thread/b25144d7-f99a-4951-b16e-b1e1d1194207

    Best Regards

    bbfromgb

    Friday, July 06, 2012 9:43 AM
  • Did you find an answer for this and get it working?  Thanks Hugh
    Tuesday, August 28, 2012 3:35 PM