Visual Studio: Add Uninstall to Your Application

First let me send a shout out to my reference for this little tidbit of information:  How to add a Uninstall option in Visual Studio Setup project without writing code GoGoToTo created a very nice article on this.  I simply expanded it further to include getting your application “registered” so within BigFix it will show up as one of the registered apps.

First View your File System so we can add the special folder “System”

Uninstall and Register 1

If your application is x86, then we’ll want to add the msiexec.exe from the c:\windows\SysWow64 folder.

Uninstall and Register 2

Uninstall and Register 3

Left click to highlight the msiexec.exe file and in the properties window, adjust as indicated in the following image:

Uninstall and Register 4

Next we’ll need to add a shortcut to the “User’s Program Menu”.  In my example, I’ve created a sub-folder named after my application.  Click that folder and in the right window, right-click and create a shortcut.

Uninstall and Register 5

Navigate to the System Folder and select the msiexe.exe file.

Uninstall and Register 6

Uninstall and Register 7

Before we modify the shortcut’s properties, we’ll need to copy the ProductCode from the Setup Application Properties.

Uninstall and Register 8

Using that ProductCode, modify the shortcut’s properties as follows:

Uninstall 8a

Now we get to register our application… Open the Registry View.

Uninstall and Register 9

Under HKEY_LOCAL_MACHINE add the following sub-keys:

Microsoft\Windows\CurrentVersion\App Paths\[name of your exe]

Remember to specify the last key to “DeleteAtUninstall” = True

Add the following 2 string values with the values as shown.

Uninstall and Register 10

 

That’s it.  You now have an uninstall link that will be created upon installation of your app.  You will also have your application properly “registered” so BigFix can properly detect it.

Advertisements

XML Deserialization

So, you have an XML document, your programming in Visual Studio 11 for your new Windows 8 Metro app, and you need to access the data within?  I’m here to help…

DE serializing your XML document is very simple.  First you’ll need to define a CLASS object the way your XML document is…

Here’s my example XML document:

<?xml version="1.0" encoding="UTF-8" ?>

<Congress>
  <Regions>
    <Region>
      <Title>Northeast</Title>

      <States>
        <State>
          <Title>Connecticut</Title>

          <Districts>
            <District>
              <Title>District 1</Title>
              <SubTitle>Larson, John B.</SubTitle>
            </District>
          </Districts>
        </State>
      </States>
    </Region>
  </Regions>
</Congress>

This is an example of an XML document I’m currently using in my contest application.  As you can see there can be multiple Regions, States or Districts.  Each organized in sub objects… I am showing you only one of each since it would get pretty long otherwise…

Now, we’ll need a few classes organized just like this XML document:

[XmlRoot("Congress")]
public class clsCongress
{
    [XmlArray("Regions")]
    [XmlArrayItem("Region", typeof(clsRegion))]
    public clsRegion[] Region { get; set; }
}

[XmlRoot("Regions")]
public class clsRegion
{
    [XmlElement("Title")]
    public string Title { get; set; }

    [XmlArray("States")]
    [XmlArrayItem("State", typeof(clsState))] 
    public clsState[] State { get; set; }
}

[XmlRoot("States")]
public class clsState
{
    [XmlElement("Title")]
    public string Title { get; set; }
        
    [XmlArray("Districts")]
    [XmlArrayItem("District", typeof(clsDistrict))]
    public clsDistrict[] District { get; set; }
}

[XmlRoot("Districts")]
public class clsDistrict
{        
    [XmlElement("Title")]
    public string Title { get; set; }
        
    [XmlElement("SubTitle")]
    public string SubTitle { get; set; }
}


As you can see form my class objects, you’ll need to specify the XmlRoot for each class as well as each XmlElement so everything maps correctly.  In my example, the elements match, but they don’t have to so long as they’re mapped with the XmlElement tag.

Now, I know you can find this code anywhere on the net… but what they don’t go into detail explaining is the array variables I have shown here. 

In my example, I have Congress which is made up of multiple Regions, which is made up of multiple States, and Districts.  In my example here, I demonstrate how to get multiple sub-objects pulled in easily and quickly.

Here is the code I use to load up the XML text, oh and I’m downloading this content using the new fancy async features from VS11 and Windows 8:

internal async Task PullRegionsAsync(Uri baseUri)
{
    string baseUrl = "https://danielheth.com/myexample.xml";

    //download the data xml
    //http://msdn.microsoft.com/en-us/library/windows/apps/system.net.http.httpclienthandler.maxrequestcontentbuffersize(v=VS.110).aspx
    //says there is a 65k limit on the size of what this function will download...
    var client = new HttpClient();
    var response = await client.GetAsync(baseUrl + "Data.xml");
            
    //------------------------------------------------
    //convert xml into an easily digestable object
    clsCongress congress = null;
    XmlSerializer des = new XmlSerializer(typeof(clsCongress));
    congress = (clsCongress)des.Deserialize(response.Content.ContentReadStream);
    //------------------------------------------------

    foreach (clsRegion r in congress.Region)
    {
        string RegionTitle = r.Title;

        foreach (clsState s in r.State)
        {
            string StateTitle = s.Title;

            foreach (clsDistrict d in s.District)
            {
                string DistrictTitle = d.Title;
            }
        }
    }
}

There you have it… deserializing your XML document into an easily digestible object within C#.

If you have any questions or comments please leave them below…

Windows 8 Metro Application–Bing Maps

I’ve entered myself into a new Windows 8 application contest.  I’ve come up with a wonderful idea which includes utilizing Bing Maps.  After an awful lot of research I’ve come up with something that works… Perfectly!!!

Since this is a Windows 8 application, I’m writing this in Visual Studio 11 express which utilizes an awesome multi-threading feature called async/await.  So I’ll be taking advantage of that here.

First thing I needed to do was acquire my Bing Map Developers key… Acquire yours free from:  https://www.bingmapsportal.com

Let’s start coding!!!

I followed the following MSDN article to setup my app for access to the Bing SOAP API’s.  http://msdn.microsoft.com/en-us/library/cc966738.aspx

Then added the following to the top of my code:

using HouseofRepresentatives.GeocodeService;
using HouseofRepresentatives.SearchService;
using HouseofRepresentatives.ImageryService;
using HouseofRepresentatives.RouteService;


private ImageSource _map = null;
public String Latitude = "";
public String Longitude = "";


public ImageSource Map
{
    get
    {
        if (this._map == null) UpdateMap();
        return this._map;
    }

    set
    {
        if (this._map != value)
        {
            this._map = value;
            this.OnPropertyChanged("Map");
        }
    }
}

I had two situations for my locations… in one case I knew the exact Lat/Lon, and in others I only knew an address… in my case a state name.  First I needed to turn that address into a Lat/Lon for passing onto the get map function.

private async Task<string> getLocationPoint(string address)
{
    if (address != null && address != "")
    {
        GeocodeRequest request = new GeocodeRequest();
        request.ExecutionOptions = new HouseofRepresentatives.GeocodeService.ExecutionOptions();
        request.ExecutionOptions.SuppressFaults = true;
        GeocodeServiceClient geocodeClient = 
            new GeocodeServiceClient(GeocodeServiceClient.EndpointConfiguration.BasicHttpBinding_IGeocodeService);
        HouseofRepresentatives.GeocodeService.Credentials t = 
            new HouseofRepresentatives.GeocodeService.Credentials();
        t.Token = "[[put your Bing Maps Key Here]]";

        request.Query = address;
        request.Credentials = t;

        GeocodeResponse response = await geocodeClient.GeocodeAsync(request);
        if (response.Results.Count() > 0)
        {
            return response.Results[0].Locations[0].Latitude.ToString() + 
                "," + response.Results[0].Locations[0].Longitude.ToString();
        }
    }
    return "";
}

Next I needed to actually get the Image from Bing.  Now let’s do that using the following function:

private async Task<string> GetImagery(string locationString)
{  //http://msdn.microsoft.com/en-us/library/dd221354.aspx
    string key = "[[insert your Bing Maps Key here]]";
    MapUriRequest mapUriRequest = new MapUriRequest();

    // Set credentials using a valid Bing Maps key
    mapUriRequest.Credentials = 
        new HouseofRepresentatives.ImageryService.Credentials();
    mapUriRequest.Credentials.ApplicationId = key;
                      

    // Set the location of the requested image
    mapUriRequest.Center = new HouseofRepresentatives.ImageryService.Location();
    string[] digits = locationString.Split(',');
            
    mapUriRequest.Center.Latitude = double.Parse(digits[0].Trim());
    mapUriRequest.Center.Longitude = double.Parse(digits[1].Trim());

    // Set the map style and zoom level
    MapUriOptions mapUriOptions = new MapUriOptions();
    mapUriOptions.Style = MapStyle.AerialWithLabels;
    mapUriOptions.ZoomLevel = 17;

    // Set the size of the requested image in pixels
    mapUriOptions.ImageSize = new HouseofRepresentatives.ImageryService.SizeOfint();
    mapUriOptions.ImageSize.Height = 240;
    mapUriOptions.ImageSize.Width = 480;

    mapUriRequest.Options = mapUriOptions;

    //Make the request and return the URI
    ImageryServiceClient imageryService = 
        new ImageryServiceClient(ImageryServiceClient.EndpointConfiguration.BasicHttpBinding_IImageryService);
            
    try
    {
        MapUriResponse mapUriResponse = await imageryService.GetMapUriAsync(mapUriRequest);

        if (mapUriResponse.Uri != null)
        {
            return mapUriResponse.Uri;
        }
        else { return ""; }
    }
    catch (Exception ex)
    {
        return "";
    }
}

Ok… now that I have my image Uri, it’s time to use it to load a picture:

public async Task<bool> UpdateMap(string address = "")
{
    if (address != "")
    {
        //then user is specifying an address instead of a specific long/lat.  
        //We need to get that info in order to proceed...
        string point = await getLocationPoint(address);
        if (point != "")
        {
            string[] p = point.Split(',');
            Latitude = p[0];
            Longitude = p[1];
        }
    }

    if (Longitude != "" && Latitude != "")
    {
        string uripath = await GetImagery(Longitude + "," + Latitude);
        if (uripath != "")
        {
            this.Map = new BitmapImage(new Uri(uripath));
            return true;
        }
        else
        {
            this.Map = new BitmapImage(new Uri(imageBaseUri, "Data/blank.png"));
            return false;
        }
    }
    else
    {
        this.Map = new BitmapImage(new Uri(imageBaseUri, "Data/blank.png"));
        return false;
    }
}

If you’ve stuck with me this far… you are a programmer… LOL.

In each of my functions I utilized the new async/await features.  This means when I call either of the two functions as below, it will load the image once the OS has downloaded and cached it.  The image will automatically appear when ready…

//calling the get-map function with an address
UpdateMap("Arkansas");

//or
UpdateMap("1 Microsoft Way, Redmond, Washington");

//or i can configure my lat/lon then update
Latitude = "39.450000762939453";
Longitude = "-98.907997131347656";
UpdateMap();

If you guys have any questions or comments, be sure to post them below!

Robocopy’ing Basics

So, you have a large batch of files and want to move or copy them reliably from one location to another.  (this works for nearly all scenarios:  local->local, local->network, ext hd->local, ext ht->network)

Microsoft TechNet reference for Robocopy

Helpful TechNet Magazine article on Robocopy   and another

Download it here if you don’t already have it

All you have to know is this simple command:

robocopy [destination] –z –e

/Z :: copy files in restartable mode.  This means if the command stops because the network is no longer available or some other reason… all you have to do is re-run the command and it’ll pickup where it left off.

/E :: copy subdirectories, including Empty ones.  This will recreate the exact directory tree… so if you’re copying an entire tree (files and sub-directories) it will exactly recreate it even if there are no files inside of a folder.

image

This command also takes advantage of a few defaults:

/COPY: DAT :: what to COPY for files.   This means the files that are copied, will also transfer over the data, attributes, as well as the timestamps like last modified, etc…

/R:n :: number of Retries on failed copies: default 1 million.  This means if the command fails it will sit and retry up to a million times before failing.  I rely on this since I usually run my command overnight.  If the network goes down, it is probably do to a simple power issue.  The hub will go down but the computers won’t due to my UPS’s.  When power is restored and the hubs come backup, the copy will continue.

/W:n :: Wait time between retries: default is 30 seconds.   If it fails as described previously, this is the timer which runs before retrying.  Every 30 seconds upon a failure. 

 

Robocopy is an essential command that everyone who uses computers should be aware of.  Put this one in your pocket and pull it out when needed. 

Podcaster XML Generator

I’ve been working on resurrecting what was known as RootSync.  I’ve also been working on making it a fully in-house project where everything from the hosts to the software the show runs on is built fully in-house.

Yesterday I sat down to create a podcast RSS feed application… and I’ve succeeded:

podcaster1

Podcaster 0.0.1 is an application to make generating those carefully crafted RSS feeds quick and easy. 

Upon installation you’ll be presented a basic windows form.  Hit the file menu and either open an existing iTunes compatible RSS XML file or start a new podcast.  Fill in the blanks and you’re done.

In the end you will end up with a simple document similar to this:

image

If you have any questions or comments, or even suggestions… PLEASE leave post them here…

This application is still in early beta version 0.0.1.  Thus there may still be bugs, if you find any post what happened and if possible some screen shots and I’ll get them repaired and a new version released ASAP.

Since we are in beta, this application is completely free for anybody to use for any purpose… Enjoy!Get it from CNET Download.com!

Launch either the Setup.msi or Setup.exe within.  Once installed look under your start menu->Moran IT->Podcaster  for the launch-able shortcut.

For best use… put your mp3 or mp4 all into the same directory with this rss file.  Like this:

image

Notice how I’ve got a different folder for each podcast.  Under each is the related graphics, feed.rss, and mp3/4’s. 

Podcaster will use the feed.rss’s PATH to search for related media when choosing the episodes media and graphic files.  It is linked to the Episode number… increment it and it will search for the related media file.

I host my own podcasts and have IIS setup to give the feed.rss as the default document.  Thus I simply put http://podcasts.rootsync.com/audio and the audio folders feed.rss is served up.

CountDown Timer

SNAGHTMLd734465During our last Week in Review broadcast, I realized we needed a timer which would provide us a visual queue for the start and stop of the broadcast.  Since our show is centered around the start of the hour and lasts for an hour, the programming was rather easy to accomplish.

I built an application which would count down to the hour and flash at the 2min warning and on the hour.  Since I have all these spare monitors on the wall, what better place to put it than up there.

Get it from CNET Download.com!

Wireless provides an easy Virtual GPS device

858001-1053401So I’ve done the research and have determined what Skyhook wireless and other Wi-Fi Mapping companies has done and it is ingenious!  Ok, let me set the scene:  Say you’re walking through the forest and spot an interesting tree.  Right next to that is another interesting tree.  If you end up walking in circles in the forest and you see those same two interesting trees you know where you are at that instant right?

Well… apply that same line of thinking to wireless access points (AP) anywhere in the world.  Skyhook has went around the world mapping out all of the access points and linking them to GPS locations… Thus if your in a certain location and you see 5 wireless access points around you and one of them has a 99% signal.  Odds are you are extremely close to that access point right? Send the information about that access point (like ssid and/or mac) to skyhook and they’ll send you back your most likely position.  This is the perfect mix of technology and good old fashion logic.

Well I’ve spent the time putting together the components needed to do this very same mapping and I’m sharing it with you guys free…  You will need a few things… a laptop with Wi-Fi and a GPS device. 

As far as code goes, you’ll need the following two visual studio 2008 projects:

1. WifiScanner (755kb) – a program to be run on the laptop.  It uses netsh and GPS (41kb) to map out all of the surrounding Wi-Fi access points. This map is uploaded via a SOAP call to our next program needed…

2. SOAP vGPS (56kb) – a server side application for databasing the mapped access points and returning results for finding your virtual GPS location.

The great thing about this project is the bigger the map gets the more accurate the vGPS becomes.

There are two directions these VS projects can go… the first is to complete the logging feature on the WifiScanner so the data can be captured off-line and uploaded at a later time… or second an offline and portable database can be created for personal use.  This database can be updated as you drive and vGPS can be taken with you so if you are not using the real GPS device, the vGPS can act as a viable alternative.

Comment on all the things you do with this stuff below…