使用COM Interop的依赖项注册程序集

时间:2017-02-16 17:48:18

标签: c# .net visual-studio com registry

提前抱歉所有代码......

我正在尝试创建一个名为" CliParser"的Visual Studio自定义工具,并且有一段艰难时期。在我的VS解决方案中,我有一个名为CliParser的项目依赖于名为Danware.COM的项目。 Danware.COM处理将COM类注册为VS自定义工具的样板,其中包含一个名为VsSingleFileGenerator的抽象类和一个名为VsCustomToolAttribute的属性。然后,CliParser定义了一个名为CliParser的类,它继承VsSingleFileGenerator并具有[VsCustomTool]属性。这两个项目都已经签署,并且已经注册了COM Interop"已检查属性,并且正在定位"任何CPU"。构建成功完成,没有任何COM注册错误。

然而,我无法在任何COM客户端找到CliParser! Visual Studio和MS Excel都不会在“添加引用”菜单中显示它。即使我手动运行regasm.exe / tlb(32- 64位版本),它也表示所有内容都已成功导出/注册,但引用不会出现在这些COM客户端中。如何能够毫无错误地构建/注册所有内容,但实际的COM类型是不可用的?我可以想象的是,我正在将这个继承层次结构拆分为汇编。所有相关代码如下所示。如果有人能发现我错过的东西,我将非常感激

以下是VsSingleFileGenerator

using System;
using System.Runtime.InteropServices;

using Microsoft.Win32;
using Microsoft.VisualStudio.Shell.Interop;

namespace Danware.COM {

    [ComVisible(true)]
    [Guid("A298E59F-2B16-4E2F-A5CC-61FE4B7CA676")]
    public abstract class VsSingleFileGenerator : IVsSingleFileGenerator {

        public abstract int DefaultExtension(out string pbstrDefaultExtension);
        public abstract int Generate(string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace, IntPtr[] rgbOutputFileContents, out uint pcbOutput, IVsGeneratorProgress pGenerateProgress);

        [ComRegisterFunction]
        private static void RegisterClass(Type t) {
            var ga = t.GetCustomAttribute<GuidAttribute>(true);
            var cta = t.GetCustomAttribute<VsCustomToolAttribute>(true);
            string keyName = getKeyName(cta.LanguageGuid, cta.Name);
            using (RegistryKey key = Registry.LocalMachine.CreateSubKey(keyName)) {
                key.SetValue("", cta.Description);
                key.SetValue("CLSID", $"{{{ga.Value}}}");
                key.SetValue("GeneratesDesignTimeSource", 1);
            }
        }

        [ComUnregisterFunction]
        private static void UnregisterClass(Type t) {
            var cta = t.GetCustomAttribute<VsCustomToolAttribute>(true);
            string keyName = getKeyName(cta.LanguageGuid, cta.Name);
            Registry.LocalMachine.DeleteSubKey(keyName, false);
        }

        private static string getKeyName(string languageGuid, string customToolName) {
            return $"SOFTWARE\\Microsoft\\VisualStudio\\14.0\\Generators\\{{{languageGuid}}}\\{customToolName}\\";
        }

    }

}

以下是VsCustomToolAttribute

using System;
using System.Collections.Generic;

namespace Danware.COM {

    public enum VsLanguage {
        CSharp,
    }

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
    public class VsCustomToolAttribute : Attribute {

        private IDictionary<VsLanguage, string> _langGuids = new Dictionary<VsLanguage,string>() {
            { VsLanguage.CSharp, "FAE04EC1-301F-11D3-BF4B-00C04F79EFBC" },
        };

        public VsCustomToolAttribute(string name) : 
            this(name, VsLanguage.CSharp, "") { }

        public VsCustomToolAttribute(string name, string description) :
            this(name, VsLanguage.CSharp, description)
        {
            Name = name;
            Description = description;
        }

        public VsCustomToolAttribute(string name, VsLanguage language, string description) {
            Name = name;
            LanguageGuid = _langGuids[language];
            Description = description;
        }

        public string Name { get; }

        public string LanguageGuid { get; }

        public string Description { get; }
    }

}

这是CliParser

using System;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

using Danware.COM;

using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;

namespace CliParser {

    [ComVisible(true)]
    [Guid("F4BA90DA-E459-4889-8E14-AF27FC7437DC")]
    [VsCustomTool("CliParser", "Generates a strongly typed class to faciliate implementating a command line interface")]
    public class CliParser : VsSingleFileGenerator {

        public override int DefaultExtension(out string pbstrDefaultExtension) {
            pbstrDefaultExtension = ".txt";
            return pbstrDefaultExtension.Length;
        }
        public override int Generate(string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace, IntPtr[] rgbOutputFileContents, out uint pcbOutput, IVsGeneratorProgress pGenerateProgress) {
            try {
                byte[] bytes = Encoding.UTF8.GetBytes("OMG did we actually make it??");
                int length = bytes.Length;
                rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(length);
                Marshal.Copy(bytes, 0, rgbOutputFileContents[0], length);
                pcbOutput = (uint)length;
            }
            catch (Exception ex) {
                MessageBox.Show(ex.ToString());
                pcbOutput = 0;
            }
            return VSConstants.S_OK;
        }

    }

}

编辑:以下是VS构建过程创建的CliParser.tlb的内容:

// Generated .IDL file (by the OLE/COM Object Viewer)
// 
// typelib filename: CliParser.tlb

[
  uuid(6C2440B0-A869-4983-A8CA-4FF470C64F18),
  version(1.0),
  helpstring("Generates a strongly typed class to faciliate implementating a command line interface"),
  custom(90883F05-3D28-11D2-8F17-00A0C9A6186D, "CliParser, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5e32040c76b2825f")

]
library CliParser
{
    // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
    importlib("mscorlib.tlb");
    // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    importlib("stdole2.tlb");

    // Forward declare all types defined in this typelib
    interface _CliParser;

    [
      uuid(F4BA90DA-E459-4889-8E14-AF27FC7437DC),
      version(1.0),
      custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "CliParser.CliParser")
    ]
    coclass CliParser {
        [default] interface _CliParser;
        interface _Object;
    };

    [
      odl,
      uuid(0AEBD8C3-E835-3921-8830-CCB69042366B),
      hidden,
      dual,
      oleautomation,
      custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "CliParser.CliParser")    

    ]
    interface _CliParser : IDispatch {
    };
};

0 个答案:

没有答案