I've created a toolbar button in OneNote like Daniel Escapa showed. Usually, it works, but sometimes OneNote decides to grey out the toolbar button, making it impossible to click. I can't figure out what state is causing this. How can I prevent this?
I'm careful to return true from the OnEvent and OnClick handlers, but maybe there's a special case that is causing it to return false? Here is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OneNoteAddin;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.IO;
using OneNote = Microsoft.Office.Interop.OneNote;
namespace NoteTakerPlugin
{
[Guid("792d0410-d53c-402d-92c9-5db9ea29f644")]
public class NoteTakerButton : IOneNoteAddIn
{
// for sending messages to window handles
private struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
// this should be hardcoded in the note taker application
private const string NoteTakerAppClassName = "CubicNoteTaker-792d0410-d53c-402d-92c9-5db9ea29f644::EventReceiver";
private const int WM_COPYDATA = 0x4A;
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);
IntPtr app;
public NoteTakerButton()
{
tellAppSomething("{ \"appStart\": true }", false);
}
public bool OnClick([In] String strActivePageID)
{
// send the click event to the note taker app
tellAppSomething("{ \"click\": { \"pageId\": \"" + strActivePageID + "\" }}", true);
return true;
}
public bool OnEvent([In] OneNote.OneNoteAddIn_Event evt, [In] String strParameter)
{
// send the event to the note taker app
tellAppSomething("{ \"event\": { \"id\": " + (int)evt + ", \"param\": \"" + strParameter + "\" }}", false);
return true;
}
private void tellAppSomething(String message, bool startProgram)
{
// if the process is running
refreshAppStatus();
if( app != IntPtr.Zero )
{
// send a window message to the process telling it the message
sendMessageTo(app, message);
}
else if( startProgram )
{
//开发者_开发百科 start the process with a command line telling it the message
startApp(message);
}
}
private void refreshAppStatus()
{
app = FindWindowByCaption(IntPtr.Zero, NoteTakerAppClassName);
}
private void sendMessageTo(IntPtr hWnd, String msg)
{
int wParam = 0;
int result = 0;
if (hWnd != IntPtr.Zero )
{
byte[] sarr = System.Text.Encoding.Default.GetBytes(msg);
int len = sarr.Length;
COPYDATASTRUCT cds;
cds.dwData = IntPtr.Zero;
cds.lpData = msg;
cds.cbData = len + 1;
result = SendMessage(hWnd, WM_COPYDATA, wParam, ref cds);
}
}
private void startApp(String args)
{
string exe = getAppExe();
if (File.Exists(exe))
{
System.Diagnostics.Process.Start(exe, args);
}
else
{
System.Windows.Forms.MessageBox.Show("You need to reinstall the Note Taker application. The installation is corrupted.");
}
}
private string getAppExe()
{
// use the registry to find where the application is installed
RegistryKey noteTakerKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\NoteTaker");
String path = noteTakerKey.GetValue("Path","").ToString();
String exe = noteTakerKey.GetValue("Exe", "").ToString();
if (!Directory.Exists(path))
return "";
String combo = Path.Combine(path, exe);
if( File.Exists(combo) )
return combo;
else // not installed
return "";
}
}
}
EDIT: I remember this issue, now! When you close OneNote, check if an instance of it is still running in taskman, I think this sort of locks the addon in future instances and grays them out, make sure you dont have any code left running that would be causing the instance to stay alive.
In my project properties Build tab, I had forgotten to check "Register for COM interop" in Release mode. This caused intermittent errors.
精彩评论