How to make an icon

August 26, 2007 at 6:43 am | Posted in .Net, C# | Leave a comment

Apparently, .Net does not provide a good set of classes to create icons programmatically.  In helping someone on a forum, I ran across a free tool for image processing that does a great job.

The technique uses a free .dll called FreeImage. I gave it a try and with the help of a wrapper found in CodeProject was able to convert a .bmp file to a .ico file.

Here are the steps:

1. Download the FreeImage .dll from here.

2. Copy the .dll into the bin/Debug and/or bin/Release folder in your project

3. Add an Enum and FreeImage Class to your project (shown in the example below).

4. Use three calls to the functions in FreeImage: load the bitmap file, save in icon format, release the resource.

The following example loads a .bmp into FreeImage and saves it back as a .ico file. It includes the required Enum and FreeImage Class. (Requires using System.Runtime.InteropServices; )

class Program
{
    static void Main(string[] args)
    {
        int handle = FreeImage.FreeImage_Load(
            FIF.FIF_BMP,
            @"C:\Documents and Settings\User\Desktop\myBmp.bmp", 
            0);
                      
        FreeImage.FreeImage_Save(
            FIF.FIF_ICO,   
            handle, 
            @"C:\Documents and Settings\User\Desktop\new.ico", 
            0);
 
        FreeImage.FreeImage_Unload(handle);         

    }
}

public enum FIF
{
    FIF_UNKNOWN = -1,
    FIF_BMP = 0,
    FIF_ICO = 1,
    FIF_JPEG = 2,
    FIF_JNG = 3,
    FIF_KOALA = 4,
    FIF_LBM = 5,
    FIF_MNG = 6,
    FIF_PBM = 7,
    FIF_PBMRAW = 8,
    FIF_PCD = 9,
    FIF_PCX = 10,
    FIF_PGM = 11,
    FIF_PGMRAW = 12,
    FIF_PNG = 13,
    FIF_PPM = 14,
    FIF_PPMRAW = 15,
    FIF_RAS = 16,
    FIF_TARGA = 17,
    FIF_TIFF = 18,
    FIF_WBMP = 19,
    FIF_PSD = 20,
    FIF_CUT = 21,
    FIF_IFF = FIF_LBM,
    FIF_XBM = 22,
    FIF_XPM = 23
}
public class FreeImage
{
     [DllImport("FreeImage.dll")]
     public static extern int FreeImage_Load(FIF format, 
                    string filename, int flags);
     
     [DllImport("FreeImage.dll")]
     public static extern void FreeImage_Unload(int handle);
     
     [DllImport("FreeImage.dll")]
     public static extern bool FreeImage_Save(FIF format, 
        int handle, string filename, int flags);
}
Advertisements

Visual Studio 411

August 16, 2007 at 9:14 am | Posted in .Net, C#, Visual Studio | Leave a comment

Visual Studio has a powerful array of features that can greatly boost productivity–especially for new programmers who may not have a full grasp of the .Net framework.  While the C# language itself is quite compact and comprehensible, the number of classes available in the .Net framework is almost mind boggling.  How is a newcomer supposed to remember it all?

The good news is that with Visual Studio you don’t have to.  You just need to know how to get the information (‘411’) when you need it.  Here are the most helpful features for me:

Intellesense

There are three big productivity enhancements that I get out of Intellesense.  First, I use it to help find out what is possible with an object.  By typing a ‘.’ after the object name in a statement, the Intellesense drop down shows all of the properties and methods that are available to me.  Icons by the names of the members indicate the type (properties: a page with a hand, methods: a diamond, events: a lightning bolt).  Second, selecting one of the members gives a brief synopsis which includes the type of value returned and the arguments that are expected.  After selecting, if I type another delimiter (a space, a dot, a parenthesis), Intellesense will  enter the code for me reducing the possibility of making a typographical mistake.  For methods, entering the open parenthesis results in Intellesense showing the possible overloads (different argument possibilities).  Intellesense is almost like having an expert programmer sitting over your shoulder advising you every step of the way.

Dynamic Help

Dynamic help is a way of quickly getting to more information from the MSDN documentation file.  Turn this feature on using menu Help > Dynamic Help.  Now, when you click on an item in the code view or the designer view, a list of links to the Help documentation is presented.  Click on a link and most likely you will get exactly the information you are seeking.

MSDN Documentation

Newcomers need to understand the format of the help documentation so as not to be overwhelmed by its scope.  Every class typically has the following organization: an overview page, a members page listing all properties, methods and events, finally leading to pages for individual members.  More often than not, the individual members page will offer an example that can be adapted or even copied directly into the application.

Index

For me, the most useful way of getting to the information in the documentation (outside of dynamic help) is to use the Index: menu Help > Index.  Also available are ‘Search’ and ‘Content’ but ‘Index’ works best for me.

How do I

Help > How do I can also lead to helpful articles in the documentation for doing the most common tasks like File IO or drawing.

Getting Help Online

Outside of Visual Studio there is a wealth of information.  If I have a question about a control or how to do something, chances are good that someone else has had the same problem and has already posted the solution.  I usually fire up a search engine and put in a few keywords about the problem along with ‘msdn’.  This biases the search to either the msdn documentation or one of the msdn forums.

For me, asking a question in an online forum is my option of last resort.  Not that it is a bad thing to do but the time I spend using the other resources available is always a valuable learning experience in itself and can turn up nuggets that can be used in later projects.

Using WMP and Quicktime with Silverlight

August 15, 2007 at 7:47 am | Posted in Silverlight | 9 Comments

 

Note: There have been some breaking changes in Silverlight since this post was published.  For the latest info see this link.

Silverlight has a MediaElement control  which can be used for most cross-platform media display tasks.  I was disappointed that my application can not use it because it currently does not support playback at a variable rate.

My application requires a media player that can playback speech mp3 files at rates varying from 0.5 to 1.0x realtime.  Windows Media Player (WMP) is especially good at this in that the playback at reduced speed does not modify the pitch of the speech.

My solution to this problem is to instantiate a WMP or Quicktime player in the page depending on the platform and control the player from Silverlight C# code through a Javascript layer.

First, the player is installed in the body of the html page like this:

<!--Player goes here-->
     <div id="PlayerDiv"></div>    

 <script type="text/javascript">  

 //Installs the player
 var wmp;
 var qtp;
 document.getElementById('PlayerDiv').innerHTML = playerCreate('news clip.mp3');
 if(useWmp){
 wmp = document.getElementById('wmPlayer');
 }else{
 qtp = document.qtPlayer;
 }    

 </script>

The playerCreate function is a bit of Javascript that determines the browser capabilities and installs either a WMP or Quicktime player.  If IE is detected or Firefox is detected with the WMP component, then WMP is installed else use Quicktime.  (WMP is preferred over Quicktime for this application because while Quicktime has a rate control, the pitch is not preserved for mp3 playback.)  Here is the playerCreate Javascript:

var useWmp;
    function playerCreate(url) {
    //Find browser
var userAgent = navigator.userAgent.toLowerCase();
var is_opera  = (userAgent.indexOf('opera') != -1);
var is_saf    = ((userAgent.indexOf('applewebkit') != -1) || (navigator.vendor == "Apple Computer, Inc."));
var is_webtv  = (userAgent.indexOf('webtv') != -1);
var is_ie     = ((userAgent.indexOf('msie') != -1) && (!is_opera) && (!is_saf) && (!is_webtv));
var is_ie4    = ((is_ie) && (userAgent.indexOf("msie 4.") != -1));
var is_moz    = ((navigator.product == 'Gecko') && (!is_saf));
var is_kon    = (userAgent.indexOf('konqueror') != -1);
var is_ns     = ((userAgent.indexOf('compatible') == -1) && (userAgent.indexOf('mozilla') != -1) && (!is_opera) && (!is_webtv) && (!is_saf));
var is_ns4    = ((is_ns) && (parseInt(navigator.appVersion) == 4));   

    var str = "";
    if (is_ie) {
    // create the WMP for IE 
    useWmp = true;
    str = '<object id="wmPlayer" classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6" width="0" height="0">';
// str += '<param name="URL" value="'+url+'" />'; 
    str += '<param name="uiMode" value="none">';
    str += '<param name="autoStart" value="false">';
    str += '</object>';
    return str;  

    }else if(is_moz && navigator.plugins["Microsoft® Windows Media Player Firefox Plugin"]){
    // create WMP for FF. 
    useWmp = true;
    str = '<object id="wmPlayer" type="application/x-ms-wmp" data="'+url+'" width="0" height="0">';
// str += '<param name="URL" value="'+url+'" />'; 
    str += '<param name="uiMode" value="none">';
    str += '<param name="autoStart" value="false">';
    str += '</object>';
    return str;      

    }else{
    //try to create the qtp as last resort
    useWmp = false;
    str ='<object id="qtPlayer" classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab" width="0" height="0" >';
// str += '<param name="src" value="'+url+'">';
    str += '<param name="autoplay" value="false">';
    str += 'http://qtStartUp.mp3';
    str += ' </embed> ';
    str += '</object> ';
    return str;  

}
}

A set of Javascript functions were defined in order to create a common API for the Silverlight C# code to use.

function playerPlay(){
if(useWmp){
wmp.controls.play();
}else{
qtp.Play();
}
}  

function playerStop(){
if(useWmp){
wmp.controls.stop();
}else{
qtp.Stop();
qtp.Rewind();
}
}   

function playerPause(){
if(useWmp){
wmp.controls.pause();
}else{
qtp.Stop();
}
}   

function playerUrl(url){  

if(useWmp){  

wmp.URL = url;
}else{
qtp.SetURL(url);
qtp.Stop();
}
}   

function playerGetPosition(){
if(useWmp){
return wmp.controls.currentPosition;
}else{
return qtp.GetTime()/600;
}
}   

function playerSetPosition(t){
if(useWmp){
wmp.controls.currentPosition = t;
}else{
qtp.SetTime(t*600); //int
}
}   

function playerSetVolume(v){
if(useWmp){
wmp.settings.volume = v;
}else{
qtp.SetVolume(v); //int 0-100
}
}   

function playerSetRate(r){
if(useWmp){
wmp.settings.rate = r;
}else{
qtp.SetRate(r); //flost 0.5-1.0
}
}

These functions are called by a single event handler that manages calls from the Silverlight C# code using the techniques for C# to Javascript communications described in the QuickStart guide.

//Event handler for Silverlight control
function agEventHandler(sender, args){
switch (args.Name){
case 'stop':
playerStop();
break;
case 'play':
playerPlay();
break;
case 'pause':
playerPause();
break;
case 'url':
playerUrl(args.Sdata);
break;
case 'position':
playerSetPosition(args.Data);
break;
case 'volume':
playerSetVolume(args.Data);
break;
case 'rate':
playerSetRate(args.Data);
break;  

default:
}

The event handler arguments are defined on the C# side as follows:

//This class defines the arguments for the control's events
[Scriptable]
public class CustomEventArgs : EventArgs
{
    private double data;
    private string name;
    private string sdata;  

    public CustomEventArgs(string iname, double idata, string isdata)
    {
        data = idata;
        name = iname;
        sdata = isdata;
    }  

    [Scriptable]
    public string Name
    {
        get { return name; }
        set { name = value; }
    }  

    [Scriptable]
    public double Data
    {
        get { return data; }
        set { data = value; }
    }  

    [Scriptable]
    public string Sdata
    {
        get { return sdata; }
        set { sdata = value; }
    }
}//End of class

This class of custom event arguments allows the passing of a string name which specifies the media player event to control as well as a double and string parameter for data.

The event method is defined in the C# code like this:

//This defines the event from the control
//This is an example of how to fire an event from the control to Javascript
//AgEvents(this, new CustomEventArgs("hello", 25, "something"));
[Scriptable]
public event EventHandler<CustomEventArgs> AgEvents;

Finally, here is an example of C# code controlling the media player:

void play()
{
    if (playerState != (int)playerStates.paused)
    {
        AgEvents(this, new CustomEventArgs("position", t1, null));
    }  

    AgEvents(this, new CustomEventArgs("play", 0, null));

 

Hopefully, future releases of Silverlight will have a MediaElement with a rate control so that my application can be greatly simplified.

Renaming things in Visual Studio

August 14, 2007 at 7:03 am | Posted in Visual Studio | 9 Comments

Many newcomers to Visual Studio experience the problem of breaking their application after renaming something.  I certainly have!  First, there are many different names that are used to tag different things (see list below); second, there are multiple ways of renaming things and the impact on the IDE are not always clear to the novice; third, renaming things can sometimes confuse the Designer and your program because of references to names in the Designer generated code and helper files.

Here are some general guidelines that work for me:

1. It is always easier to name things when you first add them to your project. This includes everything from the initial project name to the controls you drag to your form from the toolbox.

2. Before renaming things like Classes, UserControls, NameSpaces, Assemblies etc, back up your project. This can be easily done in the Windows Explorer by making a copy of the Solution Folder for the project (found in your VS Projects Folder).

3. To change the name of something in your user code such as NameSpace, Class or UserControl, select an instance of the name in your code editor and use the Refactor > Rename function. You may have to rebuild the solution after this to get things back to normal.

4. To change the name of the Solution File or Project File, use the Solution Explorer and right click > Rename.

Here is a list of various high-level names that one might want to manage:

Solution Folder – this is the name of the top folder in the ..\Visual Studio 2005\Projects Folder. Change in Windows Explorer. Note that it is possible that this will confuse the Recent Projects Start Page but you should be able to use Open …Projects to find it.

Project Folder – this is the name of the folder(s) inside the Solution Folder with project data. (A solution can have more than one project.) Change in Windows Explorer. Note that it is possible that this will confuse the Recent Projects Start Page but you should be able to use Open …Projects to find it.

Solution File – the name of the solution. Change in the Solution Explorer, right-click Rename. Note that it is possible that this will confuse the Recent Projects Start Page but you should be able to use Open …Projects to find it.

Project File – the name of the project. Change in the Solution Explorer, right-click Rename. Note that it is possible that this will confuse the Recent Projects Start Page but you should be able to use Open …Projects to find it.

Assembly Name – as found in Properties > Application. This will be the name of your .exe file. Change in the Properties >Application dialog.

NameSpace – also in Properties >Application and in your code. This is useful for keeping your class and control names distinct from other code bases. Change using the Refactor.

Title – as found in Properties>Application>Assembly Information. This will be put in the title bar of the AboutBox. Change in the Assembly Information Dialog.

Product – also as found in Properties>Application>Assembly Information. This will be a name listed in the AboutBox. Change in the Assembly Information Dialog.

Timer for Silverlight 1.1

August 13, 2007 at 10:27 am | Posted in Silverlight | 3 Comments

I needed a timer control for a Silverlight 1.1 application but it is not supported in the Alpha release.  My solution was to use the timer in Javascript and have it send events to the C# code.

Event sending from Javascript to C# is described in the Silverlight QuickStart document.

Here is the initialization of the timer in Javascript:

//initialize silverlight event hookup and start timer 
var control; 
function init(sender){ 
control = sender; 
control.Content.basic.AgEvents = agEventHandler; 
setInterval(jtimer,10); 
}

In this routine, the timer is set to execute the jtimer function every 10 ms.  (The agEvents statement is used for sending information to the Javascript.  I will describe this later.)

The init function is called by the CreateSilverlight function in the page.js file:

// JScript source code 

//contains calls to silverlight.js, example below loads Page.xaml 
function createSilverlight() 
{ 
    Silverlight.createObjectEx({ 
        source: "Page.xaml", 
        parentElement: document.getElementById("SilverlightControlHost"), 
        id: "SilverlightControl", 
        properties: { 
            width: "100%", 
            height: "100%", 
            version: "1.1", 
            enableHtmlAccess: "true", 
            isWindowless: "True" 
        }, 
        events: { 
        onLoad: init 
        } 
    }); 

    // Give the keyboard focus to the Silverlight control by default 
    document.body.onload = function() { 
      var silverlightControl = document.getElementById('SilverlightControl'); 
      if (silverlightControl) 
      silverlightControl.focus(); 
    } 
}

Here is the jtimer function:

//Send position of player to silverlight based on a timer 
function jtimer(){ 
control.Content.basic.timer(playerGetPosition()); 
}

In this function, a function timer is called in the C# code with a value that is passed as an argument.

On the C# side, the timer function looks like this:

        //This receives the timer event from Javascript 
        [Scriptable] 
        public void timer(double arg) 
        { 
            tnow = arg;

Note the ‘[Scriptable]’ tag which makes the timer function usable from Javascript.

Finally, the page load event needs some boilerplate to hook the Javascript to C# communications:

        public void Page_Loaded(object o, EventArgs e) 
        { 
            // Required to initialize variables 
            InitializeComponent(); 
            //Register the scriptable endpoints 
            WebApplication.Current.RegisterScriptableObject("basic", this);

Testing the Visual Studio Plug-in

August 12, 2007 at 7:33 pm | Posted in Visual Studio | Leave a comment

Here is a  code snippet from Visual Studio using the plug-in for Windows Live Writer.

        private void button1_Click(object sender, EventArgs e)
        {
            string[] names = { "Scott", "George", "Mike" };

            Database1DataSet.Table1Row row;

            foreach (string name in names)
            {
                row = database1DataSet.Table1.NewTable1Row();
                row["name"] = name;
                database1DataSet.Table1.AddTable1Row(row);
            }
            table1TableAdapter.Update(database1DataSet.Table1);
            database1DataSet.Table1.AcceptChanges();
        }

It works!!!

public void Page_Loaded(object o, EventArgs e)
{
    // Required to initialize variables
    InitializeComponent();
    //Register the scriptable endpoints
    WebApplication.Current.RegisterScriptableObject("basic", this);
Next Page »

Blog at WordPress.com.
Entries and comments feeds.