API for Sticky Notes in Windows 7

In the Day View project I needed to open a Windows 7 Sticky Note programmatically and write to it. Unfortunately I found out that there is not an API for the Sticky Notes application. At least not a managed one.

So I had to fake it and make my own API. I have made a small class that basicly uses Process.Start to open the program, and SendKeys to write to the Note.

Here it is:

using System;  
using System.Diagnostics;  
using System.IO;  
using System.Runtime.InteropServices;  
using System.Threading;  
using System.Windows.Forms;  
  
namespace DayView  
{  
    public class StickyNote  
    {  
        private const string m_ProcessName = "StikyNot";  
        private readonly string m_ProcessFileName = Path.Combine(Environment.SystemDirectory, "StikyNot.exe");  
        private event EventHandler m_Activated = delegate { };  
        [DllImport("user32.dll")]  
        [return: MarshalAs(UnmanagedType.Bool)]  
        static extern bool SetForegroundWindow(IntPtr hWnd);  
  
        public void Activate()  
        {  
            bool makeNewNote = true;  
            Process p = FindProcess();  
            if (p == null)  
            {  
                p = StartProcess();  
                if (!NoteContainsText(p.MainWindowHandle))  
                {  
                    makeNewNote = false;  
                }  
            }  
            var state = new StickyNoteState();  
            state.MakeNewNote = makeNewNote;  
            state.StickyNoteProcess = p;  
            ThreadPool.QueueUserWorkItem(Activate, state);  
        }  
  
        private void Activate(object state)  
        {  
            var stickyNoteState = state as StickyNoteState;  
            if (stickyNoteState.MakeNewNote)  
            {  
                NewNote(stickyNoteState.StickyNoteProcess);  
            }  
            OnActivated();  
        }  
  
        private Process StartProcess()  
        {  
            var startInfo = new ProcessStartInfo(m_ProcessFileName);  
            Process p = Process.Start(startInfo);  
            Thread.Sleep(200); //This is an annoying hack. I haven't been able to find another way to be sure the process is started.  
            return p;  
        }  
  
        private void NewNote(Process p)  
        {  
            SetForegroundWindow(p.MainWindowHandle);  
            Signal("^n");              
        }  
  
        /// <summary>  
        /// Weird hack to find out if note contains text.  
        /// </summary>  
        /// <returns></returns>  
        private bool NoteContainsText(IntPtr handle)  
        {  
            string textOfClipboard = Clipboard.GetText();  
            Signal("^a");  
            Signal("^c");  
            Signal("{RIGHT}");  
            string noteText = Clipboard.GetText().Trim();  
            if (textOfClipboard == null)  
            {  
                Clipboard.SetText(textOfClipboard);  
            }  
            return !string.IsNullOrEmpty(noteText);  
        }  
  
        private Process FindProcess()  
        {  
                Process[] processes = Process.GetProcessesByName(m_ProcessName);  
                if(processes != null && processes.Length > 0)  
                {  
                    return processes[0];  
                }  
            return null;  
        }  
  
        internal void OnActivated()  
        {  
            m_Activated(this, new EventArgs());  
        }  
  
        public event EventHandler Activated  
        {  
            add { m_Activated += value; }  
            remove { m_Activated -= value; }  
        }  
  
        public void Signal(string message)  
        {  
            SendKeys.SendWait(message);  
            SendKeys.Flush();  
        }  
    }  
  
    public class StickyNoteState  
    {  
        public bool MakeNewNote { get; set; }  
        public Process StickyNoteProcess { get; set; }  
  
    }  
}  

It works OK. The only really buggy thing in the code is in line 47, where I have to use a Thread.Sleep in order to make sure the note is loaded before I write to it. Unfortunately this is necessary because the Process class does not provide an event to signal when it has finished loading. I arbitrarily chose 200 milliseconds for the Sleep. Larger values might be necessary on slower computers.

In order to use the class you have to configure SendKeys in your app.config like this:

<?xml version="1.0" encoding="utf-8" ?>  
<configuration>  
  <appSettings>  
    <add key="SendKeys" value="SendInput"/>  
  </appSettings>  
</configuration>  

Comments

Great article… I need to create a note with some text inside. Is there a way to do this?

Bruno de Almeida Luz
Wed, Jun 23, 2010

Hi Bruno,

Well I guess it is not that obvious how to use my API. Sorry…

Here is an example:

public void NewNote(string someText)
{
    var note = new StickyNote();
    note.Activate();
    note.Activated += (s, e) => { note.Signal(someText); };
}

Just use \n in the text string for lineshifts.

Jesper
Wed, Jun 23, 2010

Great and valuable work done by you.Can you tell how to delete or update existing notes?

Shoaib
Sat, Jul 14, 2012

Hi Shoaib,

Thank you.

Since there is really no API for Sticky Notes you would have to emulate a user like I did in the StickyNote class. E.g. Delete is possible by sending Ctrl+D to the App. I have not tried this, you are on your own :)

Not elegant but I think that is the only way unless Microsoft has come up with an API since I wrote the article.

Good luck.

Jesper
Tue, Jul 24, 2012

Comments closed.