通过Activation Context API使用免注册COM

关于免注册COM的使用,Simplify App Deployment with ClickOnce and Registration-Free COM 已经有了很详细的介绍。正如该文指出的,Windows会在CreateProcess的早期阶段根据*.exe.manifest创建一个内部表供将来CoCreateInstance使用。如果你无法控制exe.manifest,譬如你需要在Office Word Add-in中使用免注册COM,你不能也不应该修改Word.exe.manifest,那么这种方法就不灵了。

幸好Microsoft提供了Activation Context API。Programming the Activation Context API 详细介绍了如何在C++/C#中使用Activation Context API。下面通过一个简单例子来介绍其具体使用:

1。PInvoke帮助类

ExpandedBlockStart.gif 代码
     public   static   class  NativeActivationCtxApi
    {
        [StructLayout(LayoutKind.Sequential, Pack 
=   4 , CharSet  =  CharSet.Unicode)]
        
public   struct  ACTCTX
        {
            
public   int  cbSize;
            
public   uint  dwFlags;
            
public   string  lpSource;
            
public   ushort  wProcessorArchitecture;
            
public  Int16 wLangId;
            
public   string  lpAssemblyDirectory;
            
public   string  lpResourceName;
            
public   string  lpApplicationName;
            
public  IntPtr hModule;
        }

        [DllImport(
" Kernel32.dll " , SetLastError  =   true )]
        
public   static   extern  IntPtr CreateActCtxW( ref  ACTCTX pActCtx);

        [DllImport(
" Kernel32.dll " , SetLastError  =   true )]
        [
return : MarshalAs(UnmanagedType.Bool)]
        
public   static   extern   bool  ActivateActCtx(IntPtr hActCtx,  out  IntPtr lpCookie);

        [DllImport(
" Kernel32.dll " , SetLastError  =   true )]
        [
return : MarshalAs(UnmanagedType.Bool)]
        
public   static   extern   bool  DeactivateActCtx( int  dwFlags, IntPtr lpCookie);

        [DllImport(
" Kernel32.dll " , SetLastError  =   true )]
        
public   static   extern   void  ReleaseActCtx(IntPtr hActCtx);

        
public   const   int  ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID  =   0x004 ;
    }
    
public   static   class  ActivationCtx
    {
        
public   static   bool  Activate(Action action,  string  manifestPath,  string  assemblyRootDir)
        {
            NativeActivationCtxApi.ACTCTX ac 
=   new  NativeActivationCtxApi.ACTCTX();
            ac.cbSize 
=  Marshal.SizeOf( typeof (NativeActivationCtxApi.ACTCTX));
            ac.lpAssemblyDirectory 
=  assemblyRootDir;
            ac.lpSource 
=  manifestPath;
            ac.dwFlags 
=  NativeActivationCtxApi.ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
            IntPtr cookie;
            IntPtr hActCtx 
=  NativeActivationCtxApi.CreateActCtxW( ref  ac);

            
if  (hActCtx  ==  (IntPtr)( - 1 ))
                
return   false ;

            
if  (NativeActivationCtxApi.ActivateActCtx(hActCtx,  out  cookie))
            {
                
try
                {
                    action();
                }
                
finally
                {
                    NativeActivationCtxApi.DeactivateActCtx(
0 , cookie);
                }
            }
            
else
            {
                
return   false ;
            }
            NativeActivationCtxApi.ReleaseActCtx(hActCtx);
            
return   true ;
        }
    }

 

2. COM组件及对应的manifest,这里以dsofile.dll(下载)为例,你可以在dsofile安装目录下运行VS命令行工具mt -tlb:dsofile.dll -dll:dsofile.dll -identity:dsofile.x,type=win32,version=1.0.0.0 -out:dsofile.x.manifest生成必要的manifest file:dsofile.x.manifest

 

ExpandedBlockStart.gif 代码
<? xml version="1.0" encoding="UTF-8" standalone="yes" ?>
< assembly  xmlns ="urn:schemas-microsoft-com:asm.v1"  manifestVersion ="1.0" >
  
< assemblyIdentity  name ="dsofile.x"  type ="win32"  version ="1.0.0.0" ></ assemblyIdentity >
  
< file  name ="dsofile.dll"  hashalg ="SHA1" >
    
< comClass  clsid =" {58968145-CF05-4341-995F-2EE093F6ABA3} "  tlbid =" {58968145-CF00-4341-995F-2EE093F6ABA3} "  description ="DSOFile OleDocumentProperties" ></ comClass >
    
< typelib  tlbid =" {58968145-CF00-4341-995F-2EE093F6ABA3} "  resourceid ="1"  version ="2.1"  helpdir =""  flags ="HASDISKIMAGE" ></ typelib >
  
</ file >
  
< comInterfaceExternalProxyStub  name ="CustomProperty"  iid =" {58968145-CF03-4341-995F-2EE093F6ABA3} "  tlbid =" {58968145-CF00-4341-995F-2EE093F6ABA3} "  proxyStubClsid32 =" {00020424-0000-0000-C000-000000000046} " >
  
</ comInterfaceExternalProxyStub >
  
< comInterfaceExternalProxyStub  name ="CustomProperties"  iid =" {58968145-CF04-4341-995F-2EE093F6ABA3} "  tlbid =" {58968145-CF00-4341-995F-2EE093F6ABA3} "  proxyStubClsid32 =" {00020424-0000-0000-C000-000000000046} " >
  
</ comInterfaceExternalProxyStub >
  
< comInterfaceExternalProxyStub  name ="SummaryProperties"  iid =" {58968145-CF02-4341-995F-2EE093F6ABA3} "  tlbid =" {58968145-CF00-4341-995F-2EE093F6ABA3} "  proxyStubClsid32 =" {00020424-0000-0000-C000-000000000046} " >
  
</ comInterfaceExternalProxyStub >
  
< comInterfaceExternalProxyStub  name ="_OleDocumentProperties"  iid =" {58968145-CF01-4341-995F-2EE093F6ABA3} "  tlbid =" {58968145-CF00-4341-995F-2EE093F6ABA3} "  proxyStubClsid32 =" {00020424-0000-0000-C000-000000000046} " >
  
</ comInterfaceExternalProxyStub >
</ assembly >

 

 

3.直接传给Activation Context的manifest: regFree.manifest

ExpandedBlockStart.gif代码

<? xml version="1.0" encoding="UTF-8" standalone="yes" ?>
< assembly  xmlns ="urn:schemas-microsoft-com:asm.v1"  manifestVersion ="1.0" >
  
< assemblyIdentity  type ="win32"  name ="regFree"  version ="1.0.0.0"   />
  
< dependency >
    
< dependentAssembly >
      
< assemblyIdentity
                  
type ="win32"
                  name
="dsofile.x"
                  version
="1.0.0.0"   />
    
</ dependentAssembly >
  
</ dependency >
</ assembly >

 

4. 在你的程序中使用Activation Context,假设dsofile.dll以及dsofile.x.manifest位于c:\dsofile

 

ExpandedBlockStart.gif 代码
         private   void  CreateAndUseDso()
        {
            OleDocumentProperties properties 
=   new  OleDocumentProperties();
            properties.Open(
" c:\\my.doc " true , dsoFileOpenOptions.dsoOptionOnlyOpenOLEFiles);
        }

        
private   void  UseContext()
        {

            ActivationCtx.Activate(CreateAndUseDso, 
" d:\\yourApp\\regFree.manifest " " c:\\dsofile " );
        }

 

 

在这里有一点需要指出的是,貌似第三步的regFree.manifest可以不需要,可以在第四步中直接传入dsofile.x.manifest。满足下面条件之一你的确可以这么做:

a。你的程序运行在Windows 7上(没有在Vista上测过)

b。你可以确保COM dll和application(your executable)位于同一目录下

在XP/2003下,如果你在传入context api的manifest中直接指定COM文件,系统会忽略掉你指定的lpAssemblyDirectory而直接在程序exe的目录下寻找COM,有兴趣的可以通过Process Monitor来验证这一点。

 

转载于:https://www.cnblogs.com/wyong27/archive/2010/08/01/1789961.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值