Thursday, April 30, 2009

Microsoft Surface Development Environment

Continued from my previous post: Introduction to Microsoft Surface.

Surface Application Development Kit
Microsoft Surface applications are developed using WPF. You need Surface SDK Version 1.0 which is available only to some conference attendees and Microsoft partners. If you don’t have an actual Surface device, the SDK can be installed on a Windows computer; and the Surface Simulator from the SDK can be used to test the applications.

Here are the prerequisites for Surface SDK 1.0
The SDK will install all required Surface libraries, Surface Simulator, Sample Applications, Documentation and Visual Studio project templates for Surface.

Surface User Experience
Before we get into the actual application development, let us see how Surface UX is different from conventional windows based applications. Even though the Surface application is running on top of Windows, the end user will not see any signs of it. Instead, the Surface device will be showing an attract application (similar to screensaver) which fills the complete display area. There will be four access points in the corners to open Launcher and explore available Surface applications. Note that only one application will be visible at a time. There is also an I’m done button to close all the applications and to return to the attract mode.

surfacelauncher
The above screenshot from the SDK documentation shows various parts of the Launcher (1. Application title | 2. Application description | 3. Application preview image | 4. Application icon image | 5. Access points | 6. I'm done button)

Surface Simulator
Surface Simulator is a Windows application with a fixed size (1224 × 868) used to simulate the actual Surface unit experience. It can be launched from ‘Start Menu > All Programs > Microsoft Surface SDK 1.0 > Tools > Surface Simulator’. Once the Surface Simulator is launched, any Surface applications launched there after will get displayed within the Simulator window.

Surface recognizes three types of contacts viz. Finger, Blob (any objects), and Tagged object (objects with a tag mark similar to barcode). There are two types of tags namely byte tags (up to 256 unique values) and identity tags (still in beta but supports more values).

All these contacts can be placed on the Simulator using the equivalent buttons as shown in the image below.

surfacesimulator
This screenshot shows the Data Visualizer sample application from SDK which is displaying the contact information.

To choose a contact on the application, the equivalent button is selected from the tool bar using mouse or its short key is pressed. The mouse pointer is then changed to the selected contact icon. For Tagged objects, the tag value can be specified in the adjacent text box.

To place a contact click and hold using the left mouse button, and to leave the contact there, click on the right moue button after that.


To remove a contact, choose the same contact selector, hover it on the placed contact, click left button and hold and then click right button of the mouse.

To rotate contact, use the mouse scroll wheel.

To select placed contacts, use the Contact Selector button. Drag a box around required contacts to select more than one. After selection, the contact can be moved around, rotated, and resized. To remove the selection click anywhere outside the contacts.

Below are the short cut keys available in Surface Simulator:
  • Ctrl+F: Finger contact
  • Ctrl+B: Blob contact
  • Ctrl+T: Byte tag contact
  • Ctrl+I: Identity tag contact
  • Ctrl+S: Contact selector
  • Ctrl+H: Hides all contacts
  • Ctrl+S: Removes all contacts
The Surface Simulator also has a recording tab which can be used to record a set of actions (placing and movements of contacts) on the application. The recording is saved as a script file (*.scs) which is nothing but an xml file with key frames of contacts against time.  It is very useful to reproduce scenarios during testing of an application.

Continued to Developing Microsoft Surface Applications

Introduction to Microsoft Surface

Microsoft Surface is a multi-touch product from Microsoft which is developed as a software and hardware combination technology that allows user interaction with natural gestures and physical objects.
 
surfacelogo
 It was announced on May 29, 2007 in US, and even now its availability is limited to companies in few countries like USA, UK, UAE, etc. Microsoft doesn’t say anything in their how to buy section about when they will release it to end users and to other countries like India.

This new surface computing platform opens up a a variety of possibilities for applications with Natural User Interfaces (NUI) as is evident from the following marketing video from Microsoft.





But its huge size and high price prevents many from appreciating this next generation device for digital interaction. See the following parody video which raises this exact point.



IdentityMine had ventured into the field of Surface application development from its earlier days itself and still continues to deliver products with remarkable user experiences.



Continued to Microsoft Surface Application Development Environment.

Thursday, March 05, 2009

Upload Photos using Flickr API in .NET

You know there is Flickr, and you know they provide free API Service for accessing the online photos repository programmatically. Now let us see how easy it is to use those APIs in .NET.

In this example I am creating a .NET 2.0 Windows Forms Application (I used Visual Studio 2008) in C# to upload a photo to your Flickr account and then create a new set (album) and assign that photo to this set.

Here are the steps to do this:

  • Get the API Key from Flickr (This key and its secret code are required to access the service)
    • Go to Your API Keys section on Flickr.
    • Click on ‘Apply for a new key online’ link.
    • Complete the process. I used the Non-Commercial option to get the key immediately. You will have to provide the details of your application. Once this is done, click on Edit key details and update all the information.
    • Note down the Key (it will look like 3e1f3c83c5e92ead353be33162fr4883) and Shared Secret (it will look like 700f4d5220833d34)
  • Get the FlickrNet API Library (This is a .NET wrapper class library around Flickr API and makes it very easy to call the services)
    • Go to http://flickrnet.codeplex.com/
    • Download either just the binaries or the source code if you would like to debug into the library.
    • FlickrNet.dll is the only one file you will require.
  • Design the application interface
    • I created a WinForm application as shown below with options to authenticate the user and to choose a picture file for uploading.

FlickrTest Now let us understand some theories behind Flickr API before we get into coding. Skip this if all you bother is to get your code working. :)

You need to do an authentication to the flickr account you are trying to access. This is a one time process and is done by directing the user to a URL (generated using the service) which will then open up in a browser. This process is initiated using ‘Start Auth’ button. Once the user logs into the flickr account and approve the access request from this application, he or she will have to come back to this application and click on ‘Complete Auth’. In this method, we get a ‘Token’ which uniquely identifies the user. This token can be saved and used again to access this user’s account without requiring further authentication process.

  • Add code to call Flickr API methods

First thing is to add a reference to the FlickrNet (either direct dll or the project reference if you use source code) in your project. Next declare the required variables.

private string flickrFrob = "";
private long fileSize = 1;
FlickrNet.Flickr myFlickr;

Then in the Form’s load event, provide your API Key and Share Secret codes and create the Flickr object. Event handlers are also added here.


private void MainForm_Load(object sender, EventArgs e)
{
uxKey.Text = "3e1f3c83c5e92ead353be33162fr4883";
uxSecret.Text = "700f4d5220833d34";
myFlickr = new FlickrNet.Flickr(uxKey.Text, uxSecret.Text);
uxOpen.Click += new EventHandler(uxOpen_Click);
uxAuthStart.Click += new EventHandler(uxAuthStart_Click);
uxAuthComplete.Click += new EventHandler(uxAuthComplete_Click);
uxUpload.Click+=new EventHandler(uxUpload_Click);
myFlickr.OnUploadProgress += new FlickrNet.Flickr.UploadProgressHandler(myFlickr_OnUploadProgress);
}

Now let us open an image for uploading…


void uxOpen_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "Pictures|*.jpg";
if (ofd.ShowDialog() == DialogResult.OK)
{
uxFile.Text = ofd.FileName;
fileSize = ofd.OpenFile().Length;
Image img = Image.FromFile(ofd.FileName);
uxPicture.Image = img;
}
}

and then start authentication.


void uxAuthStart_Click(object sender, EventArgs e)
{
flickrFrob = myFlickr.AuthGetFrob();
string url = myFlickr.AuthCalcUrl(flickrFrob, FlickrNet.AuthLevel.Write);
System.Diagnostics.Process.Start(url);
}

This uses something called Frob (cookie kinda stuff) and generates a URL which is then opened up in the user’s default browser. Remember, at this point, user will have to sign in and authenticate the access request from this application.

Once the user completes the authentication and comes back to the application, we gets the token for that user.


void uxAuthComplete_Click(object sender, EventArgs e)
{
try
{
FlickrNet.Auth auth = myFlickr.AuthGetToken(flickrFrob);
myFlickr.AuthToken = auth.Token;
uxToken.Text = auth.Token;
uxUser.Text = auth.User.UserId;
}
catch (FlickrNet.FlickrException ex)
{
MessageBox.Show("User didn't approve!\n\n" + ex.Message);
}
}

The token is assigned to the Flickr object to enable access to that user’s account. It can be saved for later use without doing this authentication process again.

Now we are all set to upload the picture to flickr.


private void uxUpload_Click(object sender, EventArgs e)
{
uxProgress.Maximum = Convert.ToInt32(fileSize / 1000);
uxProgress.Value = 0; try
{
FlickrNet.Photo p = new FlickrNet.Photo();
System.Threading.Thread threadUpload = new System.Threading.Thread(delegate()
{
p.PhotoId = myFlickr.UploadPicture(uxFile.Text, "Sample Title", "Sample Description", "Sample Tag", false, false, true);
p.UserId = uxUser.Text;
FlickrNet.Photoset mySet = myFlickr.PhotosetsCreate("New Photoset", p.PhotoId);
System.Diagnostics.Process.Start(p.WebUrl);
}); threadUpload.Start();
}
catch (Exception ex)
{
MessageBox.Show("Upload failed!\n\n" + ex.Message);
}
}

Here we set the progress bar values and then use a new thread different from UI thread to call the Upload method. We also create a new photo set and add this photo to it.

The last thing is to make sure that the progress bar is updated properly.


private void myFlickr_OnUploadProgress(object sender, FlickrNet.UploadProgressEventArgs e)
{
if (e.UploadComplete)
{
this.Invoke((MethodInvoker)delegate()
{
uxProgress.Value = 0;
});
}
else
{
this.Invoke((MethodInvoker)delegate()
{
uxProgress.Value = e.Bytes / 1000;
});
}
}

That’s it… Hope this was useful to you and as always, feel free to ask any questions you may have on this…

Tuesday, February 24, 2009

Nullsoft Scriptable Install System (NSIS)

I have been using Visual Studio’s ‘Setup Project’ template for creating Windows installers to install my applications on a Windows computer. It’s pretty straight forward and easy, but gets a bit complicated when we need to do something more advanced. I knew there were things like InstallShield but they cost money.

Recently I was introduced to a new tool named as Nullsoft Scriptable Install System (NSIS). It’s completely free, and is a professional open source system to create Windows installers. It is driven by scripts (using a custom language) and offers a myriad of built-in features and functions covering all the basic installer necessities, from layout of install wizard dialogs, to manipulating files and registry keys.

Installing NSIS is very easy. Go to its home page at http://nsis.sourceforge.net and download the latest version. I used 2.43.

There are two types of installers that can be created using NSIS. The simple one is based on zip file. You package all your files into a single zip file and then feed it to the NSIS (Main Menu > Compiler > Installer based on ZIP file).

Zip2Exe It will generate a setup exe which the end user can execute to copy your files into a specified directory.

Zip2ExeSetup

The next option is the more powerful and flexible one. You create a NSIS script file (which is just a text file with extension as .nsi) with all the details of the installer like how many navigation pages it should have, what files need to be copied, and what values to be added to registry, etc. All these are specified through NSIS's own script language which is fairly easy to learn.

Once the script is ready and all the required files mentioned in the script are placed at the proper folders, you can right click on the script file and choose 'Compile NSIS Script' option. NSIS will then compile this script and will create a single setup exe file.

Now let us see the internals of such a script file. In this example, I am creating a Windows installer for my free software tool SQL Analyzer.

[Remember to get a fine text editing tool such as Notepad++ which has line number support and syntax highlighting for NSIS].

Initially I am defining some constants using the !define keyword. These are some string constants that will be used later on.

!define PRODUCT_NAME "SQL Analyzer"
!define PRODUCT_VERSION_MAJOR 7
!define PRODUCT_VERSION_MINOR 0
!define PRODUCT_DISPLAY_VERSION "7.0"
!define PRODUCT_PUBLISHER "Coolwayfarer"
!define PRODUCT_WEB_SITE "http://www.codeplex.com/sqlanalyzer"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" ; 
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES\SQL Analyzer"

Anything that comes after a $ sign is a predefined constant or variable. For example $PROGRAMFILES will translate into the user’s program files folder (typically C:\Program Files\).

Next we need to specify what compression technique we are using and what kind of user interface is required for the installer.

SetCompressor /SOLID lzma
!include "MUI2.nsh"

Here I am using the lzma. Don’t worry about that, it gives maximum compression. I also include a header file (you don’t need to get a copy of that file to include it) for the settings for Modern UI 2 (MUI2) which is the latest version of a user interface in a wizard style.

Next, the settings for the installer interface are specified.

!define MUI_ABORTWARNING
!define MUI_ICON "resources\sqlanalyzer.ico"
!define MUI_UNICON "resources\sqlanalyzer.ico"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP "resources\sqlanalyzerheader.bmp"
!define MUI_HEADERIMAGE_RIGHT
!define MUI_HEADER_TRANSPARENT_TEXT
!define MUI_WELCOMEFINISHPAGE_BITMAP "resources\sqlanalyzerwelcome.bmp"
!define MUI_WELCOMEFINISHPAGE_BITMAP_NOSTRETCH

As you can see, things like MUI_ICON are predefined properties/settings. Here I have specified an icon for the installer and two images, one for the header and another one for the welcome page. Note that the files are put in a relative path to the script file.

Now the different wizard pages in the installer are specified.

; Welcome page
!insertmacro MUI_PAGE_WELCOME

; License page
!define MUI_LICENSEPAGE_CHECKBOX
!insertmacro MUI_PAGE_LICENSE "resources\license.txt"

; Instfiles page
!insertmacro MUI_PAGE_INSTFILES

; Finish page
!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\README.txt"
!define MUI_FINISHPAGE_NOREBOOTSUPPORT
!insertmacro MUI_PAGE_FINISH

; Uninstaller pages
!insertmacro MUI_UNPAGE_INSTFILES

; Language files
!insertmacro MUI_LANGUAGE "English"

Anything that starts with a semicolon is a comment. So I have pages like Welcome page, license page, etc. defined here. Note that in the finish page, I have an option specified to show readme file and it points to the file README.txt in the installed location ($INSTALLDIR). We will see in a moment that as part of our installation, we are copying this file as well.

Now we specify some basic settings for the installer itself.

Name "${PRODUCT_NAME}"
OutFile "${PRODUCT_NAME} Setup.exe"
InstallDir "${PRODUCT_INSTALL_DIR}"
ShowInstDetails show
ShowUnInstDetails show
BrandingText "${PRODUCT_PUBLISHER}"
RequestExecutionLevel admin

We are making use of the constants we defined earlier here to specify things like the installer file (OutFile: which will be now ‘SQL Analyzer Setup.exe’).

Now the settings are complete and we need to define the actions during the installation. This is done by defining a section with some name.

Section "MainSection" MainSection
;Action goes here...
SectionEnd

Within this section, first we need to set the out path (which is the installation directory) and then copy all the required files to this path.

SetOutPath "$INSTDIR"
SetOverwrite ifnewer

;Copy files
File "/oname=sqlanalyzer.ico" "resources\sqlanalyzer.ico" ;Binary of the application.
File "/oname=SQLAnalyzer.exe" "files\SQLAnalyzer.exe" ;Binary of the application.
File "/oname=sqlanalyzer.gif" "files\sqlanalyzer.gif" ;A sample screen shot.
File "/oname=README.txt" "files\README.txt" ;Readme file.
File "/oname=RICHTX32.OCX" "files\RICHTX32.OCX" ;Required OCX control: Rich Text Box.
File "/oname=COMDLG32.OCX" "files\COMDLG32.OCX" ;Required OCX control: Common Dialog. 
File "/oname=MSFLXGRD.OCX" "files\MSFLXGRD.OCX" ;Required OCX control: Flex Grid.

Next, I am registering the dependent OCX controls and creating Start Menu shortcuts.

;Register the OCX controls.
Exec 'regsvr32 "$INSTDIR\RICHTX32.OCX" /S'
Exec 'regsvr32 "$INSTDIR\COMDLG32.OCX" /S'
Exec 'regsvr32 "$INSTDIR\MSFLXGRD.OCX" /S'

;Create Start Menu folders and shortcuts.
CreateDirectory "$STARTMENU\Programs\${PRODUCT_NAME}"
CreateShortCut "$STARTMENU\Programs\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\SQLAnalyzer.exe"
CreateShortCut "$STARTMENU\Programs\${PRODUCT_NAME}\README.lnk" "$INSTDIR\README.txt"
CreateShortCut "$STARTMENU\Programs\${PRODUCT_NAME}\Sample.lnk" "$INSTDIR\sqlanalyzer.gif"
CreateShortCut "$STARTMENU\Programs\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"

;Create uninstaller
WriteUninstaller "$INSTDIR\Uninstall.exe"

Any external tool can be used using the Exec keyword. If you need to run your own custom tool as part of installation, first copy that tool and then use this command. NSIS can create an uninstaller automatically using the keyword WriteUninstaller.

If we need this product to appear on Windows installed programs list (Add/Remove Programs), then we need to write a registry entry as below.

WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "${PRODUCT_NAME}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\Uninstall.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\sqlanalyzer.ico"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_DISPLAY_VERSION}"
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMajor" "${PRODUCT_VERSION_MAJOR}"
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMinor" "${PRODUCT_VERSION_MINOR}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"

We are almost done and only thing left now is to instruct NSIS on what to do while the uninstaller is executed. Well, we need to remove whatever files we have copied, directories and shortcuts we have created, and registry entries we have made. This is specified in a section named Uninstall as below.

Section "Uninstall"
;Unregister the OCX controls.
Exec 'regsvr32 -u "$INSTDIR\RICHTX32.OCX" /S'
Exec 'regsvr32 -u "$INSTDIR\COMDLG32.OCX" /S'
Exec 'regsvr32 -u "$INSTDIR\MSFLXGRD.OCX" /S'

;Delete all the files
Delete "$INSTDIR\sqlanalyzer.ico"
Delete "$INSTDIR\SQLAnalyzer.exe"
Delete "$INSTDIR\sqlanalyzer.gif"
Delete "$INSTDIR\README.txt"
Delete "$INSTDIR\RICHTX32.OCX"
Delete "$INSTDIR\COMDLG32.OCX"
Delete "$INSTDIR\MSFLXGRD.OCX"
Delete "$INSTDIR\Uninstall.exe"

;Remove the installation folder.
RMDir "$INSTDIR"

;Remove the Shortcuts
Delete "$STARTMENU\Programs\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk"
Delete "$STARTMENU\Programs\${PRODUCT_NAME}\README.lnk"
Delete "$STARTMENU\Programs\${PRODUCT_NAME}\Sample.lnk"
Delete "$STARTMENU\Programs\${PRODUCT_NAME}\Uninstall.lnk"
RMDir /r "$STARTMENU\Programs\${PRODUCT_NAME}"

;Remove the entry from 'installed programs list'
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
SectionEnd

That’s it! Now make sure that the extension of this script file is .nsi (download the complete file from here). Right click on this file from Windows Explorer and you will see an option ‘Compile NSIS Script’ if you have successfully installed NSIS.

sa9If there is any error, the compiler will inform about it specifying the line number in the script. So it is easy to fix issues. If everything went fine, the installer exe will be created at the same location.

Now let us see how the installer interface looks like with the settings in the script file.

sa1This is the first welcome screen. The image on the left is the onwe we specified with ‘sqlanalyzerwelcome.bmp’.

sa2Here in the second page the license from a text file is displayed. The ‘Install’ button will be enabled only when  ‘I accept…’ checkbox is checked.

sa3 This screen shows the progress of the installation.

sa4 This is the final page with an option to show Readme file. After the installation, the Start Menu shortcuts are created as below.

sa5The product will also be listed under ‘Add/Remove Programs’

sa6Now on clicking the Uninstall button, the uninstaller will get executed and will remove all the changes we have done.

sa7

You can download all the files and the script as a zip from here or just try out the installer from here. Let me know if this article helped you and feel free to post any questions you may have. Remember to first check out the tutorial and documentation on NSIS site which is very detailed.

Thursday, November 27, 2008

Windows Live Writer Plugin Development

Windows Live Writer is a cute small free blog publishing desktop application. If you are tired of the browser based tools to post your blogs, you must try Writer where you can create rich content posts offline and then publish to your blog hosting server when you are online.
lwplugin0
Windows Live Writer can be easily installed by double clicking the downloaded WLinstaller.exe file. To The initial wizard during the startup will help to configure to an existing blog or to create a new blog. There are no other additional configurations or settings involved.
Plugins helps in extending the capabilities of Writer to insert, edit, and publish new types of content. It is very easy to develop a plugin if you are a .NET developer. For the plugin development no separate SDK is required as all the APIs comes with the installation and will be available in the installation folder typically at C:\Program Files\Windows Live\Writer.
lwplugin4
lwplugin1
lwplugin2
lwplugin3
There are two types of content source plugins a) Simple (inserts custom html) and b) Smart (inserts custom html with editing options).
Content created by both simple and smart content sources can originate from an Insert dialog box, a URL, or Live Clipboard data. Each content source plugin can support creating content from one or all of these contexts.
In this post, we will see how we can develop a Simple Content Source Plugin through Insert Dialog Box. You can use Visual Studio 2008 or 2005 or 2003.
  • Launch Visual Studio and start a new Class Library Project in C#.
  • Add a reference to the WindowsLive.Writer.Api assembly (located in the directory C:\Program Files\Windows Live\Writer).
  • Create a new class derived from ContentSource base class from this API.
  • Apply the WriterPluginAttribute to the new class that will define the plugin properties. (Use a new GUID to identify this plugin. If an image is specified in the attribute, add this image as an embedded resource to the project. The publisher URL and description will appear in the Plugins options in Writer).
  • Apply the InsertableContentSourceAttribute to the new class that will define the plugin content. This will appear as the menu name under Insert menu.
  • Override the CreateContent method and code the required functionality there.
  • Add a Post Build event to the project to copy plugin dll to the Writer plugins directory after it is built (XCOPY /D /Y /R "$(TargetPath)" "C:\Program Files\Windows Live\Writer\Plugins\").
  • Build the project and then run Windows Live Writer to test and debug. New plugin will appear under Insert menu.
The complete code snippet for a hello world plugin is given below:
using System.Windows.Forms;
using WindowsLive.Writer.Api;

namespace LiveWriterPlugin
{
[WriterPluginAttribute
("8CFEFA0C-6366-419f-9590-20A6590728DC",
"My Sample Plugin",
ImagePath = "mypluginimage.png",
PublisherUrl = "http://ctlabs.blogspot.com",
Description = "A sample plugin that can insert hellow world in your blog posts")]

[InsertableContentSourceAttribute("My Sample Plugin Content")]
public class MyPlugin: ContentSource
{
public override DialogResult CreateContent(IWin32Window dialogOwner, ref string newContent)
{
DialogResult result = MessageBox.Show("Do you want to insert this sample content?","My Plugin",MessageBoxButtons.OKCancel);

if (result == DialogResult.OK)
{
newContent = "Hello World from Plugin";
}

return result;
}
}
}

That's it. Look at the above images to see this plugin in action. Happy plugin development!