C# Passing Values Between Multiple Projects using Interface

Earlier when I was doing some major update on a project I was working on for a client, I was also thinking how to optimize the code, not just by using MVP pattern and also the way of passing values between projects. Some of my class libraries where using the same type of property and then gets updated in the main form. I noticed though that setting the same value into the multiple objects with one type of property is pretty hard and unmanageable and also producing a lot of lines of codes. So I experimented a little bit and made an proof on concept how to pass values into multiple projects with minimal coding and using Interface

Let's see the sample animation below. What was shown there is we have satellite that moves in the form and there are 3 child forms. Those 3 child forms are the other 3 projects which are PlanetEarth, PlanetMars, and PlanetSaturn project and the big the form is our Main project. You'll notice that the 3 forms are getting updated everytime the satellite make its next move.

What is so interesting in using an Interface is you can share its values to whoever uses it. Like what I did on that simple P.O.S. project. Those 3 forms, PlanetEarth, PlanetMars, and PlanetSaturn is using one interface but they all get the update.

So why Interface instead of making a property for each project?

Because like I said, you can share the values between multiple projects or whoever uses it.

Let's get into the code

In this sample VS solution. We have 5 projects.

GlobalInterface class library project which contains the Interface code which have an NextPosition property signature what we're going to use later on the Main Project

public interface iSatellite
{
	Point NextPosition { get; set; }
}

Then we have 3 projects that has the same code (For demo only) which is using this iSatellite interface. These are the PlanetEarth, PlanetMars, and PlanetSaturn. Let's take PlanetEarth for example

GlobalInterface.iSatellite Satellite;

public Form1()
{
	InitializeComponent();

	timer1.Interval = 100;
	timer1.Tick += new EventHandler(timer1_Tick);
}

void timer1_Tick(object sender, EventArgs e)
{
	// update the location information of the satellite
	label2.Text = string.Format("X: {0}\r\nY:{1}", this.Satellite.NextPosition.X, this.Satellite.NextPosition.Y);
}

public void InitializeSatellite(GlobalInterface.iSatellite satellite)
{
	this.Satellite = satellite;
	this.timer1.Start();
}

As you noticed, we used Timer object to show the next location of the satellite. We could also use Event to shout that the satellite is making a next move.

InitializeSatellite(GlobalInterface.iSatellite satellite) will be called on our Main Project to bind the "this.Satellite" into our Main project.

Next is our Main project that implements iSatellite interface

public partial class MainController : Form, GlobalInterface.iSatellite
{
	TweenLibrary tween;
	Random destXY = new Random(DateTime.Now.Millisecond);
	List<Form> forms;

	public MainController()
	{
		InitializeComponent();
		InitializeControls();
		InitializeControlEvents();
	}

	public void InitializeControls()
	{
		// show our 3 forms
		PlanetEarth.Form1 earth = new PlanetEarth.Form1();
		earth.InitializeSatellite(this);
		earth.Show();

		PlanetMars.Form1 mars = new PlanetMars.Form1();
		mars.InitializeSatellite(this);
		mars.Show();

		PlanetSaturn.Form1 saturn = new PlanetSaturn.Form1();
		saturn.InitializeSatellite(this);
		saturn.Show();

		// then put them on the list to update their location
		forms = new List<Form>()
		{
			earth, mars, saturn
		};

		tween = new TweenLibrary();

		timer1.Interval = Convert.ToInt32(TimeSpan.FromSeconds(3).TotalMilliseconds);
		timer1.Tick += new EventHandler(timer1_Tick);
		timer1.Start();
	}

	public void InitializeControlEvents()
	{
		this.LocationChanged += new EventHandler(Form1_LocationChanged);
	}

	/// <summary>
	/// update child form positions
	/// </summary>
	/// <param name="sender"></param>
	/// <param name="e"></param>
	void Form1_LocationChanged(object sender, EventArgs e)
	{
		int last_y = this.Location.Y;

		foreach (Form frm in forms)
		{
			frm.Location = new Point(this.Location.X + this.Size.Width, last_y);
			last_y = frm.Location.Y + frm.Size.Height;
		}
	}

	void timer1_Tick(object sender, EventArgs e)
	{
		this.NextPosition = new Point()
		{
			X = destXY.Next(this.ClientSize.Width),
			Y = destXY.Next(this.ClientSize.Height)
		};

		tween.startTweenEvent(picSatellite, this.NextPosition.X, this.NextPosition.Y, "easeinoutcubic", 100);
	}

	/// <summary>
	/// Implement GlobalInterface.iSatellite property
	/// </summary>
	public Point NextPosition { get; set; }
}

As you can see just below on that code, we implemented iSatellite interface with NextPosition property with a Point type which we're going to use to update the location of the satellite. In the timer1_Tick event, this gets triggered every 3 seconds and you can see, we update the "NextPosition" X and Y values. The 3 projects that is bound in the interface are automatically updated.

So what is the benefit of the Interface in this type of problem about passing values between multiple visual studio projects?

  • Lesser code
  • We do not need to update the values for each project.
  • Easy to manage
  • More structured.

Comparing the usage of Property vs Interface

Let's say each projects PlanetEarth, PlanetMars, and PlanetSaturn are using NextPosition Property

void timer1_Tick(object sender, EventArgs e)
{
	Point newXY = new Point()
	{
		X = destXY.Next(this.ClientSize.Width),
		Y = destXY.Next(this.ClientSize.Height)
	};
	
	this.earth.NextPosition = newXy;
	this.mars.NextPosition = newXy;
	this.saturn.NextPosition = newXy;
}

But when we use Interface

void timer1_Tick(object sender, EventArgs e)
{
	this.NextPosition = new Point()
	{
		X = destXY.Next(this.ClientSize.Width),
		Y = destXY.Next(this.ClientSize.Height)
	};

	tween.startTweenEvent(picSatellite, this.NextPosition.X, this.NextPosition.Y, "easeinoutcubic", 100);
}

We only update the property we implemented from iSatellite and all 3 projects are automatically updated as well.

Hope you learned about another special way of implementing Interface in your projects, not only in Windows Forms, but in Windows Phone, Windows 8, Silverlight, and WPF projects as well.

Here's the a sample project that you can play with.

Click here to expand the blog post

EasyUpdater for .NET 4.0 and higher

EasyUpdater is an application for .NET developers that allows their ,NET projects to have an auto update functionality. Most of our application deployed requires to be updated whenever there are bugs, fixes, and new features. EasyUpdater is a great way to help and easy to implement on your .NET projects.

EasyUpdater features:

  • Can customize the title bar text
  • Can customize the title
  • Can add description below the title
  • Have your own application icon
  • Have your own Terms and Condition text
  • Threaded downloading
  • Able to run an application after the update.
  • Can have periodic check of new update
  • Manually check for update

How to use

First you must understand how the configuration works. It's important to include the EasyUpdater.exe.config file in your projects because EasyUpdater is a stand alone application.

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <!-- generic downloader configuration -->
    
    <!-- the window title bar text -->
    <add key="titlebar_text" value="Your application name"/>
    <!-- the main title -->
    <add key="title_text" value="Your application name/>
    <!-- description located below the main title. 160 characters max -->
    <add key="short_description_text" value="A short description of the application"/>
    <!-- the default png image of your application -->
    <add key="app_icon_png_path" value="appicon.png"/>
    <!-- terms and condition filename that must be located on the same folder where this EasyUpdater is located. Can be left blank -->
    <add key="temrs_and_condition_filename" value="your_license_agreement.txt"/>
    <!-- the link where to download the configuration file -->
    <add key="update_config_link" value="http://www.your_domain.com/app/setup/your_product_version_info.ini"/>
    <!-- base url where the files to be downloaded -->
    <add key="base_url" value="http://www.your_domain.com/app/setup/"/>
    <!-- application to launch once the updater is done updating the files -->
    <add key="file_to_launch" value="YourApplication.exe"/>
    <!-- the application parameter if any -->
    <add key="file_to_launch_parameter" value=""/>
  </appSettings>
</configuration>

How does those configuration reflect EasyUpdater?

here are some infoimage

terms_and_condition_filename is optional. You can left the value blank so EasyUpdater will immediately go to Page 2, or specify a license filename (not fullpath) if you want the show your license in Page 1

update_config_link configuration also needs some formatting. You can copy the template below and change the values.

version=version here. make sure to follow the correct Major.Minor.Bug.Build format
release=release date
files=files to be downloaded and should be separated by comma
details=additional information like release history and features abd
you continue the other details in the next line
like here

e.g.

version=0.1.0.0824
release=08/24/2012
files=File1.exe,File2.dll,File3.dll
details=Initial Release version
- Can customize the title bar text
- Can customize the title
- Can add description below the title
- Have your own application icon
- Have your own Terms and Condition text
- Threaded downloading
- Able to run an application after the update.
- Can have periodic check of new update
- Manually check for update

Watch the video how to properly implement EasyUpdater

Here's the PeriodicUpdateChecker class

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Net;
using System.Windows.Forms;
using System.ComponentModel;
using System.IO;
using System.Diagnostics;

namespace EasyUpdater
{
    public delegate void NewUpdateHandler(object sender, Dictionary<string, string> details);

    public class PeriodicUpdateChecker
    {
        public event NewUpdateHandler NewUpdate;

        Timer tmr;
        WebClient web;
        string _update_config_link = string.Empty;

        int _Interval = Convert.ToInt32(TimeSpan.FromMinutes(30).TotalMilliseconds);
        public int Interval
        {
            get { return this._Interval; }
            set
            {
                this._Interval = value;
                if (tmr != null)
                {
                    tmr.Interval = value;
                }
            }
        }

        public PeriodicUpdateChecker()
        {
            tmr = new Timer()
            {
                Interval = _Interval,
                Enabled = false
            };
            tmr.Tick += new EventHandler(tmr_Tick);

            web = new WebClient();
            web.DownloadProgressChanged += new DownloadProgressChangedEventHandler(web_DownloadProgressChanged);
            web.DownloadFileCompleted += new AsyncCompletedEventHandler(web_DownloadFileCompleted);

            var setting = ConfigurationManager.AppSettings;

            // update configuration link
            if (setting["update_config_link"] != string.Empty && setting["update_config_link"] != null)
            {
                this._update_config_link = setting["update_config_link"];
            }
            else
            {
                this._update_config_link = string.Empty;
            }
        }

        void web_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                Status("Download complete. Checking if there's a new update");
                string local_file = Path.Combine(Application.StartupPath, Path.GetFileName(this._update_config_link));
                if (File.Exists(local_file))
                {
                    string version = string.Empty;
                    string release = string.Empty;
                    string files = string.Empty;
                    string details = string.Empty;

                    using (StreamReader reader = new StreamReader(local_file))
                    {
                        while (reader.EndOfStream == false)
                        {
                            string textline = reader.ReadLine();
                            bool isdetails = true;

                            if (textline.ToLower().IndexOf("version") == 0)
                            {
                                version = textline.Split("=".ToCharArray())[1];
                                isdetails = false;
                            }

                            if (textline.ToLower().IndexOf("release") == 0)
                            {
                                release = textline.Split("=".ToCharArray())[1];
                                isdetails = false;
                            }

                            if (textline.ToLower().IndexOf("files") == 0)
                            {
                                files = textline.Split("=".ToCharArray())[1];
                                isdetails = false;
                            }

                            if (isdetails)
                            {
                                details += textline + "\r\n";
                            }
                        }
                    }

                    if (version != Application.ProductVersion)
                    {
                        if (NewUpdate != null)
                        {
                            Dictionary<string, string> dic_details = new Dictionary<string, string>()
                            {
                                { "version", version },
                                { "release", release },
                                { "files", files },
                                { "details", details }
                            };

                            NewUpdate(new object(), dic_details);
                        }
                    }
                    else
                    {
                        Status("no update");
                    }
                }
            }
            else
            {
                Status("Unable to download the configuration file needed to check the latest versoin.\r\nServer returned: " + e.Error.Message);
                Status("Make sure you set the correct link in 'update_config_link'.");
            }
        }

        void web_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            
        }

        void tmr_Tick(object sender, EventArgs e)
        {
            Status("downloading configuration: " + this._update_config_link);
            web.DownloadFileAsync(
                new Uri(this._update_config_link), 
                Path.Combine(Application.StartupPath, Path.GetFileName(this._update_config_link))
            );
        }

        public void Check()
        {
            tmr_Tick(null, EventArgs.Empty);
        }

        public void Start()
        {
            tmr.Enabled = true;
            Status("periodic update started");
        }

        public void Stop()
        {
            tmr.Enabled = false;
            tmr.Dispose();
            web.Dispose();
        }

        void Status(string text)
        {
            Debug.WriteLine("EasyUpdater> " + text);
        }

        public void RunUpdater()
        {
            Process.Start(new ProcessStartInfo()
            {
                FileName = Path.Combine(Application.StartupPath, "EasyUpdater.exe"),
                UseShellExecute = true
            });

            Application.Exit();
        }
    }
}

I hope you were able to follow the instructions on the video.

Here are the download files including the samples

Click here to expand the blog post

File and Folder ListView Component

May 3rd, 2012, I asked in Stackoverflow.com site about the standard OpenDialogBox and CommonOpenDialogbox from WindowsAPICodePack about the capability of these controls of selecting either File or Folder at the same time when these dialog boxes showed up. The question is truly a stupid one and I received a negative vote due to this dumbest question I have ever asked.

Anyway, same day, I wrote my own, and took a screenshot (above). 

It's actually a component and I used the ListVew as it's base object. One challenge here is to separate the loading of the icons and details of it's associated file/folder, so meaning it should be in a separate thread. using BackgroundWorker object do the trick.

 

Submitted in CodeProject

Click here to expand the blog post

Just a simple Anagram I made

Just a simple Anagram I made for a couple of hours. I found some guys having a problem creating their own so I just tried to see how hard it will since the navigation of letters are in keyboard -no mouse- at all. Lucky I wrote some code before about handling Arrow Keys when you have some button controls on the form.

Anyway, here's the Anagram game. Just 4 letters, words are hard wired. So just download the code below while watching this animation

and download the file here

http://www.mediafire.com/download.php?cor573jeqw0w5tj

Click here to expand the blog post

Session Aware Web Client

I tried looking for some free session aware web clients but I couldn't find a better one so I made my own instead.

/*
 * Session Aware Web Client Library v1.3
 * ---------------
 * Date: 12/17/2010
 * Author: Jayson Ragasa
 * http://wall.jaysonragasa.net
 * License: Common Development and Distribution License (CDDL)
 */

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.Web;

namespace Nullstring.Modules.WFWebClient
{
    public class SessionAwareWebClientLibrary
    {
        #region vars

        string _referer = string.Empty;

        ArrayList _params;
        CookieContainer cookieko = new CookieContainer();
        HttpWebRequest req = null;
        HttpWebResponse resp = null;
        Uri uri = null;

        #endregion

        #region properties
        public string Referer
        {
            get { return _referer; }
            set { _referer = value; }
        }

        bool _list_cookies = false;
        public bool ListCookiesInOutputWindow
        {
            get { return _list_cookies; }
            set { _list_cookies = value; }
        }

        public CookieContainer Cookie
        {
            get { return cookieko; }
            set { cookieko = value; }
        }
        #endregion

        #region constructor
        public SessionAwareWebClientLibrary()
        {
            _params = new ArrayList();
            cookieko = new CookieContainer();
        }
        #endregion

        #region methods
        public void ClearParameter()
        {
            _params.Clear();
        }

        public void AddParameter(string key, string value)
        {
            _params.Add(string.Format("{0}={1}", WebTools.URLEncodeString(key), WebTools.URLEncodeString(value)));
        }

        void SetupWebRequests(string URL)
        {
            uri = new Uri(URL);
            req = (HttpWebRequest)WebRequest.Create(uri);
			
            req.AllowAutoRedirect = true;
            req.KeepAlive = true;
            req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            req.UserAgent = "Mozilla/5.0 (Windows NT 6.1; rv:8.0) Gecko/20100101 Firefox/8.0";
			
			// handle respnose cookie
            req.CookieContainer = cookieko;
			
			// if we made the first request
            if (resp != null)
            {
				// just reuse it
                req.CookieContainer.Add(resp.Cookies);
            }			
			
			// some optional properties
			//req.MaximumAutomaticRedirections = 20;
            //req.Timeout = 300;
            //req.ImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
            //req.UseDefaultCredentials = true;
			//req.Referer = this._referer;
			
			// get rid of 100 service bug
            req.ServicePoint.Expect100Continue = false;
        }

        void BuildPostData()
        {
            string Parameters = String.Join("&", (String[])this._params.ToArray(typeof(string)));

            ASCIIEncoding encoding = new ASCIIEncoding();
            byte[] loginDataBytes = encoding.GetBytes(Parameters);

            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";
            req.ContentLength = loginDataBytes.Length;

            Stream stream = req.GetRequestStream();
            stream.Write(loginDataBytes, 0, loginDataBytes.Length);
            stream.Close();
        }

        StringBuilder GetWebResponse()
        {
            StringBuilder response = new StringBuilder();

            resp = (HttpWebResponse)req.GetResponse();

            Stream resStream = resp.GetResponseStream();

            int bytesReceived = 0;
            string tempString = null;
            int count = 0;
            byte[] buf = new byte[8192];

            do
            {
                count = resStream.Read(buf, 0, buf.Length);

                if (count != 0)
                {
                    bytesReceived += count;
                    tempString = Encoding.UTF8.GetString(buf, 0, count);
                    response.Append(tempString);
                }
            }
            while (count > 0);

            return response;
        }

        public string GetResponse(string URL)
        {
            StringBuilder response = new StringBuilder();

            try
            {
                SetupWebRequests(URL);
                req.Method = "GET";
                response = GetWebResponse();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex);
            }

            if (this._list_cookies)
            {
                ListCookieHeaders(URL);
            }

            return response.ToString();
        }

        public string GetResponse(string URL, bool UsePostData)
        {
            StringBuilder response;

            try
            {
                SetupWebRequests(URL);

                if (UsePostData)
                {
                    BuildPostData();
                }
                else
                {
                    req.Method = "GET";
                }

                response = GetWebResponse();
            }
            catch (Exception ex)
            {
                response = new StringBuilder(string.Empty);
            }

            if (this._list_cookies)
            {
                ListCookieHeaders(URL);
            }

            return response.ToString();
        }

		// test
        void SetCookieContainer(CookieContainer cc, string url)
        {
            IEnumerator ie = cookieko.GetCookies(new Uri(url)).GetEnumerator();
            while (ie.MoveNext())
            {
                string[] cookie = ie.Current.ToString().Split('=');
                cc.Add(new Cookie(cookie[0], cookie[1]));
            }
        }

        void ListCookieHeaders(string url)
        {
            System.Diagnostics.Debug.WriteLine("listing cookies");

            IEnumerator ie = cookieko.GetCookies(new Uri(url)).GetEnumerator();
            while (ie.MoveNext())
            {
                System.Diagnostics.Debug.WriteLine(ie.Current.ToString());
            }

            System.Diagnostics.Debug.WriteLine("listing cookies: done");
        }
        #endregion
    }
}
Click here to expand the blog post

TipidPC or TipidCP Bot Tool

Just a few days ago, I wrote the same application, but as a console application. It went well but what sucks is I cannot hide it everytime it runs because the app is recurrently executing through Task Scheduler. So I decided to port it in Windows Forms so I could have more control.

The application looks like this now

It has some new features:

  • Can check your alerts
  • Can check the last user who commented on your item and notifies you
  • Can post a comment depends on the interval

 

BUT this one is not available to everybody since it's a personal tool. I could consider giving you this one for just Money mouthPhp 1,000.00.

Contact me if you want to buy it Cool

Click here to expand the blog post

Using NotifyIcon Control

This is a very basic implementation of NotifyIcon control in Windows forms.

Some of you might want to add this somehow useful control for your desktop application. I admit it, it's very useful for me too especially when some of apps doesn't really need to be always in Taskbar or an app that monitors something. It really has to stay in my system tray then notify me in case something is interesting going on.

So here's what we want to do. We have a NotifyIcon control and we want Minimize and Hide our form, and double click the notification icon in system tray then show our form in Normal state window mode.

So let's just assume you have your form then double click the NotifyIcon control in Common Control toolbox. NotifiIcon knows what form to handle so what we just want to do now is to set the Icon just like this.

// make the notificaion icon in system tray
// looks like the icon we have in our Form.
notifyIcon1.Icon = this.Icon;
notifyIcon1.Text = "My Notification Icon";

and that just it and you'll have something look like this

 

Now what we want to do now is when we minimize the form, it will hide, show a balloon popup something looks like this

(that should be "BALLOON")

then if we want to show the form again, we're going to double click the notification icon in system tray. Here's how to do it

private void Form1_Load(object sender, EventArgs e)
{
	// make the notificaion icon in system tray
	// looks like the icon we have in our Form.
	notifyIcon1.Icon = this.Icon;
	notifyIcon1.Text = "My Notification Icon";

	// Use Form's Resize event to check for WindowState
	this.Resize += new EventHandler(Form1_Resize);
	// Use NotifyIcon DoubleClick event to whatever we want
	// when we double clicked the notification icon in system tray
	notifyIcon1.DoubleClick += new EventHandler(notifyIcon1_DoubleClick);
}

void Form1_Resize(object sender, EventArgs e)
{
	if (this.WindowState == FormWindowState.Minimized)
	{
		// hide the form
		this.Hide();

		int timeout_before_fading = 2 * 1000; // 2 seconds
		notifyIcon1.ShowBalloonTip(
			timeout_before_fading, 
			"The Balloon Title Goes Here", "Double click to show the window", 
			ToolTipIcon.Info
		);
	}
}

void notifyIcon1_DoubleClick(object sender, EventArgs e)
{
	// show the form
	this.Show();

	// set the WindowState to Normal
	// so it doesn't just stay minimize on the taskbar
	this.WindowState = FormWindowState.Normal;
}

 

Let's go further and let's try adding a Context Menu Strip in our Notification Icon. What you need to do is just to add an Context Menu Strip from Common Control toolbox then add your desired Menu Items and attach to our NotifyIcon control just simple as this.

// add context menu to Notification Icon
notifyIcon1.ContextMenuStrip = contextMenuStrip1;

You don't have to add any codes to show the menu when right clicking on the notification icon because it's automatically wired in. So you'll have something look like this now after right clicking on the notification icon.

 

There are other Events, Methods, and Properties built-in in the NotifyIcon. You can refer to MSDN and play with it.

and that's the end of tutorial for today. I hope you learn something new

Click here to expand the blog post

Html Agility Pack Testbed

Project Description
Html Agility Pack Testbed or HAP Testbed was originally named HTML Live but unfortunately, few people notice the tool so I updated the name and to be more specific.

HAP Testbed features:

  • Built-in web request
  • Live preview on Xpath result
  • Copy / Paste Html Codes
  • Results can viewed as Html code or Rendered using WebBrowser control
  • Can spawn multiple window (Project)
  • Can Return Node result or Node Collection results
  • Can return HTML or Text results

you can download or watch the actual video I recorded when I was doing some xpath tests

Click here to expand the blog post

Tipid PC or CP “up” posting tool called TipidUp

Warning!

This tool is out dated and forgotten. Use it at your own risk.

 

Anyway, I have a simple tool which could post an “up” (or depends on the caption you want) in your Tipid PC or CP items.

tipidup

It does respect spamming so it tries to delete the last “up” caption that was posted and post an “up” caption again.

 

Instructions for Logging in.

I have included a file called APP.CONFIG

Here you can enter your username and password and other options such as the caption you want to post and the item id where you want the application to post an caption and also the tipid host, weather you want the application to post a caption in TipidPC.com or TipidCP.com

so you have:

  • username – where your tipid pc/cp username should be placed
  • password – your tipid pc/cp password. Don’t worry, I don’t steal account because it’s unethical and an professional
  • tipid_host – the application need to know where your items are so the values would be either “http://www.tipidpc.com/” or “http://www.tipidcp.com/” DO NOT FORGET THE BACKSLASH ON THE END
  • iids – could be specific id from your item page or all of your items.
    e.g.
    <add key="iids" value="all"/> – means post to all of your items.
    <add key="iids" value="3400041"/> – post to that specific item only
  • post_caption – it’s up to you what you want to post on your item if “up” or whatever.

 

Now if everything is already setup. You can add the app to run depends on when you like just by adding that in your Windows Scheduler ;)


Download here:

TipidUp.7z (54kb) http://www.mediafire.com/?l7z9glhqf55rrb6

TipidUp.Zip (69kb) http://www.mediafire.com/?67s7vi74ibpz0d8

Click here to expand the blog post

Multi Remote Desktop Client .NET New Release Update 2.0.1122.2011

And so I decided to make this application open source again.

Welcome to Multi Remote Desktop Client .NET Open Source

Check-out now here at CodePlex

http://multirdpc.codeplex.com/

Click here to expand the blog post

About Jayson Ragasa

Jayson Ragasa is an Applications Developer and founder of CAPPLOUD.

Badges

Free Page Rank Tool

wall.jaysonragasa.net Webutation
Uptime Report for http://wall.jaysonragasa.net/: Last 30 days