创建属于自己的OneNote插件

OneNote是一款很受欢迎的笔记软件,其分章节的结构特点非常适合记录课堂笔记,读书笔记和知识体系,但与Office其他明星产品相比,OneNote的资历更短,功能也不及Word、Excel强大,还好我们可以通过AddIn来扩展OneNote的功能。

发现国内OneNote插件开发的资料基本没有,好不容易找到两篇也是针对2010版的开发,在此附上链接:

http://www.malteahrens.com/#/blog/howto-onenote-dev/

https://support.microsoft.com/en-us/help/2555352/how-to-develop-an-onenote-2010-ribbon-add-in-application

现在正式进入开发阶段,由于涉及注册表,所以需要以管理员权限打开VS,不然会无法生成工程的。

第一步:创建工程

首先要完善开发环境,OneNote二次开发不像Word、Excel有现成的VSTO工具,需要创建安装和部署的工程,已有教程中都是用VS2010自带的安装和部署工具来安装测试,VS2015移除了该功能,需要手动安装一个部署软件,这是地址Microsoft Visual Studio 2015 Installer Projects

接下来创建工程,我们需要创建一个类库,如图

工程创建好后设置工程属性,在程序集信息中勾选使程序集COM可见,

在生成中勾选为COM互操作注册

第二步:创建Ribbon配置文件

1.添加一个叫ribbon的XML文件

2.将配置文件存入工程资源以便运行时访问

3.写ribbon配置文件代码

此处我们添加一个叫做Custom的Ribbon选项卡

<?xml version="1.0" encoding="utf-8" ?>
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" loadImage="GetImage">
  <ribbon>
    <tabs>
      <tab id="tabCustom" label="Custom">
        <group id="groupHello" label="Hello">
          <button id="buttonHello" label="Hello World!" size="large" screentip="Press this for a ‘Hello World!‘ message" onAction="showHello" image="HelloWorld.png" />
        </group>
      </tab>
    </tabs>
  </ribbon>
</customUI>

如果想在已有选项卡中添加功能,只需要将tab中的值改为idMso="指定Tab页"即可

第三部:写功能代码

1.为工程添加引用,这里主要需要添加三个引用,分别是:Extensibility,office和Microsoft OneNote 15.0 Type Library

2.在Class1中添加如下using



using System.Runtime.InteropServices;
using Extensibility;
using Microsoft.Office.Core;
using OneNote = Microsoft.Office.Interop.OneNote;

3.创建一个新的GUID以标识工程

  工具→创建GUID(G)

  

  将创建的GUID粘贴到记事本,之后还要用

4.在Class1上添加标记

[Guid("743A0108-BBE3-4D22-A6A8-3C00ADD2B610"), ProgId("HelloWorld.Class1")]
public class Class1
{
}

5.实现接口IDTExtensibility2

  IDTExtensibility2来自Extensibility名空间,需要实现以下方法:  

public void OnAddInsUpdate(ref Array custom) { }
public void OnBeginShutdown(ref Array custom) { }
public void OnConnection(object Application, ext_ConnectMode ConnectMode, object AddInInst, ref Array custom) { }
public void OnDisconnection(ext_DisconnectMode RemoveMode, ref Array custom) { }
public void OnStartupComplete(ref Array custom) { }

6.OnConnection()方法在插件加载时调用,传递了OneNote的实例,我们创建一个object类型的变量application来接收

private object application;
public void OnConnection(object Application, ext_ConnectMode ConnectMode, object AddInInst, ref Array custom)
{
    application = Application;
}

7.为了实现Ribbon按钮事件,需要添加IRibbonExtensibility接口,IRibbonExtensibility来自Microsoft.Office.Core名空间,包含获取Ribbon界面的方法

public string GetCustomUI(string RibbonID)
{
   return Properties.Resources.ribbon;
}

此时返回工程中的ribbon.xml配置信息

8.现在实现与ribbon.xml文件中按钮的onAction事件调用的函数,注意此函数是公共的并且以IRibbonControl作为参数

public void showHello(IRibbonControl control)
{
    var app = application as OneNote.Application;
    var win = app.Windows;
    string id = (application as OneNote.Application).Windows.CurrentWindow.CurrentPageId;
    string title;
    app.GetPageContent(id, out title);
    var doc = XDocument.Parse(title);
    string pageTitle = doc.Descendants().FirstOrDefault().Attribute("ID").NextAttribute.Value;
    MessageBox.Show("Current Page = " + pageTitle, "Hello World!");
}

这里实现了输出当前页标题的功能。

9.为Ribbon按钮添加图片,需要将图片添加到资源中

还要实现ribbon.xml中loadImage的GetImage方法

public IStream GetImage(string imageName)
{
    MemoryStream mem = new MemoryStream();
    Properties.Resources.HelloWorld.Save(mem, ImageFormat.Png);
    return new CCOMStreamWrapper(mem);
}

这里采用将图片转为流的方式

class CCOMStreamWrapper: IStream
{
    public CCOMStreamWrapper(System.IO.Stream streamWrap)
    {
        m_stream = streamWrap;
    }

    public void Clone(out IStream ppstm)
    {
        ppstm = new CCOMStreamWrapper(m_stream);
    }

    public void Commit(int grfCommitFlags)
    {
        m_stream.Flush();
    }

    public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
    {
    }

    public void LockRegion(long libOffset, long cb, int dwLockType)
    {
        throw new System.NotImplementedException();
    }

    public void Read(byte[] pv, int cb, IntPtr pcbRead)
    {
        Marshal.WriteInt64(pcbRead, m_stream.Read(pv, 0, cb));
    }

    public void Revert()
    {
        throw new System.NotImplementedException();
    }

    public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
    {
        long posMoveTo = 0;
        Marshal.WriteInt64(plibNewPosition, m_stream.Position);
        switch (dwOrigin)
        {
            case 0:
                {
                    /* STREAM_SEEK_SET */
                    posMoveTo = dlibMove;
                }
                break;
            case 1:
                {
                    /* STREAM_SEEK_CUR */
                    posMoveTo = m_stream.Position + dlibMove;

                }
                break;
            case 2:
                {
                    /* STREAM_SEEK_END */
                    posMoveTo = m_stream.Length + dlibMove;
                }
                break;
            default:
                return;
        }
        if (posMoveTo >= 0 && posMoveTo < m_stream.Length)
        {
            m_stream.Position = posMoveTo;
            Marshal.WriteInt64(plibNewPosition, m_stream.Position);
        }
    }

    public void SetSize(long libNewSize)
    {
        m_stream.SetLength(libNewSize);
    }

    public void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag)
    {
        pstatstg = new System.Runtime.InteropServices.ComTypes.STATSTG();
        pstatstg.cbSize = m_stream.Length;
        if ((grfStatFlag & 0x0001/* STATFLAG_NONAME */) != 0)
            return;
        pstatstg.pwcsName = m_stream.ToString();
    }

    public void UnlockRegion(long libOffset, long cb, int dwLockType)
    {
        throw new System.NotImplementedException();
    }

    public void Write(byte[] pv, int cb, IntPtr pcbWritten)
    {
        Marshal.WriteInt64(pcbWritten, 0);
        m_stream.Write(pv, 0, cb);
        Marshal.WriteInt64(pcbWritten, cb);
    }

    private System.IO.Stream m_stream;
}

10.当关闭OneNote的时候要确保清空占用的内存

public void OnDisconnection(ext_DisconnectMode RemoveMode, ref Array custom)
{
    application = null;
    GC.Collect();
    GC.WaitForPendingFinalizers();
}
public void OnBeginShutdown(ref Array custom)
{
    if (application != null)
    {
        application = null;
    }
}

11.Class1的全部代码如下:

using System;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Windows.Forms;
using System.Xml.Linq;
using Extensibility;
using Microsoft.Office.Core;
using OneNote = Microsoft.Office.Interop.OneNote;

namespace HelloWorld
{
    [Guid("743A0108-BBE3-4D22-A6A8-3C00ADD2B610"), ProgId("HelloWorld.Class1")]
    public class Class1: IDTExtensibility2, IRibbonExtensibility
    {
        private OneNote.Application onApp = new OneNote.Application();
        private object application;
        public void OnConnection(object Application, ext_ConnectMode ConnectMode, object AddInInst, ref Array custom)
        {
            application = Application;
        }

        public void OnDisconnection(ext_DisconnectMode RemoveMode, ref Array custom)
        {
            application = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        public void OnAddInsUpdate(ref Array custom)
        {

        }

        public void OnStartupComplete(ref Array custom)
        {

        }

        public void OnBeginShutdown(ref Array custom)
        {
            if (application != null)
            {
                application = null;
            }
        }

        public string GetCustomUI(string RibbonID)
        {
            return Properties.Resources.ribbon;
        }

        public void showHello(IRibbonControl control)
        {
            var app = application as OneNote.Application;
            var win = app.Windows;
            string id = (application as OneNote.Application).Windows.CurrentWindow.CurrentPageId;
            string title;
            app.GetPageContent(id, out title);
            var doc = XDocument.Parse(title);
            string pageTitle = doc.Descendants().FirstOrDefault().Attribute("ID").NextAttribute.Value;
            MessageBox.Show("Current Page ID = " + pageTitle, "Hello World!");
        }

        public IStream GetImage(string imageName)
        {
            MemoryStream mem = new MemoryStream();
            Properties.Resources.HelloWorld.Save(mem, ImageFormat.Png);
            return new CCOMStreamWrapper(mem);
        }
    }
}

第四步:安装和部署

1.在解决方案中添加安装和部署的项目

2.修改注册表,右击Setup工程→View→注册表,将注册表中的项清空

3.按如下步骤新建键

HKEY_CLASSES_ROOT→AppID→{工程的GUID}

  右击→New:

类型 名称
字符串值 DllSurrogate  

HKEY_CLASSES_ROOT→CLSID→{工程的GUID}

  右击→New:

类型 名称
字符串值 AppID {工程的GUID}

HKEY_CURRENT_USER→Software→Microsoft→Office→OneNote→AddIns→工程的ProgId

  右击→New:

类型 名称
字符串值 Description 自定义的工程描述
字符串值 FriendlyName 自定义的工程名称
DWORD LoadBehavior 3

HKEY_LOCAL_MACHINE→Software→Classes→AppID→{工程的GUID}

  右击→New:

类型 名称
字符串值 DllSurrogate  

HKEY_LOCAL_MACHINE→Software→Classes→CLSID→{工程的GUID}

  右击→New:

类型 名称
字符串值 AppID {工程的GUID}

完成后的效果如图所示:

4.此时就可以安装我们的工程了,首先如图进入文件系统

然后选择安装目录:Application Folder (一般是 C:\Program Files\ ···) → 右击 → Add → Project Output… → OK

5.此时就可以生成解决方案了,如果报错,你可能需要用管理员权限打开VS

6.最后如图进行安装就完成了:

时间: 2025-01-05 01:43:42

创建属于自己的OneNote插件的相关文章

发现问题 解决问题:好用的OneNote插件Onetastic

今天晚上,我发现一个外国人写的OneNote插件Onetastic.(下载链接:http://omeratay.com/onetastic/?) 初次使用之后,觉得挺好用,功能很强大.但很多功能有待发掘.下面介绍一下这个插件的功能.如图所示: ? ? 这个插件有五大功能: 宏:宏功能非常强大,能够做很多你平时重复劳动的事情. OneCalendar: 笔记录入日程表,这里可以查看你录入的文章的时间和修改的时间等等. 自定义样式: 作者自己说他不喜欢OneNote当中的样式,所以他就加入自定义样式

Android Studio快速创建常用工具类的插件Utils

现如今Android开发,开发工具Android Studio已成为主流,而为Android Studio打造的插件也越来越多,今天为大家介绍一个快速创建常用工具类的插件Utils.其实Android中有关工具类的库有很多,但我们开发中一般只会用到某个库的一个或几个类,所以这时候Utils就有了很大的优势了,它直接创建自己所需要的工具类,而且每个工具类是相互解耦的.下面,我们就来一起看看它的集成及使用. 首先,我们看一下集成方式 下载jar包导入1.下载最新jar包Utils.jar-v1.32

10条建议让你创建更好的jQuery插件

前言:在开发过很多 jQuery 插件以后,我慢慢的摸索出了一套开发jQuery插件比较标准的结构和模式.这样我就可以 copy & paste 大部分的代码结构,只要专注最主要的逻辑代码就行了.使用相同的设计模式和架构也让修复bug或者二次开发更容易.一套经过验证的架构可以保证我的插件不出大的问题,不论插件简单还是复杂.我在这里分享10条我总结的经验. 1. 把你的代码全部放在闭包里面 这是我用的最多的一条.但是有时候在闭包外面的方法会不能调用.不过你的插件的代码只为你自己的插件服务,所以不存

10条建议帮助你创建更好的jQuery插件

本文总结了帮助你创建更好jQuery插件的10条建议.分享给大家供大家参考.具体说明如下: 在开发过很多 jQuery 插件以后,我慢慢的摸索出了一套开发jQuery插件比较标准的结构和模式.这样我就可以 copy & paste 大部分的代码结构,只要专注最主要的逻辑代码就行了.使用相同的设计模式和架构也让修复bug或者二次开发更容易.一套经过验证的架构可以保证我的插件不出大的问题,不论插件简单还是复杂.我在这里分享10条我总结的经验. 1. 把你的代码全部放在闭包里面 这是我用的最多的一条.

如何创建一个基本JQuery的插件

如何创建一个基本的插件 有时您希望在整个代码中提供一些功能.例如,也许你想要一个单一的方法,你可以调用一个jQuery选择,对选择执行一系列的操作.在这种情况下,您可能需要编写一个插件. 链接jQuery如何工作101:jQuery对象方法 在我们编写自己的插件之前,首先要了解一下jQuery如何工作.看看这段代码: 1 $( "a" ).css( "color", "red" ); 这是一些很基础的jQuery代码,但你知道幕后发生了什么吗?无

16款创建CSS3动画的jQuery插件

jQuery插件是用来扩展jQuery原型对象的方法. 本文搜集了用来为你的网站创建CSS3动画的一些jQuery插件. 1. jQuery Smoove Smoove 简化了CSS3转换效果,使得页面向下滚动时网页内容能有一种滑入的动效. 在线演示:http://wow.techbrood.com/fiddle/7 2. CSS3 Animate it 这个插件效果和Smoove类似. 3. WaitMe WaitMe 是用于创建加载CSS3动画的 jQuery 插件. 4. Stroll.j

转:10条建议让你创建更好的jQuery插件

在开发过很多 jQuery 插件以后,我慢慢的摸索出了一套开发jQuery插件比较标准的结构和模式.这样我就可以 copy & paste 大部分的代码结构,只要专注最主要的逻辑代码就行了.使用相同的设计模式和架构也让修复bug或者二次开发更容易.一套经过验证的架构可以保证我的插件不出大的问题,不论插件简单还是复杂.我在这里分享10条我总结的经验. 1. 把你的代码全部放在闭包里面 这是我用的最多的一条.但是有时候在闭包外面的方法会不能调用. 不过你的插件的代码只为你自己的插件服务,所以不存在这

15款创建漂亮幻灯片的 jQuery 插件

1. Skippr Skippr 是一个超级简单的 jQuery 幻灯片插件.只是包括你的网页中引入 jquery.skippr.css 和 jquery.skippr.js 文件就能使用了.Skippr 能够自适应窗口宽度,而且导航是独特的条形导航. 效果演示      源码下载 2. Prezento Prezento 这款 jQuery 插件可以让你网页以新颖的交互方式呈现.另外,Prezento 支持响应式设计,配置项也很灵活,可以根据你需要的效果配置. 效果演示      源码下载 3

推荐15款创建漂亮幻灯片的 jQuery 插件

对于设计师,开发者,摄影师或任何创造性的个人和企业,他们自己的网站是展示他们的技能和服务的最佳场所.你可能打算设计一个新的个人作品网站,不管你是从头开始或使用模板,都会需要使用 jQuery 幻灯片插件,以美丽夺目的方式显示的作品. 网络上有很多的 jQuery 幻灯片插件,很难决定哪一个更好.因此,我们编辑了15款目前比较优秀的 jQuery 幻灯片插件,帮助你用一个美丽的和创新的方式展示你的图片或者视频列表.如果你有熟悉的任何其他幻灯片插件,请与我们的读者分享您的反馈. 您可能感兴趣的相关文