<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Jesper Niedermann's .NET Blog - Windows 7</title>
    <link>http://www.niedermann.dk/</link>
    <description>about .NET and related technologies</description>
    <language>en-us</language>
    <copyright>Jesper Niedermann</copyright>
    <lastBuildDate>Fri, 13 Nov 2009 23:28:10 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.2.8279.16125</generator>
    <managingEditor>jesper@niedermann.dk</managingEditor>
    <webMaster>jesper@niedermann.dk</webMaster>
    <item>
      <trackback:ping>http://www.niedermann.dk/Trackback.aspx?guid=0a44a9f8-67aa-45a8-aea4-d644321cd0f7</trackback:ping>
      <pingback:server>http://www.niedermann.dk/pingback.aspx</pingback:server>
      <pingback:target>http://www.niedermann.dk/PermaLink,guid,0a44a9f8-67aa-45a8-aea4-d644321cd0f7.aspx</pingback:target>
      <dc:creator>Jesper Niedermann</dc:creator>
      <wfw:comment>http://www.niedermann.dk/CommentView,guid,0a44a9f8-67aa-45a8-aea4-d644321cd0f7.aspx</wfw:comment>
      <wfw:commentRss>http://www.niedermann.dk/SyndicationService.asmx/GetEntryCommentsRss?guid=0a44a9f8-67aa-45a8-aea4-d644321cd0f7</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
In the <a href="http://www.niedermann.dk/2009/10/20/Windows7ContestFinished.aspx" target="_blank">Day
View</a> 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.
</p>
        <p>
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.
</p>
        <p>
Here it is:
</p>
        <pre class="c#" name="code">using System;<br />
using System.Diagnostics;<br />
using System.IO;<br />
using System.Runtime.InteropServices;<br />
using System.Threading;<br />
using System.Windows.Forms;<br /><br />
namespace DayView<br />
{<br />
public class StickyNote<br />
{<br />
private const string m_ProcessName = "StikyNot";<br />
private readonly string m_ProcessFileName = Path.Combine(Environment.SystemDirectory,
"StikyNot.exe");<br />
private event EventHandler m_Activated = delegate { };<br />
[DllImport("user32.dll")]<br />
[return: MarshalAs(UnmanagedType.Bool)]<br />
static extern bool SetForegroundWindow(IntPtr hWnd);<br /><br />
public void Activate()<br />
{<br />
bool makeNewNote = true;<br />
Process p = FindProcess();<br />
if (p == null)<br />
{<br />
p = StartProcess();<br />
if (!NoteContainsText(p.MainWindowHandle))<br />
{<br />
makeNewNote = false;<br />
}<br />
}<br />
var state = new StickyNoteState();<br />
state.MakeNewNote = makeNewNote;<br />
state.StickyNoteProcess = p;<br />
ThreadPool.QueueUserWorkItem(Activate, state);<br />
}<br /><br />
private void Activate(object state)<br />
{<br />
var stickyNoteState = state as StickyNoteState;<br />
if (stickyNoteState.MakeNewNote)<br />
{<br />
NewNote(stickyNoteState.StickyNoteProcess);<br />
}<br />
OnActivated();<br />
}<br /><br />
private Process StartProcess()<br />
{<br />
var startInfo = new ProcessStartInfo(m_ProcessFileName);<br />
Process p = Process.Start(startInfo);<br />
Thread.Sleep(200); //This is an annoying hack. I haven't been able to find another
way to be sure the process is started.<br />
return p;<br />
}<br /><br />
private void NewNote(Process p)<br />
{<br />
SetForegroundWindow(p.MainWindowHandle);<br />
Signal("^n"); 
<br />
}<br /><br />
/// &lt;summary&gt;<br />
/// Weird hack to find out if note contains text.<br />
/// &lt;/summary&gt;<br />
/// &lt;returns&gt;&lt;/returns&gt;<br />
private bool NoteContainsText(IntPtr handle)<br />
{<br />
string textOfClipboard = Clipboard.GetText();<br />
Signal("^a");<br />
Signal("^c");<br />
Signal("{RIGHT}");<br />
string noteText = Clipboard.GetText().Trim();<br />
if (textOfClipboard == null)<br />
{<br />
Clipboard.SetText(textOfClipboard);<br />
}<br />
return !string.IsNullOrEmpty(noteText);<br />
}<br /><br />
private Process FindProcess()<br />
{<br />
Process[] processes = Process.GetProcessesByName(m_ProcessName);<br />
if(processes != null &amp;&amp; processes.Length &gt; 0)<br />
{<br />
return processes[0];<br />
}<br />
return null;<br />
}<br /><br />
internal void OnActivated()<br />
{<br />
m_Activated(this, new EventArgs());<br />
}<br /><br />
public event EventHandler Activated<br />
{<br />
add { m_Activated += value; }<br />
remove { m_Activated -= value; }<br />
}<br /><br />
public void Signal(string message)<br />
{<br />
SendKeys.SendWait(message);<br />
SendKeys.Flush();<br />
}<br />
}<br /><br />
public class StickyNoteState<br />
{<br />
public bool MakeNewNote { get; set; }<br />
public Process StickyNoteProcess { get; set; }<br /><br />
}<br />
}</pre>
        <p>
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.
</p>
        <p>
In order to use the class you have to configure SendKeys in your app.config like this:
</p>
        <pre class="xml" name="code">&lt;?xml version="1.0" encoding="utf-8" ?&gt;<br />
&lt;configuration&gt;<br />
&lt;appSettings&gt;<br />
&lt;add key="SendKeys" value="SendInput"/&gt;<br />
&lt;/appSettings&gt;<br />
&lt;/configuration&gt;</pre>
        <img width="0" height="0" src="http://www.niedermann.dk/aggbug.ashx?id=0a44a9f8-67aa-45a8-aea4-d644321cd0f7" />
      </body>
      <title>API for Sticky Notes in Windows 7</title>
      <guid isPermaLink="false">http://www.niedermann.dk/PermaLink,guid,0a44a9f8-67aa-45a8-aea4-d644321cd0f7.aspx</guid>
      <link>http://www.niedermann.dk/2009/11/13/APIForStickyNotesInWindows7.aspx</link>
      <pubDate>Fri, 13 Nov 2009 23:28:10 GMT</pubDate>
      <description>&lt;p&gt;
In the &lt;a href="http://www.niedermann.dk/2009/10/20/Windows7ContestFinished.aspx" target="_blank"&gt;Day
View&lt;/a&gt; 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.
&lt;/p&gt;
&lt;p&gt;
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.
&lt;/p&gt;
&lt;p&gt;
Here it is:
&lt;/p&gt;
&lt;pre class="c#" name="code"&gt;using System;&lt;br&gt;
using System.Diagnostics;&lt;br&gt;
using System.IO;&lt;br&gt;
using System.Runtime.InteropServices;&lt;br&gt;
using System.Threading;&lt;br&gt;
using System.Windows.Forms;&lt;br&gt;
&lt;br&gt;
namespace DayView&lt;br&gt;
{&lt;br&gt;
public class StickyNote&lt;br&gt;
{&lt;br&gt;
private const string m_ProcessName = "StikyNot";&lt;br&gt;
private readonly string m_ProcessFileName = Path.Combine(Environment.SystemDirectory,
"StikyNot.exe");&lt;br&gt;
private event EventHandler m_Activated = delegate { };&lt;br&gt;
[DllImport("user32.dll")]&lt;br&gt;
[return: MarshalAs(UnmanagedType.Bool)]&lt;br&gt;
static extern bool SetForegroundWindow(IntPtr hWnd);&lt;br&gt;
&lt;br&gt;
public void Activate()&lt;br&gt;
{&lt;br&gt;
bool makeNewNote = true;&lt;br&gt;
Process p = FindProcess();&lt;br&gt;
if (p == null)&lt;br&gt;
{&lt;br&gt;
p = StartProcess();&lt;br&gt;
if (!NoteContainsText(p.MainWindowHandle))&lt;br&gt;
{&lt;br&gt;
makeNewNote = false;&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
var state = new StickyNoteState();&lt;br&gt;
state.MakeNewNote = makeNewNote;&lt;br&gt;
state.StickyNoteProcess = p;&lt;br&gt;
ThreadPool.QueueUserWorkItem(Activate, state);&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
private void Activate(object state)&lt;br&gt;
{&lt;br&gt;
var stickyNoteState = state as StickyNoteState;&lt;br&gt;
if (stickyNoteState.MakeNewNote)&lt;br&gt;
{&lt;br&gt;
NewNote(stickyNoteState.StickyNoteProcess);&lt;br&gt;
}&lt;br&gt;
OnActivated();&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
private Process StartProcess()&lt;br&gt;
{&lt;br&gt;
var startInfo = new ProcessStartInfo(m_ProcessFileName);&lt;br&gt;
Process p = Process.Start(startInfo);&lt;br&gt;
Thread.Sleep(200); //This is an annoying hack. I haven't been able to find another
way to be sure the process is started.&lt;br&gt;
return p;&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
private void NewNote(Process p)&lt;br&gt;
{&lt;br&gt;
SetForegroundWindow(p.MainWindowHandle);&lt;br&gt;
Signal("^n"); 
&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
/// &amp;lt;summary&amp;gt;&lt;br&gt;
/// Weird hack to find out if note contains text.&lt;br&gt;
/// &amp;lt;/summary&amp;gt;&lt;br&gt;
/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br&gt;
private bool NoteContainsText(IntPtr handle)&lt;br&gt;
{&lt;br&gt;
string textOfClipboard = Clipboard.GetText();&lt;br&gt;
Signal("^a");&lt;br&gt;
Signal("^c");&lt;br&gt;
Signal("{RIGHT}");&lt;br&gt;
string noteText = Clipboard.GetText().Trim();&lt;br&gt;
if (textOfClipboard == null)&lt;br&gt;
{&lt;br&gt;
Clipboard.SetText(textOfClipboard);&lt;br&gt;
}&lt;br&gt;
return !string.IsNullOrEmpty(noteText);&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
private Process FindProcess()&lt;br&gt;
{&lt;br&gt;
Process[] processes = Process.GetProcessesByName(m_ProcessName);&lt;br&gt;
if(processes != null &amp;amp;&amp;amp; processes.Length &amp;gt; 0)&lt;br&gt;
{&lt;br&gt;
return processes[0];&lt;br&gt;
}&lt;br&gt;
return null;&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
internal void OnActivated()&lt;br&gt;
{&lt;br&gt;
m_Activated(this, new EventArgs());&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
public event EventHandler Activated&lt;br&gt;
{&lt;br&gt;
add { m_Activated += value; }&lt;br&gt;
remove { m_Activated -= value; }&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
public void Signal(string message)&lt;br&gt;
{&lt;br&gt;
SendKeys.SendWait(message);&lt;br&gt;
SendKeys.Flush();&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
public class StickyNoteState&lt;br&gt;
{&lt;br&gt;
public bool MakeNewNote { get; set; }&lt;br&gt;
public Process StickyNoteProcess { get; set; }&lt;br&gt;
&lt;br&gt;
}&lt;br&gt;
}&lt;/pre&gt;
&lt;p&gt;
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.
&lt;/p&gt;
&lt;p&gt;
In order to use the class you have to configure SendKeys in your app.config like this:
&lt;/p&gt;
&lt;pre class="xml" name="code"&gt;&amp;lt;?xml version="1.0" encoding="utf-8" ?&amp;gt;&lt;br&gt;
&amp;lt;configuration&amp;gt;&lt;br&gt;
&amp;lt;appSettings&amp;gt;&lt;br&gt;
&amp;lt;add key="SendKeys" value="SendInput"/&amp;gt;&lt;br&gt;
&amp;lt;/appSettings&amp;gt;&lt;br&gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;&lt;img width="0" height="0" src="http://www.niedermann.dk/aggbug.ashx?id=0a44a9f8-67aa-45a8-aea4-d644321cd0f7" /&gt;</description>
      <comments>http://www.niedermann.dk/CommentView,guid,0a44a9f8-67aa-45a8-aea4-d644321cd0f7.aspx</comments>
      <category>.NET</category>
      <category>Tips &amp; Tricks</category>
      <category>Windows 7</category>
    </item>
  </channel>
</rss>