Oct 24, 2008

Nice game for software developers :)

Some of you may remember the CRobots game. It is a game in which you program your own robot (in C) and put it to fight against other robots.
This game is available in 3D variant and I think it may be very userful to improve your programming skills.

Try it from here:

http://antru.ru/crobots3d/

I also built my own robot, I named it Kamikadze because all it does is to spin around and shout itself :D

Documentation can be found here:

http://crobots.deepthought.it/html/manual.html#8

Happy playing!
>

Oct 21, 2008

C# AddIn - Start Debugging and get the running Internet Explorer instance.

I needed to do this (actually I wanted). I was curious if you can obtain an instance of a Internet Explorer which was started in debugging session. Here is a snipet to do this:

        _applicationObject.Debugger.Go(
false);
        SHDocVw.
ShellWindowsClass windows = new ShellWindowsClass();
        
foreach (SHDocVw.InternetExplorer explorer in windows)
        {
          
if (explorer.LocationURL == string.Empty)
           {
            
// this is our guy!
             ie = explorer;
           }
        }


Note : this snipet should be added somewhere where you have access to the _applicationObject.
This is the variable which is declared automatically when you create new instance. I suggest you to put it into the exec method of the AddIn:

     public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
     {
        _applicationObject.Debugger.Go(
false);
        SHDocVw.
ShellWindowsClass windows = new ShellWindowsClass();
        
foreach (SHDocVw.InternetExplorer explorer in windows)
        {
          
if (explorer.LocationURL == string.Empty)
           {
            
// this is our guy!
             ie = explorer;
           }
        }
     }

You also need to add reference to ShDocVw (Microsoft Shell And Automation Library).
Enjoy!

Oct 19, 2008

Touchless SDK : Very interesting and promising technology each of you guys should play with :)

I came on this yesterday, I was bored because all the projects I am working on are to some degree "standard". No dev chalenge. I wanted to create, to do something interesting.
So I started to browse CodePlex and found this SDK.

Overview :
Touchless SDK is a software development kit to help developers create applications which can be controlled without the standard peripheral devices (mouse, keyboard and so on). It enable you to create a applications which are controlled without the need to touch anything at all, just gestures in the air.
How is this done?
Well, I think there was a lot of research on this topic. We already have programs to detect motion from your video camera, why not try to extract information from those motions? This is
exactly what Touchless does. It captures an info from your camera and if it finds something that is known to be marker - it raises events, to which you can subscribe and do something.
The better news is that Touchless is Open Source project and can be obtained from CodePlex for free.
You can also whach a video on Touchless:





I downloaded this SDK and in less than a minute I made a small program which let's you move your cursor with fingers (I still can't find a good enough way to left and right click ;).
I hope I will have enough time this week to post this simple project so you can get deeper with Touchless as it seems promising technology to me.

Limitations:
Well every good thing has drawbacks. Don't get it wrong. Touchless isn't the standard in this area. It has problems (however I think after it is open source a lot of people can work on it and improve it).
So what are the limitations?
First of all - Touchless is very very very sensitive to light and to colors. It is because the way it works. In order to work, you need to specify a "marker". Marker is the thing the program looks for. So if you have a red tape on your finger and define it as marker, you will be able to command your computer with it. But if there is a object with the same color on the screen and this object is about the same size, it may be found as another marker.

The second problem (at least for the sample project I did) is that most web cameras are not sensitive enough. They are (most of them offcourse) with 640 x 480 pixels resolution. If you are about to move your cursor and your screen resolutions is 1280 x 1024 you will be only able to move the cursor 640 pixels horizontally and 480 pixels vertically (this can be software corrected by moving the cursor 3 or 4 pixels on each pixel that comes from the camera but for sensitive operations (resizing, drawing) it will not be good enough.


However I think the things above will be resolved and we will have another great way to use our computers for almost no extra charge.
I do really wish those guys luck and I will definatelly watch how this project goes and even if I can I will help a bit.
I really fell in love with this toy!

Oct 16, 2008

C# - Web Browser Control - Load String in Web Browser control (4th way).

Here is one more way to load string in Web Browser Control (C#). This is in case you are using the managed control.

        
// Fourth way to write html in WebBrowserControl with C#:
        wb.DocumentText = strHtml;

I can tell you (just guessing) that this will be the best one as it became available in the managed control (at least I didn't found it in the old COM versions). That is why I think it was reviewed and probably optimized.
>

C# - Web Browser Control - Load String in Web Browser control.

I was thinking about this long time ago. I recently found this post:

http://www.xtremevbtalk.com/showthread.php?t=167531

So how to load a string in WebBrowser Control with C#?

First - navigate to "about:blank" (as the web browser needs a document to operate on)
Then use WebBrowser.Document.Write(string text) to write the string you want to load in the WebBrowser control. Kind of tricky but ...

Another way is to write something like:

about:your html here

And the last one is to write the document on the hard disk with StreamWriter for example, and then to navigate to it.

Here is a code to show you all methods discussed:


        
WebBrowser wb = new WebBrowser();
        
// First way to
write html in WebBrowserControl with C#:
        string strHtml = "you html here";
        wb.Navigate(
"about:" + strHtml);

        
// Second way to write html in WebBrowserControl with C#:
        wb.Navigate("about:blank");
        wb.Document.Write(strHtml);

        
// Third way to write html in WebBrowserControl with C#:
        const string strAddress = "test.html";
        
using (StreamWriter sw = new StreamWriter(strAddress))


{
        sw.Write(strHtml);
        

}      wb.Navigate("file://" + Application.StartupPath + "\\" + strAddress);

Oct 7, 2008

One more ASP.NET page optimization ...

I wrote two articles on this topic already. The first was that you can earn few bytes from renaming the "javascript:__doPostBack" to "__dp". Then I noticed that I have problems with this. The problem was that in some cases you need to have the "javascript:" prefix.

So my first attempt to do some optimization is considered more unsuccessful than successful.

Now I am going to propose another way.
It is again based on removing / renaming / moving existing things in the page so they can be a bit more optimized.


Let's suppose we have a GridView. We clicked on the "Auto Format" thing and we not only have a GridView, but we have a nice looking grid view. It's great, but it seems to be unefficient. It appears that the GridView will add a
style="" attribute for each row / cell (not quite sure about the exact rules). And it will generate repeating markup, increasing the size of the page and respectivelly - your bandwidth.

I did a small snipet to fix this (not the best solution again but should be kind of starting point).

Here is my code:

     protected override void Render(HtmlTextWriter writer)
     {
        System.IO.
StringWriter stringWriter = new System.IO.StringWriter();
        
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);

        
this.EnsureChildControls();
        
base.Render(htmlWriter);
        
string html = stringWriter.ToString();

        AnalyzeStyles(html);
        html = RepairStyles(html);

        writer.Write(html);
     }

    
private void AnalyzeStyles(string html)
     {
        
MatchCollection CSSMatch = Regex.Matches(html, "style=[\"].+?[\"]", RegexOptions.IgnoreCase);
        
foreach (Match mCss in CSSMatch)
        {
          
if (htDuplicates.ContainsKey(mCss.Value))
           {
             htDuplicates[mCss.Value] =
Convert.ToInt32(htDuplicates[mCss.Value]) + 1;
           }
          
else
           {
             htDuplicates.Add(mCss.Value, 0);
           }
        }
     }

    
private string RepairStyles(string html)
     {
        
int classID = 0;
        
int pos;

        
IDictionaryEnumerator iOccurences = htDuplicates.GetEnumerator();
        
this.CSS += "";

        InformaticsWeb.Pages.
Optimized master = (InformaticsWeb.Pages.Optimized)this.Master;
        
        pos =
Regex.Match(html, "", RegexOptions.IgnoreCase | RegexOptions.Singleline).Index + "".Length;
        
        html = html.Insert(pos, CSS);
        
return html;
     }

Please note : AnalyzeStyles adds each of the style="" found on the page (each unique). If it finds secound and third and so on - it increases a counter. The counter is not currently used, but may be later used to decide which of the styles should be converted to CSS classes.

So this code basically takes the page and moves all the style="" attributes in the head section as a CSS classes. I tested and my grid view seems as beautiful as before this code was applied.

Now, does it worth to add this logic?
Well I think you can achieve the same functionality by using Skin files. I am adding this more for reference.
I also did a small excel diagram to show you how much bytes are saved based on the count of the items in the GridView:




Please note that the htDupplicates is a Hashtable, declared as a global variable, so you will need to add it if you want to use this code.

Let me now explain the columns in the excel file shown above.
The “Columns” column displays how much columns does the GridView render. Typically the columns are rendered as a table cells and doesn’t contain any style=”” attributes (at least I couldn’t see any), so this is something you can’t affect. The thing that this optimization affects is the number of rows in your gridview. The more rows you have the more bytes you will get.
The second column displays the number of rows in the grid view.
The third column is the optimized size of the gridview (when the above technique is applied).
The “Size Original” column displays the size for unoptimized page (the same page!).
And the last column shows you the difference before and after.

You can see it in the diagram - for 20 items you have about 842 bytes difference. While for 80 you have about 3,512 (I don’t think there is a live site which displays 80 items at once in a grid view ;).

Oct 6, 2008

Very elegant way to cut few more bytes from your ASP.NET markup and optimize your bandwidth a bit (2) - Solving the puzzle

As I mentioned in my previous post, I ocassinally received errors when replacing the "javscript:__doPostBack" with "_dpb". It saved few bytes, yes, but for example the ASP Menu stopped working.

I finally found what was causing the problem. It is because of links (rendered as "a href"). The ASP Menu renders them as a href="javscript:__doPostBack()". If you remove the "javascript:" part you will have problems as the browser will not be able to understand that you are trying to call a JS function. A possible solution is to move the call to the OnClick of the "a" element, leaving "#" in the "href" attribute like this:

a href="#" onclick="_dpb()"

This will however cause a small side effect. When the user clicks on the first
of a series of links, all the links will change their css class to "visited:" css class (because the browser sees you already have visited the "#" address).

Conclusion : You can apply the above technique but it will not help you much and I think it involves to much efforts for a small effect (few bytes). If you really want to get this benefit you can replace the "javascript:__doPostBack" with "javascript:_dp" and you will get less bytes than if removing the "javascript:" part but the page will work as expected.

I am currently working on other techniques to cut more of the ASP page markup, but they are a bit more serious. I hope I will write another post soon to inform you how it is going.

Oct 3, 2008

Very elegant way to cut few more bytes from your ASP.NET markup and optimize your bandwidth a bit

I was thinking about how can I optimize the markup of a page a bit.
I found a great way (great but not very very very efficient) to do so.
It is based on a strategy that came in my mind recently.

Let's think a bit.
We already have very interesting methods to cut bandwith of an ASP.NET page like for example compressing the view state and so on and so on.
So provided we already have applied those techniques, if we still want to optimize what should we do?

I call my method : iterative profit, you will soon understand why ...

If we have something that repeats few times in the markup and is relatively long as name, if we make it shorter we should win some bytes right?
And if the page is big enough and "the thing" is repeated more times, we
will win more and more bytes.
So each time we cut the name of something, we win few bytes.

The next question is what can we cut in order to optimize our page?
What is the thing that repeats in each web control?

The answer is the "__doPostBack" function. I tried to replace it during the Rendering of the page and was able to cut a bit of the page size, while keeping the source relatively clean of errors (please note the word "relatively").

Here is a sample code:

     protected override void Render(HtmlTextWriter writer)
     {
        System.IO.
StringWriter stringWriter = new System.IO.StringWriter();
        
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
        
base.Render(htmlWriter);
        
string html = stringWriter.ToString();
        html = html.Replace(
"\"javascript:__doPostBack", "\"__dpb");
        writer.Write(html);
     }

I had some issues I haven't yet identified, as I was in a rush to post this as it seems to me a brand new way to optimize pages - to look for repeating elements and cut their names... (I will be happy if there are volunteers to help with this one ;)...


Other things : DoPostBackWithOptions should also be replaced by dpbw for example, this will be done in the future, after I clean the _doPostBack as it still have few problems.


And some more things - we may consider optimizing some of the ASP.NET controls which are known to be "markup unoptimized" like the treeview, gridview for example (At least I think there may be some things in them to optimize).

Any comments are welcome.

Something that a lot of C# developers will miss when designing their classes

The thing is that the developers often forget they can set access modificators at set / get level for a property.

Consider the following classes:

namespace Locals
{
  
class Program
   {
    
static void Main(string[] args)
     {
        
LocalManager LocalMgr = new LocalManager();
        Remote.
RemoteManager RemoteMgr = new Remote.RemoteManager();
        
User usr = new User();

        LocalMgr.Promote(usr);
        
Console.WriteLine("After local promotion: " + usr.Occupation);
     }
   }

  
public class LocalManager
   {
    
public LocalManager() { }
    
public void
style="color:Black;"> Promote(User usr)
     {
        usr.Occupation =
"Chief Officer";
     }
   }

  
public class User
   {
    
private string strOccupation;
    
public User() { }
    
public string Occupation
     {
        
get { return this.strOccupation; }
        
set { this.strOccupation = value; }
     }
   }
}

Here, after the program is executed the Local manager will promote the user and the output will be :
After local promotion: Chief Officer

Now imagine that we want to have the name of the manager who promoted the User, so we can store it in a database. Obviously we need to have an instance of the Manager class, and write the information in the database, prior changing the occupation for the user.

We will want to have a method in the User class, which takes the Manager instance, writes everything needed in the database and then changes the Occupation.
But we can't be sure that all developers will use the method and not the property directly.

Firs let's add a property to the LocalManager class to hold the name of the manager. Then I will create a method to change users occupation, which will take an instance of LocalManager. This will be the only way an external class to change the occupation of a user. After this, we will slightly modificate the code in the main program so everything is called properly. Here is the code:

using System;
using System.Collections.Generic;
using System.Text;

namespace Locals
{
  
class Program
   {
    
static void Main(string[] args)
     {
        
LocalManager mgr = new LocalManager();
        mgr.ManagerName =
"Pavel Donchev";
        
User usr = new User();
        mgr.Promote(usr);
        
Console.WriteLine("After promotion: " + usr.Occupation);
     }
   }

  
public class LocalManager
   {
    
private string strManagerName = string.Empty;

    
public LocalManager() { }
    
public void Promote(User usr)
     {
        usr.Promote(
this, "Chief Officer");
     }
    
public string ManagerName
     {
        
get { return this.strManagerName; }
        
set { this.strManagerName = value; }
     }
   }

  
public class User
   {
    
private string strOccupation;
    
public User() { }
    
public string Occupation
     {
        
get { return this.strOccupation; }
        
private set { this.strOccupation = value; }
     }
    
public void Promote(LocalManager manager, string Occupation)
     {
        
if (null != manager && !string.IsNullOrEmpty(manager.ManagerName))
        {
          
// Do additional work here, for example write the
           // name of the manager in the database amoung with
           // time stamp of the promotion to have audit...

          
this.Occupation = Occupation;
        }
        
else
        {
          
throw new Exception("A valid manager instance and occupation should be passed!");
        }
     }
   }
}

Now our classes are ready. You can give your user class away and be sure that no one can modify the property without passing a valid manager instance (actually the sequence of exceptions will guide your peers to follow the correct logic ;).


Oh, one more thing - we didn't proof that no one can assign the User.Occupation property directly. Well try to do so, you should receive compiler error message:

The property or indexer 'Locals.User.Occupation' cannot be used in this context because the set accessor is inaccessible

Aug 22, 2008

ASP.NET / C# - Dynamically change ObjectDataSource SelectMethod may lead to troubles.

First of all - how to reproduce this?

Add a Grid View, Object DataSource and a dropdown to a web form. Also you will need a class which has two methods with different names and can be marked as SelectMethod (return a List for example).
Here is my sample web form:
<asp:Panel ID="pnlFilter" runat="server" GroupingText="Category:">

<asp:DropDownList ID="ddProductCategory" runat="server"

onselectedindexchanged="ddProductCategory_SelectedIndexChanged"

    AutoPostBack="true">

    <asp:ListItem Value="0">All Categories</asp:ListItem>

<
asp:ListItem Value="1">Electronics</asp:ListItem>

     </asp:DropDownList>

asp:Panel>

<
asp:Panel ID="pnlProducts" runat="server" GroupingText="Products:">

<
asp:GridView ID="grdProducts"

runat="server"

    
DataSourceID="odsProducts"

    
AutoGenerateColumns="true"

    AllowPaging="true"

    PageSize="2">

asp:GridView>

<
asp:ObjectDataSource ID="odsProducts" runat="server"

DataObjectTypeName="string"

    TypeName="WebApplication2.ProductsCollection"

    SelectMethod="SelectAll">

    asp:ObjectDataSource>

asp:Panel>



Here is the code in the code behind:



protected void Page_Load(object sender, EventArgs e)

{

        

}



protected void ddProductCategory_SelectedIndexChanged(object sender, EventArgs e)

{

if (this.ddProductCategory.SelectedValue == "0")

    {

    
// Select all products from all categories

        // SelectAll() doesn't take any parameters.

        this.odsProducts.SelectMethod = "SelectAll";

        
this.odsProducts.SelectParameters.Clear();

}

    
else

    {

    
this.odsProducts.SelectMethod = "GetByCategoryID";

        
this.odsProducts.SelectParameters.Clear();

        
// Pass category id:

        this.odsProducts.SelectParameters.Add("categoryID", TypeCode.Int32, "1");

}

}



And finally the sample class:



public class ProductsCollection

{

public ProductsCollection() { }



public
List<string> SelectAll()

    {

    
List<string> retList = new List<string>();

        retList.Add(
"Notebook");

        retList.Add(
"PDA");

        retList.Add(
"GSM");

        retList.Add(
"Tomatoes");

        
return retList;

     }



    
public List<string> GetByCategoryID(int categoryID)

     {

        
// We will imagine that here we have some processing based on

        // categoryid.

        List<string> retList = new List<string>();

        retList.Add(
"Notebook");

        retList.Add(
"PDA");

        retList.Add(
"GSM");

    
return retList;

}

}



What we want to achieve here?

Well, we simply want to display all products from all categories when the user loads the page for the first time. Then we want to give him / her a way to narrow down the results, by selecting a concrete category of products (in our case there is only one category named “Electronics”



The most logical is to change the SelectMethod of the ObjectDataSource from SelectAll() to GetByCategoryID and vise versa.



And, yes, at first sight it seems to work like a charm. But try to navigate to the second page of the GridView (I made the PageSize to be 2 items so the paging control can appear).



You will receive exception in some cases. To see do the following.

1. Refresh the page so you can start from the beginning.

2. Select “Electronics” from the Categories Dropdown.

3. Click on page 2 in the GridView.





Where is the problem here?

As you may already noticed the ObjectDataSource is trying to invoke the Products using the SelectAll() method, passing it parameters for GetByCategoryID.



The reason is that the ObjectDataSource seems to maintain only the SelectParameters and get the SelectMethod from the markup. But for some reason this only happens when the GridView asks for rebind (PageIndex changed and Sorted events).

When you change in the dropdown selected index changed it works.



I have kind of workaround which I will post a bit later and it is not proven to work in all cases but did the trick for me.

Aug 15, 2008

Microsoft SQL Server – nested loops without cursors

I can’t think of a good enough examples on this topic. However, I’ll try to explain.

Let’s say we have 3 tables. Products, Sizes and Items. The Products table holds your products for example - T-Shirt, Shoes and so on. Sizes table holds the sizes for those items - Large, Medium and Small. The Items table holds a combination of valid items - like : Shoes Large, Shoes Small, Shoes Medium and so on.

Let’s say that you have 3 records in the Products table and 3 records in the Sizes table. You need to create all combinations between them (Shoes S, Shoes M, Shoes L …).

So in C# would look like this:

foreach(Record recordProduct in Products)
{
foreach(Record recordSize in Sizes)
{
// Check if the compound record (recordProduct.ProductID,
recordSize.SizeID) exist in Items table
// add it if it doesn't.
}
}

I think most of the developers will use a cursor to achieve this. But I didn’t. I don’t like cursors very much so I tried to do it my own way.

Here are the create scripts for those tables first:

Products:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Products](
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[ProductName] [nvarchar](50) COLLATE Latin1_General_CI_AS NULL
)
ON [PRIMARY]


Sizes:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Sizes](
[SizeID] [int] IDENTITY(1,1) NOT NULL,
[SizeName] [nvarchar](50) COLLATE Latin1_General_CI_AS NULL
)
ON [PRIMARY]


And finally, Items:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Items](
[ItemID] [int] IDENTITY(1,1) NOT NULL,
[SizeID] [int] NOT NULL,
[ProductID] [int] NOT NULL
)
ON [PRIMARY]

We want to add all the combinations in the Items table. To make it a bit more complex we would imagine that some of the items will be already generated so prior adding a combination we would like to check if it does not exist.
Here is my script to achieve this:

INSERT INTO Items
SELECT S.SizeID, P.ProductID FROM Sizes S, Products P
WHERE (SELECT ItemID FROM Items WHERE SizeID=S.SizeID AND ProductID=P.ProductID) IS NULL

3 lines of code…
Run it. It should affect some rows when starting it for first time. Run it again, without adding new records to Products or Sizes. It should say: “0 rows affected.”. Now add a product or a size or both. Run again. It will generate the new combinations.

Seems to be fine.

Considerations:
First of all I don’t think you will have to update such table on a daily basis. You may have a table to connect two tables but typically you will not need to generate all possible combinations. You may want to do this if you are updating some database on staging / production server for example.

Second - I am not quite if this approach is faster than the cursors / temp tables or any other approaches you may come up with, so use your head, don’t trust me. I am proven to make fundamental mistakes (see Check if a character is lower case post for reference ;)).

Third - I think you can use this to add another nested loop, so you can have nested loop in a nested loop in a nested loop. Or, with other words, to generate all possible combination between 3 or 4 or even more tables. I can not think of something to stop you doing so.

And last but not least - if you really need to access a combination of two tables, you may consider using view to select them. This way you will not have a physical table to take care of. It’s up to you.

I really love critics, positive or negative ;)

Aug 14, 2008

Skype4COMLib and Blogger - get your posts as a mood text in skype (or do whatever you want with skype ;).

My dear friend Bobby is going on vacation today at 6 p.m. Since I’m going to miss her while she’s taking her vacation on Black Sea I decided to play a bit with Skype4COM and write a small program for her.


This is where everything started ;) (thanks, Bobby for the inspiration ;).
She had her skype mood text set to how many days are until her vacation takes place. I wanted to help her so I wrote a simple tool to countdown until 6 p.m. and change her Skype mood accordingly.

Well I am not going to explain you how I did this. I got better idea later. I decided to make a mood changer for me. The mood changer will take my blogger posts and rotate them as skype mood text.

Skype Mood Text Changer, made with Skype4COM Lib and .NET C#

First of all, where should I get my posts from? Well, there are two ways I can think of. The first one is to use the Blogger API (login with the user, get all user blogs, get all user posts, etc.).
The second one is to use the RSS feed that blogger automatically creates for each blog.
Since this is very small tool I think the first approach is too “heavy” and “complex”. After all we aren’t going to post to the blog or anything that will require us to login in Blogger. So I took the RSS approach.

Let’s see how you can create a small program to do this for you:
1. Start new windows application.
2. Right click your References folder in the solution explorer and choose Add Reference …
3. In the dialog box click on the “COM” tab and find Skype4COMLib.
4. Click OK.

Now you have that skype thing referenced in your project. Add it to your using clause:

using SKYPE4COMLib;

After we are here, and we know we are going to use RSS, we will need Xml namespace as well. Add it too:

using System.Xml;

Okay. In my approach, I wanted to display random post on every 10 seconds. This means I will need to store a post title -> post link pair somewhere. I did this in a generic List of string[] arrays. I am not quite sure how optimized is this but this is only sample and it works fine for me. If you can think of something more optimized - please do not hesitate to write a comment ;). For now, however, add the System.Collections namespace to your using clause:

using System.Collections;

Okay, we have everything we will need to create our small tool. Now add a timer on your form. It’s timer1 in my sample. Set it's interval to 10000 (10 seconds).

Add the following global variables to your project:

List<string[]> posts = new List<string[]>();
private SKYPE4COMLib.Skype skype;

Here is how your Form_Load event should look like:

    
private void Form1_Load(object sender, EventArgs e)
     {
        skype =
new SkypeClass();
        
this.WindowState = FormWindowState.Minimized;
        GetBlogs();
        timer1.Enabled =
true;
     }

What I want you to note in the Page_Load is that I am assigning the skype variable. This way it will remain linked to your skype until the program is runned.

I used routine GetBlogs() in this project, here is it:

private void GetBlogs()
{
XmlDocument docRSS = new XmlDocument();
docRSS.Load(
"http://donchevp.blogspot.com/feeds/posts/default?alt=rss");
    
foreach (XmlNode nodeItem in docRSS.SelectNodes("/rss/channel/item"))
    {
    
string title = nodeItem.SelectSingleNode("title").InnerText;
        
string href = nodeItem.SelectSingleNode("link").InnerText;
posts.Add(
new string[] { href, title });
    }

}


NOTE: replace the url in the docRSS.Load() method, otherwise you will promote my blog ;).

This routine simply takes all the posts and stores them in the List of string arrays as link, title pairs.
Now we need to display the posts as title “-“ link. This will happen in the timer1_Tick event:

private void timer1_Tick(object sender, EventArgs e)
{
int iPostIndex = int.MinValue;
    
if (posts.Count > 0)
    {
    
Random rnd = new Random();
        iPostIndex = rnd.Next(0, posts.Count);
        skype.CurrentUserProfile.MoodText = posts[iPostIndex][1] +
" - " + posts[iPostIndex][0];
}
}

Everything seems to work fine now. Run your program. Skype should ask you if you are sure you want to give access to this program to use skype. Agree with that. You should now see your posts rotating each 10 seconds.

Here is the complete code (I will also upload the project on Chameleon Bulgaria site, as codes in Blogger doesn’t appear very smoothly):

Form1.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using SKYPE4COMLib;
using System.Xml;
using System.Collections;

namespace dayOffCounter
{
  
public partial class Form1 : Form
   {
    
List<string[]> posts = new List<string[]>();
    
private SKYPE4COMLib.Skype skype;
    
public Form1()
     {
        InitializeComponent();
     }

    
private void Form1_Load(object sender, EventArgs e)
     {
        skype =
new SkypeClass();
        
this.WindowState = FormWindowState.Minimized;
        GetBlogs();
        timer1.Enabled =
true;
     }

    
private void GetBlogs()
     {
        
XmlDocument docRSS = new XmlDocument();
        docRSS.Load(
"http://donchevp.blogspot.com/feeds/posts/default?alt=rss");
        
foreach (XmlNode nodeItem in docRSS.SelectNodes("/rss/channel/item"))
        {
          
string title = nodeItem.SelectSingleNode("title").InnerText;
          
string href = nodeItem.SelectSingleNode("link").InnerText;

           posts.Add(
new string[] { href, title });
        }
     }

    
private void timer1_Tick(object sender, EventArgs e)
     {
        
int iPostIndex = int.MinValue;
        
if (posts.Count > 0)
        {
          
Random rnd = new Random();
           iPostIndex = rnd.Next(0, posts.Count);
           skype.CurrentUserProfile.MoodText = posts[iPostIndex][1] +
" - " + posts[iPostIndex][0];
        }
     }
   }
}

Things to consider: Unfortunately skype has some constraints we can not avoid. First of all - the text seems to be too short to hold some of my posts, which results in links not being rendered correctly and leading to a wrong page (or even worse - to a page that doesn’t exist). I really wish to be able to set click here links as a mood text but it is not possible for now (at least I couldn’t find such functionality).

Happy codding!

Skype4COM Lib - how to register Skype ?


I wrote few tools, which only worked on my computer and not on the computer of my collegue - Bobby. She was having newer version of Skype and in the beggining I assumed it is a protocol problem. It finally appeared that the problem is her computer not having Skype4COMLib registered. So if you run in such a trouble, do the following :

1. Find the Skype4COM.dll file on your computer (typically it is in : C:\Program Files\Common Files\Skype)
2. Go to your Start Menu -> Run ...
3. Type cmd
4. In the command prompt type : regsvr32 Skype4COM.dll or "regsvr32 C:\Program Files\Common Files\Skype\Skype4COM.dll" depending on in which directory you are with the cmd (note the quotes that surround the path ;) ...


Everything should be fine now.

NOTE: I am writing this post not because it is something complex, but because I often forget how to register something ... Especially Skype :). Now I (and you) will have a reference, so don't be shy, add this post to your bookmarks :P

P.S. I hope I will be able to write a small tool to register Skype4COMLib

Jul 25, 2008

Microsoft SQL - you can ommit the INTO clause in insert statement?

I am not quite sure if this is a known feature / bug, but it is possible to write

INSERT Products (ProductName)
VALUES ('TestProduct')

instead the "standard":

INSERT INTO Products (ProductName)
VALUES ('TestProduct')

I repeat, I am not quite sure if this is standard behaviour for Microsoft SQL Server, and for which versions. I am not quite sure even if it is valid for all INSERT scenarios you may face, but I tried few different scenarious which include insertion of rows and it works like charm.

Note: I will suggest you to stick with the
INSERT INTO as it seems "more standard" to me. Furthermore if you are using some tools to do some SQL work (tools which may need to parse your
SQL) you will probably need to change back to INSERT INTO if you have used INSERT.

Nice TFS Query

I needed to find all my tasks I had closed, but I hadn't added time input for.
I was thinking how can I sort all my TFS tasks to achieve this and it appeared to be very strightforward.

Here is what you should do:

TFS Query to get all closed tasks without working hours.

In other words you are saying :

Your new TFS query will look like this.

"Give me all the work where the completed work is 0 hours, the state is closed and it is assigned to me."

After you save and give a name to your TFS query, you will find it under the "My Queries" node in your Team Explorer window:

>

Jul 17, 2008

Code Policies - the first step to get rid of boring code policy violations is made.

As I and Vesko (only!) discussed - it is great to follow code policies, and they are saving time. A lot of time. I agree.
I really like to have so strict policies at work so I can find for example the ObjectDataSource of some dropdown, without knowing its name. For example i will type "objDsSomething" or "odsSomething" or "ODSSomething". It really saves time.

I don't really agree with Vesko's opinion that only in the begining you are violating the code policies. I think even developers who worked on the same project for year will violate its policies (not so often offcourse).

The problem is that we are all human beings and we all make mistakes. I decided to do something to help myself get rid of at least the boring code policies - such
as naming conventions.
Here is what I have so far (I started this thing few days ago and I am working on it for about an hour daily after I was all day at work so it may not look very promising but I think it has potential):



When you click on "Validate Current Document" the document which is currently open will be validated against predefined naming conventions. If you violated something you will have this output:



I have few more problems to solve and will be really glad if someone can point me the direction:

1. I need to find a way to add this menu to the context menu for the document and also I would like to add hot key so you can for example validate the document by pression "CTRL + V + D" or something else (this is low priority).
2. I would also like to be able to check the code itself for inadequate assignments, method calls and so on. The CodeModel approach I think, will not allow me to do so.
3. I would like to change those standard icons with custom ;) (low priority).

Currently this thing can fly only for naming conventions.