Friday 28 November 2008

Add-In for Outlook 2003

It looks simple, but it not that simple...when I mean not simple I mean the lack of information that you get from Microsoft to develop Add-in's, but as everything, after few hours of research you can get the chance of doing something nice customizing your Outlook to the limit.

I am personaly think, that Add-In's in Visual Studio are not developed yet, it seems that Visual Studio only creates a schema of what you need, but it doesm't give you any facility, well at the end of the day it is something that could be improve it in Visual Studio 2010 (I hope Mr. Bill will read this).

For this exercise I am going to create a ToolBar or Button with an image so, when you click it will display a message. You will end having something like this:




On Visual Studio 2005/2008 go to File->New ->Project->Other Project Types->Extensibility->Shared Add-In

Type a name and click on next, next,next...

You will end with a Visual Studio Solution.

Add a resource file, and insert an image resource on it, and call it "ToolBarIcon", this will be the image we will use for our button.

Create a new class and call it "OleCreateConverter.cs" and paste code below, after that go to the "Connect.cs" and paste the code I attatch.

Sometimes when you run these add-in's, they don't work, that is because Office 2003/2007 and Add-in's have a bug that Microsoft has not resolved yet...so even if you remove your profile, or the registry or reinstall Outlook... you will not able to make it work, so avoid to do experiments otherwiese you will have to install the entire operating system + office to keep working.

Anyway, if your Outlook becomes corrupted and you managed to make it work with add-in's please let me know how you did it.

________________________________________________________
OleCreateConverter.cs
________________________________________________________
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;

namespace WSSSaveAsOutlookAddIn
{
internal class OleCreateConverter
{

[DllImport("oleaut32.dll", EntryPoint = "OleCreatePictureIndirect",CharSet = CharSet.Ansi, ExactSpelling = true, PreserveSig = true)]
private static extern int OleCreatePictureIndirect([In] PictDescBitmap pictdesc, ref Guid iid, bool fOwn,[MarshalAs(UnmanagedType.Interface)] out object ppVoid);

const short _PictureTypeBitmap = 1;

[StructLayout(LayoutKind.Sequential)]
internal class PictDescBitmap
{
internal int cbSizeOfStruct = Marshal.SizeOf(typeof(PictDescBitmap));
internal int pictureType = _PictureTypeBitmap;
internal IntPtr hBitmap = IntPtr.Zero;
internal IntPtr hPalette = IntPtr.Zero;
internal int unused = 0;

internal PictDescBitmap(Bitmap bitmap)
{
this.hBitmap = bitmap.GetHbitmap();
}
}

public static stdole.IPictureDisp ImageToPictureDisp(Image image)
{
if (image == null || !(image is Bitmap))
{
return null;
}

PictDescBitmap pictDescBitmap = new PictDescBitmap((Bitmap)image);
object ppVoid = null;
Guid iPictureDispGuid = typeof(stdole.IPictureDisp).GUID;
OleCreatePictureIndirect(pictDescBitmap, ref iPictureDispGuid, true, out ppVoid);
stdole.IPictureDisp picture = (stdole.IPictureDisp)ppVoid;
return picture;
}


public static Image PictureDispToImage(stdole.IPictureDisp pictureDisp)
{
Image image = null;
if (pictureDisp != null && pictureDisp.Type == _PictureTypeBitmap)
{
IntPtr paletteHandle = new IntPtr(pictureDisp.hPal);
IntPtr bitmapHandle = new IntPtr(pictureDisp.Handle);
image = Image.FromHbitmap(bitmapHandle, paletteHandle);
}
return image;
}

}
}

________________________________________________________
Connect.cs
________________________________________________________
namespace WSSSaveAsOutlookAddIn
{
using System;
using Extensibility;
using System.Runtime.InteropServices;
using Microsoft.Office.Core;
using System.Reflection;

#region Read me for Add-in installation and setup information.
// When run, the Add-in wizard prepared the registry for the Add-in.
// At a later time, if the Add-in becomes unavailable for reasons such as:
// 1) You moved this project to a computer other than which is was originally created on.
// 2) You chose 'Yes' when presented with a message asking if you wish to remove the Add-in.
// 3) Registry corruption.
// you will need to re-register the Add-in by building the WSSSaveAsOutlookAddInSetup project,
// right click the project in the Solution Explorer, then choose install.
#endregion

///
/// The object for implementing an Add-in.
///

///
[GuidAttribute("0632A014-721A-4545-8B36-12D7CC4373B4"), ProgId("WSSSaveAsOutlookAddIn.Connect")]
public class Connect : Object, Extensibility.IDTExtensibility2
{
private WSSSaveAsWord.SaveAs _fSaveAsForm;

private CommandBarButton _cbbToolBarButton;

///
/// Implements the constructor for the Add-in object.
/// Place your initialization code within this method.
///

public Connect()
{
}

///
/// Implements the OnConnection method of the IDTExtensibility2 interface.
/// Receives notification that the Add-in is being loaded.
///

/// Root object of the host application.
///
public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom)
{
applicationObject = application;
addInInstance = addInInst;

if (connectMode != Extensibility.ext_ConnectMode.ext_cm_Startup)
{
OnStartupComplete(ref custom);
}


}

///
/// Implements the OnDisconnection method of the IDTExtensibility2 interface.
/// Receives notification that the Add-in is being unloaded.
///

///
public void OnDisconnection(Extensibility.ext_DisconnectMode disconnectMode, ref System.Array custom)
{
if (disconnectMode != Extensibility.ext_DisconnectMode.ext_dm_HostShutdown)
{
OnBeginShutdown(ref custom);
}
applicationObject = null;

}

///
/// Implements the OnAddInsUpdate method of the IDTExtensibility2 interface.
/// Receives notification that the collection of Add-ins has changed.
///

///
public void OnAddInsUpdate(ref System.Array custom)
{
}

///
/// Implements the OnStartupComplete method of the IDTExtensibility2 interface.
/// Receives notification that the host application has completed loading.
///

///
public void OnStartupComplete(ref System.Array custom)
{
//## The toolbar is declared
CommandBars oCommandBars;

//## The toolbar where our button will be added is declared
CommandBar oStandardBar;

try
{
//## We try to get the bar,
oCommandBars = (CommandBars)applicationObject.GetType().InvokeMember("CommandBars", BindingFlags.GetProperty, null, applicationObject, null);
}
catch (Exception)
{
//## Outlook has the CommandBars collection on the Explorer object.
object oActiveExplorer;
oActiveExplorer = applicationObject.GetType().InvokeMember("ActiveExplorer", BindingFlags.GetProperty, null, applicationObject, null);
oCommandBars = (CommandBars)oActiveExplorer.GetType().InvokeMember("CommandBars", BindingFlags.GetProperty, null, oActiveExplorer, null);
}

//## Set up a custom button on the "Standard" commandbar.
try
{
//## Its main toolbar Standard.
oStandardBar = oCommandBars["Standard"];
}
catch (Exception)
{
//## Access names its main toolbar Database.
oStandardBar = oCommandBars["Database"];
}

//## In case the button was not deleted, use the exiting one.
try
{
_cbbToolBarButton = (CommandBarButton)oStandardBar.Controls["Sharepoint Save"];
}
catch (Exception)
{
object omissing = System.Reflection.Missing.Value;

//## The command bar is added into the standar bar.
_cbbToolBarButton = (CommandBarButton)oStandardBar.Controls.Add(1, omissing, omissing, omissing, omissing);

//## The caption is set
_cbbToolBarButton.Caption = "Sharepoint Save";

//## We set the style...We want text and one icon!
_cbbToolBarButton.Style = MsoButtonStyle.msoButtonIconAndCaption;
}

// The following items are optional, but recommended.
//The Tag property lets you quickly find the control
//and helps MSO keep track of it when more than
//one application window is visible. The property is required
//by some Office applications and should be provided.
_cbbToolBarButton.Tag = "Sharepoint Save";

// The OnAction property is optional but recommended.
//It should be set to the ProgID of the add-in, so that if
//the add-in is not loaded when a user presses the button,
//MSO loads the add-in automatically and then raises
//the Click event for the add-in to handle.
_cbbToolBarButton.OnAction = "!";

//## We grab the image from our resources
System.Drawing.Image _imgToolBarImage =Properties.Resources.ToolBarIcon;

//## We make our button visible.
_cbbToolBarButton.Visible = true;

//## We convert from image to IPictureDisp
_cbbToolBarButton.Picture = OleCreateConverter.ImageToPictureDisp(_imgToolBarImage);

//## We set the event
_cbbToolBarButton.Click += new Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler(this._cbbToolBarButton_Click);

object oName = applicationObject.GetType().InvokeMember("Name", BindingFlags.GetProperty, null, applicationObject, null);

// Display a simple message to show which application you started in.
// System.Windows.Forms.MessageBox.Show("This Addin is loaded by " + oName.ToString(), "MyCOMAddin");
oStandardBar = null;
oCommandBars = null;

}

///
/// Implements the OnBeginShutdown method of the IDTExtensibility2 interface.
/// Receives notification that the host application is being unloaded.
///

///
public void OnBeginShutdown(ref System.Array custom)
{
//## Unloading our stuff...
object omissing = System.Reflection.Missing.Value;
_cbbToolBarButton.Delete(omissing);
_cbbToolBarButton = null;

}

private void _cbbToolBarButton_Click(CommandBarButton cmdBarbutton, ref bool cancel)
{
//## Button Clicked
System.Windows.Forms.MessageBox.Show("_cbbToolBarButton was Clicked");
}


private object applicationObject;
private object addInInstance;
}
}

Friday 14 November 2008

Listviews, Listviews, Listviews.... in C#.NET

If you want to create something like this:


you will need to talk with the ListView control. This control combines the functionality of a list with all the fancy features of the lastest .NET properties.

This is the code you need for a control called "LSTResults":


this.LSTResults.Items.Clear();

LSTResults.Columns.Add("Name", 100,HorizontalAlignment.Left);
LSTResults.Columns.Add("Size", 70, HorizontalAlignment.Left);
LSTResults.Columns.Add("Date Modified", 70, HorizontalAlignment.Left);
LSTResults.Columns.Add("Location", 70, HorizontalAlignment.Left);


ListViewItem _lvItem1 = new ListViewItem("IMAGE_063.jpg", 1);
_lvItem1.SubItems.Add("227120"+ " KB");
_lvItem1.SubItems.Add("12/10/2008");
_lvItem1.SubItems.Add("sdfsdf/IMG");
this.LSTResults.Items.Add(_lvItem1);

ListViewItem _lvItem2 = new ListViewItem("Contact-new1.jpg", 2);
_lvItem2.SubItems.Add("58383"+ " KB");
_lvItem2.SubItems.Add("12/10/2008");
_lvItem2.SubItems.Add("Personal/IMG");
this.LSTResults.Items.Add(_lvItem2);

ListViewItem _lvItem3 = new ListViewItem("PWS-Explorer", 2);
_lvItem3.SubItems.Add("2659"+ " KB");
_lvItem3.SubItems.Add("12/10/2008");
_lvItem3.SubItems.Add("Shared Documents");
this.LSTResults.Items.Add(_lvItem3);

Thursday 13 November 2008

How to change the font forecolor, background font color and background color in a TabControl

Because the tab control does not provide any property to change font background, the font forecolor and the box background I have decided to override the DrawItem event so I can control this tab component when windows is painting it.

This event will help you to set the font background, the font forecolor and the box background of
the tab control.

To use it:
1- Just add this event into your code.
2- on Properties change DrawMode property to OwnerDraw so we can mess around with this event later.
3- Go to the events and in the DrawItem event just type the name of our event;TabAndBackgroundBoxColorHandler.

You can modify more parts of the tabcontrol. you just need to capture the coordinates



private void TabAndBackgroundBoxColorHandler(object sender, DrawItemEventArgs e)
{
//########################################################
//## TabAndBackgroundBoxColorHandler ##
//## ##
//## How to use it: -Just set the tab control from ##
//## DrawMode to OwnerDraw. ##
//## -Add this Event into DrawItem event.##
//## -Set the colors you want. ##
//########################################################

//## Getting The tab control to work with it
System.Windows.Forms.TabControl _tTabControl = ((System.Windows.Forms.TabControl)(sender));//tabControl1;

StringFormat _sfStringFormat = new StringFormat();
string _sTabName = null;
Rectangle _rTabCoordinates = e.Bounds;
//Rectangle _rBoxCoordinates = new Rectangle(e.Bounds.X, e.Bounds.Y, _tTabControl.Width, _tTabControl.Height);
Rectangle _rBoxCoordinates = new Rectangle(0, 0, _tTabControl.Width, _tTabControl.Height);
Font _fTabFont;
Brush _brBackBrush = new SolidBrush(Color.Black); //Set background font color
Brush _brForeBrush = new SolidBrush(Color.AliceBlue);//Set foreground font color
Brush _brBackBox = new SolidBrush(Color.Red);//Set background box color color

//## We check the index, so we can paint the selected tab
if (e.Index == _tTabControl.SelectedIndex)
_fTabFont = new Font(e.Font.FontFamily, e.Font.Size, FontStyle.Bold);
else
_fTabFont = e.Font;

//## Drawing the rectangle for the main box
if (!_tTabControl.TabPages[0].Capture)
{
_tTabControl.TabPages[0].Capture = true;//.BackColor = ((SolidBrush)_brBackBrush).Color;
e.Graphics.FillRectangle(_brBackBox, _rBoxCoordinates);
}
else if (_tTabControl.TabPages.Count==e.Index)
{
_tTabControl.TabPages[0].Capture = false;
}

//e.Graphics.FillRectangle(_brBackBox, _rBoxCoordinates);

//## Getting the tab name so we can work with it.
_sTabName = _tTabControl.TabPages[e.Index].Text;

//## Aligning the text...
_sfStringFormat.Alignment = StringAlignment.Center;

//## This will fill the rectangle where the tab is with the color
//## Set before...
e.Graphics.FillRectangle(_brBackBrush, e.Bounds);

//## Creating the new rectange where T is.
//## +-----+
//## | T |
//## +-----+---------+
//## | P |
//## +---------------+
_rTabCoordinates = new Rectangle(_rTabCoordinates.X, _rTabCoordinates.Y + 3, _rTabCoordinates.Width, _rTabCoordinates.Height - 3);

//## Drawing the rectangle in the TabControl + The aligment...
e.Graphics.DrawString(_sTabName, _fTabFont, _brForeBrush, _rTabCoordinates, _sfStringFormat);

//## Dispose objects.
_sfStringFormat.Dispose();

//## Disposing if we have selected something.
if (e.Index == _tTabControl.SelectedIndex)
{
_fTabFont.Dispose();
_brBackBrush.Dispose();
_brForeBrush.Dispose();
_brBackBox.Dispose();
}
else
{
_brBackBrush.Dispose();
_brForeBrush.Dispose();
_brBackBox.Dispose();
}
}