Robosoft for Beginners


Posted by Cynic | Posted in Online Marketing, OpenCandy, PAD, Robosoft, Software, Solutions to Problems, Super Simple, Web Sites | Posted on 29-09-2012

Software Marketing with Robosoft

For years RoboSoft has been the single most effective 1-stop way to promote software. If it isn’t already a part of your software marketing, it should be. If it is a part of your software marketing, there are most likely areas where you can squeeze quite a bit more juice out of it.

In this article I explain what it is, issues surrounding it, and how to use it to effectively promote your software.

This article is aimed at RoboSoft “beginners”, though there are some good tips for intermediate users as well. For highly advanced usage, you can refer to some of my previous articles on Robosoft here.

What It Is

RoboSoft lets you either automatically or semi-automatically submit your software to hundreds (or thousands) of download sites, news sites, and other software-related sites.

It works by having you enter information about your software, then automatically submitting that information to its large database of sites via web automation. Not all sites can be done automatically, so you can go back and submit to those sites that it “missed”.

For semi-automated submissions, RoboSoft automatically fills in all the forms with your software information, e.g. the product name, download URL, descriptions, etc.

What It Can Do For You

Used properly, RoboSoft can significantly boost your position in search engines, and consequently, increase your sales.

It’s that simple. RoboSoft increases sales. Period.

What It Costs

The cost of RoboSoft is insignificant compared to the value it delivers. A standard lifetime license is $99.00, while database updates are sold on a subscription basis starting at $8 / month. A full year of updates can be purchased for a discount.

About PAD

PAD stands for Portable Application Description. It is the industry standard way to communicate information about software, and is maintained by the Association for Software Professionals (ASP).

PAD files are simple XML files. Each bit of information is contained in a descriptive node. Nodes do not have any attributes.

RoboSoft, and most download sites, use the PAD standard to communicate your software information. You can either create your PAD file inside of RoboSoft, or you can use an external PAD authoring tool like PADGen to create your PAD file then import it into RoboSoft. See below for more information on this.

For more information about PAD, see the official PAD site here.

For more information about PADGen, the official ASP PAD file generator, see the official PADGen page here.

The Download Site Controversy and Why It Doesn’t Matter

Skimming through various developer forums, you will at some point encounter the download site debate, with many authors poo-pooing download sites. Don’t buy it.

The typical “controversy” goes on about how there are thousands of download sites, and how they have no value, and how submitting your software to them is a waste of time.

I beg to differ.

When digging deeper, it usually turns out that somebody submitted their software to a very small handful of sites (maybe 30) once then came to the conclusion that it’s a complete waste of time. Well, duh! That is a waste of time.

Follow the advice below, and you will not waste your time. You will see significant results.

But don’t throw a handful of sand on the beach then claim that you can’t make a sand castle with sand because you tried and it didn’t work.

The “Real Deal”

RoboSoft is an SEO tool.

Let me repeat that just in case…

RoboSoft is an SEO tool.

By submitting your software to a LARGE number of sites, you create backlinks to your site. This boosts your site in search engines even if you never get a single download from any of the sites. Even if you never get a single download directly from a download site (yes, I’m repeating that because it’s important), having your software listed and linked back to your site tells the search engines that the content on that page that links to your site is relevant to your site, and that translates into higher search engine rankings for you. Not all download sites post direct links to you, but they do post links to your software installer, which still translates into a link that search engines can follow.

So, your goal isn’t to get downloads from download sites. Your goal is to get better search engine placement, because the new download site is Google.

That means that you need to do some SEO work on your PAD file… Which is beyond the scope of this article. There’s lots of information available on SEO out there, and you can find an excellent article about on-page SEO here. Many of the same principles apply. Don’t worry about download sites out-ranking you. That may happen, but eventually it gets corrected.

In the past, I’ve had up to 95 out of the top 100 results in Google pointing to products that I was promoting, albeit 94 were on download sites. Still, that’s only room for 5 competitors inside of the top 100 results. Those days are done and gone though, but the tactics used still work to get your site up in the SERPs and are still very much worthwhile.

Entering Software Information

As space is short, we’ll forgoe the PAD SEO discussion, and get on to the simple mechanics of entering information…

If you have a PAD file, click “Import…” under “Company tasks” in RoboSoft to import your company information from your PAD file:

Import PAD info for Company

Follow the instructions and click the “Save and exit” button when you’re done:

Importing company info from PAD - save here

That will create your company info inside of RoboSoft. You will see your company info listed similar to as shown below:

Company is now listed in RoboSoft

Next, select your company as shown above, and do the same for your product information by clicking “Import…” under “Product tasks”:

Import product info from PAD

You may be prompted with the company info screen again; click the “Save and exit” button again to continue on to the product import screen:

Product import screen for RoboSoft

You can edit information in there, just as with the company import screen. However, make certain to click the “Save and exit” button to save your product into RoboSoft.

When prompted, make your imported product the selected/active one by clicking Yes:

Make product active

RoboSoft will now look something like this:

Product has been imported into RoboSoft

Before you submit, you must ensure that there are no errors. In the screenshot above, click the “Validate now” link, or in the Product tasks, click the “Validate…” link. This will check your software information for problems:

Validation errors

Walk through each error and correct them all. This may require uploading files, such as your PAD file, to your server and making certain that the information in RoboSoft accurately reflects the newly uploaded files.

You can resize the screen above to go about fixing the errors. If this is the first time you’ve used RoboSoft, you WILL have errors that must be corrected. This is perfectly normal as some fields are RoboSoft specific.

Correcting validation errors in RoboSoft

To correct the errors, click on the error then in the left pane, correct the error. Rinse. Repeat.

Correcting validation errors

!!! IMPORTANT !!! — For your contact and login information, do NOT use your normal email address, i.e. DO NOT use support@ or info@ or yourname@. Use addresses that are used ONLY for submissions. Use email addresses like pad@ or padsupport@ or padsubmit@. Your PAD submissions will generate a lot of email that is only relevant for your PAD submissions. You will also get automated PAD polling information from download sites to tell you that they’ve polled your software and that it has been added/listed or that there was a polling error (which is often because the download site PAD validation is not PAD compliant). So… To avoid filling up your inbox with all that, use another email address. Really. Trust me. I speak from experience. Lots of it.

When you’re done, click the “Save and exit” button.

!!! IMPORTANT !!! — Critical errors must be fixed, however, you can ignore some warnings. Try to fix everything that “makes sense” for your software, but don’t worry if something that is irrelevant to your software still throws a warning, e.g. Your PAD file may not have a press release in it, so you will get warnings there. (Press releases can be added through the press release PAD extension. See here for more information about PAD extensions and here for the PAD extensions repository.)

Before you continue, back in the main RoboSoft screen, double-click your newly imported software to edit it. Walk through each and every field and verify that it has been entered (if required), and is correct. There is a description of each field at the bottom of the screen when you click each field.

Enter or edit information directly in RoboSoft

That should take you several hours (or days) if you do it properly. Why? Because you should have a press release, and you should have site information, and it takes several hours at a minimum to write a draft-quality press release. Don’t overlook that. Remember, this is about SEO, and the more you submit, the better you will perform in the search engines. Take the time to do it properly. Don’t be lazy.

If you don’t have a PAD file, you can simply create a new company and product and enter the information exactly the same as in the screenshot above.

So… by this point you have taken the time to do things right, right? Good! It’s time to submit your software and open the floodgates of traffic!

Submitting Your Software

Before you start submitting, make sure that the database is up to date by clicking Site List > Update. Follow the directions.

Filter Sites That You Submit to

If you have an Excel utility, there is no point in submitting to games sites, and if you have a non-mobile game, there’s no point in submitting to mobile sites… So… Filter them.

Click the Sites tab. It should look something like this:

RoboSoft Sites tab

Click the “Site Rank” column header to sort by site rank. The ones at the top are the most important ones. You will want to do those sites semi-automatically, and not automatically.

In the lower right, check “Use filter” to enable the options there.

Filter the sites you submit to

For Category, uncheck any category that isn’t relevant. e.g. It’s unlikely that you’re a CAD developer, and more likely that your software may fit into the Multimedia category. Be honest. Checking them all is counter productive. If you don’t have a screensaver, don’t submit your software to screensaver sites. You will want to submit to news feed directories, search engines, press release sites, and web directories though.

For Language, you can submit to all of them. You don’t need to uncheck anything. Some non-English sites accept English software, while other non-English sites don’t. Cross that bridge when you get to it. However, if you want, you can check only one language and do your submissions by language, i.e. do multiple sets of submissions. That’s a solid tactic that can help you focus on specific language markets. It may or may not be applicable to you though.

The Flags options let you hide entire categories of sites. For example, some sites require that you pay to be listed, while other sites require that you link back to them. Show or hide the sites that you want to submit to.

HINT: For sites that require a link back, most of these will crawl your site to see if the link is on the home page, and if not, they will decline your submission. A small minority of sites will accept any page, even if it is not linked to anything in your site. I would recommend not bothering with these sites at all. You don’t want to link to them as it does not add enough value to your efforts to warrant it.

I would recommend hiding all sites that require payment or a link back.

For Status, leave that at ALL for the time being. Later on you will want to know where you have submitted, where you are listed, and where submissions failed or were skipped. Before you actually use those functions though, you should use the RoboSoft crawler to update the status by clicking Tools > Track Listings (Batch Search).

When you’ve finished filtering, click the “Apply” button. The status bar in the lower left will update to display something like this:

Filter results

You have now chosen the subset of sites that you will submit to. It’s time to get started…

Starting Submissions

To start submitting, click the “Auto…” button on the RoboSoft toolbar (or click Tools > Automatic submission…) and choose “Submit”:

Click autosubmit to start

RoboSoft will update the database:

Updating database

Once the database is updated, you must complete the automatic submission wizard:

Automatic submission wizard

Next, verify you have the right product that you want to submit:

step 2

RoboSoft then validates your software info:

PAD validation

Next, verify and test your SMTP settings as some submissions are done by email, and others require an account that RoboSoft can automatically create for you:

SMTP settings

Next, verify your site selections:

Verify site selections

Next, RoboSoft will check to see if your software is already listed:


In step 7, check or uncheck individual sites that you want to submit (or not submit) to. To change a category, press CTRL + click the category. If you need more categories to be available to choose from, click the “Edit possible categories” button and follow the direction in the dialog there. A green check mark means that the software is already listed at the site. Check these sites if you have an updated version. Also, make certain to check the account information in the Account tab on the right. If you don’t know what something is, mouse over the question marks (?) for more information.

Category and site selection

It is important to make sure that you get things right in step 7. Take a few minutes to go through the list and verify that everything is correct. Uncheck irrelevant sites and correct any category problems. Not all sites support all categories, so just try to get as close as possible. If you can’t get close, uncheck the site because it’s a waste of your time and a waste of the site owner’s time if your software isn’t relevant. e.g. You have a photo resizing application and the site is for network administration software.

In step 8, RoboSoft does all the submissions. Take special note that it has anti-CAPTCHA built in as you can see in the screenshot:


The various panes in the submission window detail what sites are being submitted to, show a screenshot of the submission process, give real-time statistics on the submission process, and show CAPTCHAs being cracked.

The anti-CAPTCHA feature in RoboSoft is highly effective, but not 100% of the time. At the end of the submission process, you are given the option to go back and process those CAPTCHAs that RoboSoft missed:

Process CAPTCHAs

It’s a very simple and easy process, so just click the “Process CAPTCHAs” button.


Click in the Value column and type the CAPTCHA. You can see a screenshot of the actual web site in the lower right.

If you get one wrong, you’ll be promted again. Some CAPTCHAs are very difficult, while some sites are just broken. If you can’t get one, forget about it. The chances are that the site itself is broken.

Step 9 is the “YAY~!” stage:

Success rates for software submissions

RoboSoft keeps track of all the submissions for you, including success and failure rates. Don’t worry about failures though. It’s common for a site to go down, or for a site to have internal errors, especially when you submit to hundreds and hundreds of them. RoboSoft also keeps track of why there were errors, as you can see in the screenshot above. Just make certain that you aren’t the source of the errors through some silly oversight like bad account information.

Step 10… Hmmm… Step 10… How about I let my sadistic side take over. You know… Slide on over to the Dark Side… and leave step 10 as a mystery by not telling you what it is and not posting a screenshot. Muahahahaha~! You’re tortured now, aren’t you? It’s eating you up inside, gnawing at your very soul… You must know what step 10 is… And so… You must go out and get RoboSoft and do your own submissions to find out! (You’ll be very glad that you did.)

But You’re Not Finished Yet…

That’s just the automatic part. There’s still the manual part.

Go to the Sites tab and double-click on a site that you’ve not submitted to (or one that you want to resubmit to). That will open up the site on the Browser tab. There, click the “Submit” button and carry on your submissions semi-automatically. Each site is different, so you’ll need to just roll with it. However, many sites run off of the same download site engines, and after a while, you’ll begin to recognize them. That makes submissions faster for you as you’ll know what to expect within a few seconds of visiting a site.

The important things to know are:

  • RoboSoft will automatically fill in fields for you.
  • You can use the “Autofill” button to fill in fields if RoboSoft doesn’t.
  • You can right-click in an input and choose what information to enter from the context menu.
  • This is a very important part of submissions, and if you skip is, well, you might as well throw a handful of sand on the beach and then complain about not being able to build a sand castle.

If you are diligent and aggressive, the entire submission process should take you about 2 or 3 days. That assumes some learning curve. Once you know what you are doing better, submissions are much faster; plan on a set of submissions taking a day to complete. The manual/semi-automatic portion takes the longest, as you would expect.

Again, it bears repeating: Do not skip the semi-automatic submission process. It is critical to your success. There are some very good download sites that you’ve likely never heard of, and if you skip them, you are missing out on some valuable exposure. See my praise for Softoxi here.

After You Finish Submitting…

The process doesn’t end with submissions though. RoboSoft can keep track of what sites your software is listed at, so you should periodically go back and run the batch search: Tools > Track Listings (Batch Search).

You can add in new versions, submit, and keep track of it all.


DynamicPAD is how you can turn RoboSoft from a raging 800 lb gorilla, into a fire-breathing, 800-foot high, Tokyo-smashing Godzilla. (BTW – Your competition is Toyko.)

However, DynamicPAD is well beyond the beginner or intermediate scope of this article. If you want more information about turbo-charging RoboSoft with DynamicPAD, see my articles on that here (part 1, 2, 3, 4). It’s not for the faint-of-heart, but if you really want to get some fantastic results, try it out. The articles include source code that you can use as well.


This article has been sitting around for almost a year, but is still as accurate as the day it was written. Originally, it was written for another company, but, they simply sat on it for too long, so, I’m publishing it. I know it will be useful for someone.




The Licensing Experience with Infralution and DotNetNuke


Posted by Cynic | Posted in .NET, C#, Databases, DotNetNuke, Online Marketing, Software, Solutions to Problems, Super Simple, Web Sites | Posted on 20-09-2011

Tags: ,

I don’t think that I’ve ever done a licensing or purchasing flow exactly the same way twice. Well, a couple times, but mostly I experiment with both major changes and minor tweaks.

This time around for the Super Simple Photo Resizer Social Edition, I’m doing things more or less right. There are a few things that still could be improved, and a few things that I’m not really all that happy with, but like my friend Nick Longo says, “Release at 80%.”

However, overall, I think the current functional set that I’ve got mapped out for Photo Resizer Social Edition are pretty good, and will deliver a solid user experience. My goals on the user-experience side are:

  1. Make it easy to purchase
  2. Make it easy to get and enter the license
  3. Make it easy to get a lost license back

Each of those has a real upside for users, and an upside for me as well (respectively):

  1. I make more money
  2. Fewer support emails
  3. Fewer support emails

But I also have some other goals.

  1. Cut down on piracy
  2. Cut down on piracy
  3. Cut down on piracy

For a little guy like me, piracy hurts. Badly. It also hurts users, because it removes the financial incentive to continue development. You’d be surprised at just how many people like to get paid for their work, and how much they enjoy having food on the table and paying their bills. 😉

I recently got an email from someone who purchased some other software that I write. This is part of that email:

I could have pirated the software if I wished as it is easy to crack which is something you need to work on, but I thought the software is so good that I would pay you the money for a genuine copy and support its future development.

I’m glad he bought a copy! It quite literally puts food on the table.

However, I don’t want to get into piracy here. Instead, I’d like to go over some of the things I’m doing with the new licensing scheme…

The flow looks something like this (click to zoom):

Super Simple Photo Resizer Social Edition Licensing Flow
Now, I’m leaving out a lot there because it would just be boring details, but that’s the basic flow.

The user gets 2 emails:

  1. PayPal receipt
  2. License email with account information

Now, in the past I’ve done licensing manually, which has been in many ways pretty easy, but it’s not been without its pain as well.

I’ve previously mentioned that I’m using the Infralution toolchain for licensing, but nothing is perfect “out of the box”, so I’ve done a good amount of customization. Having been burnt very badly in the past, I tend to purchase source code licenses whenever I can afford to. This leaves me the freedom to get down into things and tweak, fix, or just pimp-out stuff. Infralution offers source code along with their various products, which is another reason why I strongly recommend them to people whenever the topic of software licensing or payment integration arises.

I’ve also raved about how much I love DotNetNuke. It’s a fantastic CMS/portal written in ASP.NET (VB.NET in the past and now in C#), and comes with a BSDish license. However, I’ve been hesitant in the past to do much integration due to time constraints and other factors. However, this time around, I’m aiming to get things done more or less “right”.

Neither the Infralution ILS nor their IPN.NET integrate into DotNetNuke, so all of that is goodness that I need to take care of. Luckily, DotNetNuke is very well designed and integration isn’t really much of a problem. It’s really only a matter of getting it done and testing things out to make sure that they work. The trick is to try and make certain that I don’t step outside of the framework, and don’t create potential future issues for when I upgrade the DNN version. (Moving from DNN v2.1.2 to v3.x was a NIGHTMARE.)

ILS and IPN.NET take care of all the license generation and authentication, so the only thing needed is to get that into DNN. The relevant user-portion of the database is (click to zoom):

DotNetNuke Users Roles Database DiagramTo get ILS and IPN.NET working there, I needed to create 2 new entries in the database:

  • A Role for licensees
  • A ProfileProperty to store licenses

No new tables needed to be added, and no table modifications were needed. So, everything fits into DNN nice and cleanly.

A Note About the Database: When installing DNN, I would highly recommend using object qualifiers. These are prefixes for the database objects (tables, stored procedures, views), and will help to guarantee that well written modules that use them do not have conflicts. IPN.NET and ILS do not support object qualifiers, and have table names that could be used by other modules. As such, I’m very happy that I always stick with the wisdom of using object qualifiers because it’s made things much safer, and has allowed me the freedom to use the DNN database for the IPN.NET and ILS Authentication Server. Later on, this will let me create custom modules or do additional programming that let me access all user data in 1 place. The advantages here are never-ending.

When a user purchases a license through PayPal, PayPal then securely contacts my IPN.NET instance, and I then process the transaction by either updating the user’s existing profile, or creating a new user profile for the user and updating it with their new license information.

Since IPN.NET has no DNN integration, everything needs to work around that, and consequently, needs to be done at a low-level. Luckily, the DNN community is quite large, and there’s a lot of code out there to help with very low-level stuff like this.

The first step to integration is to create a user, and there’s some existing code out there that helped me get jump started:

Creating a DotNetNuke User via SQL

So starting from there, I’ve got a new account for the user and it has their license securely stored.

Next, there’s a password problem there… I certainly don’t want to use a known password, so that needs to change. Again, thanks to the DNN community, I’ve got the solution:

Updating a DotNetNuke User Password via SQL

However, what password do I create? What I wanted to do initially was to create a pass phrase instead of a password. However, being the grammar-Nazi that I am, and being constitutionally incapable of generating icky passphrases, I realized after some investigation that any decent passphrase generator would take me far longer than I was prepared to spend. So… Thank you again to the .NET community, I have a ready-made password generator that creates strong passwords of an arbitrary length:

Strong Passwords in C#

So that problem is also solved, in more detail that I’d care to bother with too! It creates passwords that look like these:

  • a+7P9A*rp6F&
  • So5={9WsM+g7
  • Ax8$+3JwD=a2
  • Ky8-i?H6Dw3&9%sS$rX54Q!f{2eLPp_7

The nice things about that password generator are that it

  • Leaves out ambiguous characters, e.g. I vs. | vs. l vs. 1 or 0 vs. o vs. O
  • Lets you choose the length of the password
  • Mixes in upper and lower case letters, numbers, and symbols

As far as being able to remember them? Bah! Not going to happen. Which is why I wanted to have a pass phrase generator, but, you do what you can with the time you have.

Now, code-wise, there are a few points where things need to get done:

  1. MS SQL Server stored procedures
  2. The IPN.NET project
    1. Default.aspx.cs
    2. Add in the RandomPassword.cs class
    3. Add in the “DnnLicenseIssuer.cs” class
    4. Modify the “Keys.htm” file

The MS SQL Server stored procedures won’t have any impact on DNN if done right. The prerequisite PropertyDefinitions and Roles need to be there, but that’s simple enough.

The RandomPassword.cs and DnnLicenseIssuer.cs classes won’t have any impact on the IPN.NET installation, so there’s a lot of freedom there.

However, changes to the Default.aspx.cs file will break across IPN.NET upgrades unless care is taken to migrate those changes to any new IPN.NET version. Luckily, everything that needs to be done can be done in this method:

private void ProcessPurchaseItem(PurchaseItem item, int quantity)

However, if you’ve actually sold a license, and the payment is successful, there’s only 1 spot that you need to modify, which will look something like this:

DnnLicenseIssuer dnnLi = new DnnLicenseIssuer(ipn, item, keys, false);
if (dnnLi.HasExistingAccount)
// Do stuff for license email
// Do stuff for license email

So you can easily minimize the impact there and make future upgrades very easily.

The “Do stuff” part contains customizations that I’ve written for the license email. If users have an existing account, then they get a different email than users that I’ve created an account for.

Of course it is possible to go further, and create users irrespective of whether the license payment succeeded or failed, and follow up later, however, it’s not one of my requirements at the moment.

The End Game

There’s a plan behind all this though. I’m not going to spill the beans quite yet, and it won’t get done for some time yet. However, all of this has a forward-looking purpose, and when I finally make it to that stage, I’ll post back on what I’m doing and the results.

Until then, check back at Super Simple over the next few weeks as the new Photo Resizer Social Edition is coming out very soon.



Creating Urgency for Sales with Infralution Licensing System


Posted by Cynic | Posted in .NET, Business, C#, Databases, Money, Online Marketing, Software, Solutions to Problems, Super Simple | Posted on 15-09-2011

Tags: ,

I need to create a large number of “products” for Photo Resizer, but they’re really all just the same product with different prices. And not 2 or 3 prices, but more like 20 or 30 prices. Actually, I’ll likely end up creating more than 30, but that’s a detail.

It may seem strange to some people as to why I would do this. I’ve had people tell me to just set one price and be done with it. Well, that’s all fine and dandy, but it also shows a lack of understanding about how to sell software. Just because you’re a rock star coder, doesn’t mean you’re a rock star marketer.

So, what I’m going to cover now are some motivations and reasons for the problem, and how I’m solving it. There are of course other ways to create problems, and other ways to solve them too. 🙂

  • Urgency and creating urgency
  • The Infralution Licensing System and License Tracker
  • The Code: Creating massive numbers of products for the License Tracker database

Urgency and Creating Urgency

When you’re selling, you sometimes need to create a sense of urgency for people to BUY NOW! Not later. Not tomorrow. NOW! Stores do with with 1-day sales, or “on sale until <date>”. The same sort of thing can be done for software. You just tell people that there’s a deal to be had RIGHT NOW, and that if they don’t buy your product RIGHT NOW, then they’re going to miss out.

What happens when you do this is that you effectively remove a barrier to purchase for the customer. They have 1 less reason to “not buy”, and 1 more reason to buy. The more things you can do like this, the better. Typical things include telling potential customers how your product will benefit them and make their lives better, or offer free shipping, or… You get the point.

The way in which I am creating urgency is with an initial steep discount for the product that decreases; that is, the price increases over the course of the trial period. e.g. Today it’s $5 and tomorrow it’s $6, and the day after that… So… BUY NOW and SAVE~! I’ve done it before, and it works.

The Infralution Licensing System and License Tracker

There are lots of ways to license your software, but the one I like is from Infralution. The Infralution Licensing System, or ILS, integrates with their IPN.NET product as well, so it gives me a way to license the software and collect money for it; those are 2 very different things and should not be confused.

ILS includes a program to help keep track of licenses and customers called License Tracker, which up until now I’ve never used. Since I’m looking to automate as much as possible at this stage, I’m moving things over to it now.

License Tracker stores data in a database; I’m using MS SQL Server for that. To add a new product, you simply open up a new form and enter all the data then click OK. Sounds simple enough? Well… Not when you want to add in a truck load of products; it is extremely tedious and painful. I don’t want to copy and paste 500 million times, and I don’t want to change my mind later on and end up copying and pasting another 500 million times.

Since License Tracker is a database-connected application, all data in it is just the data in MS SQL Server. This makes it easy to deal with your data because you can simply connect to the database and do whatever you feel like. As such, I wrote a utility to generate SQL for products, or rather, for product variants, though it could also be used to create top level primary products as well.

My simple “SQL Generator for the Infralution Licensing System License Tracker ” (that’s a mouthful) lets you enter data for a product and generate product variants very quickly. It even lets you increase product costs by a set increment, and lets you auto-increment IPN item numbers. Here’s a screenshot of it (click to zoom):

SQL Generator for the Infralution Licensing System License TrackerIt’s pretty basic, but it saves product information and settings automatically so that you don’t need to enter everything the next time.

You simply fill in the form and click the “Generate SQL” button. The SQL is then appended to the Generated SQL text box at the bottom of the form. You can automate part of it with the Automatic Increments settings, or quickly change the price manually and click the Generate SQL button again. It’s MUCH faster than copying and pasting for every field.

Now, you do need to know what you are doing, and the “Parent Product ID” needs to be the primary key for the product’s parent in SQL Server, so this isn’t a utility for just anyone to use. However, if you use the Infralution Licensing System and License Tracker, you’ll already be familiar with everything in there, and you won’t have any problems in using it.

Once you have your SQL, you can simply review it to see that it’s what you want and run it in MS SQL Server Management Studio, or whatever you use to execute SQL against MS SQL Server.

After you run your SQL, simply open up License Tracker and all your products will be there.

The Code: Creating Massive Numbers of Products for the License Tracker Database

To make things easier, I’m including the full source code for download here. Please note that I’ve chosen for it to be licensed under the WTFPL 2.0, so you have maximum freedom to “Do What The F*** You Want To”. If you don’t like that license, then feel free to send me lots of money and I’ll give you another license. 😉

Download Source Code for SQL Generator for the Infralution Licensing System License Tracker

The download includes all source code and a debug build that you can run immediately.

The code is commented extensively, so you can consider that the “documentation”. If you have any questions, which I rather doubt anyone will, you can post a reply here. (Also email me to let me know to respond. You can email me through the contact page at

I hope that helps someone out.



Dynamic Help Topics in C#


Posted by Cynic | Posted in C#, Software, Super Simple | Posted on 01-08-2011

I’ve got a situation where I want to use a keyboard shortcut for a specific help topic: Keyboard Shortcuts. Oh, the irony… So I fart around trying to bang things into shape, but it’s really just not taking very well as help is really setup to use with controls, and not really setup to use dynamically/programmatically.

However, with a little hacking around, it’s not very difficult.

The following shows how to use a HelpProvider to dynamically choose a help topic without using a control. You need a Windows Form with a HelpProvider and a CHM file. You must know the CHM file and must use the proper keywords from it. In this case, the keywords is “Keyboard_Shortcuts.htm”. Note that it is NOT “Keyboard Shortcuts” or some other variation.

Here’s how to display a specific help topic from a keyboard shortcut in the KeyDown event handler:

case Keys.K:
    // do shortcuts here

    helpProvider1.SetHelpNavigator(this, HelpNavigator.Topic);
    helpProvider1.SetHelpKeyword(this, "Keyboard_Shortcuts.htm");
    helpProvider1.SetHelpNavigator(this, HelpNavigator.TableOfContents);


The things to watch there are that you:

  • Use the form for the help control (this),
  • Use “*.htm” for the keyword,
  • Set focus to your form (just in case),
  • Use the SendWait method to give the application time to respond to the key event, and
  • Reset the help back to the table of contents afterwards so that subsequent help requests don’t end up at the keyboard shortcuts (or whatever you use)

The last 2 there are the most important. If you don’t use the SendWait method, the following line where you reset the help provider will run before the key event has time to execute.

It’s very straight forward, but there are a few things to watch there.

I hope that saves someone a bit of time.



Photo Resizer Hits #12 in Google


Posted by Cynic | Posted in Internet, Online Marketing, Robosoft, Super Simple | Posted on 23-07-2011

Well, I’ve not done anything since last posting about this (or before), but the Super Simple Photo Resizer has edged up a bit from #15 to #12 in Google. Just a little bit more and it will be in the top 10!

That’s a bit more vindication for my assertions that Robosoft really and truly rocks! Yay~! Now, for the nay-sayers…. Nyah nyah nyah nyah nyah~! =P

So, I’ve got a bit of work to do still for Photo Resizer, but unfortunately it’s been delayed by a short gig doing some contracting, and about to be delayed again by a larger project that I’m about to start and a proposal for another small gig.

However, here’s a quick preview of what you can expect in the next version:

  • Crop photos
  • Upload resized and cropped photos to various social networking services:
    • Facebook
    • Flickr
    • TwitPic / Twitter

It’s all actually finished, however, I still have the long process of “polish” to do. I’ll be streamlining things and working on making the user-experience (UX) as smooth and easy as possible. It’s supposed to be super simple, so it won’t get released until I’m happy that it meets a certain standard there. It won’t be perfect because nothing is, but it will most certainly be above average.




Logging Out of Facebook with C# SDK


Posted by Cynic | Posted in .NET, C#, Software, Solutions to Problems, Super Simple | Posted on 22-06-2011


FacebookLogging out of Facebook programmatically turns out to be much more problematic that you would think.

I posted the question at StackOverflow asking if anyone knew of a way to get it done. The only answer, other than mine, turned up the same results I’d been having, i.e. You just can’t logout easily.

So, I was forced to resort to nasty, dirty, hacky, ugly measures to get the job done. Using the FacebookOAuthClient.GetLogoutUrl() method didn’t work. I tried and tried and tried. I manually constructed URLs in many different combinations and permutations, and nothing worked.

The problem, as it turns out, isn’t limited to C# though, as many other developers using different SDKs and languages have had similar problems.

The general answer seems to be to use the Facebook JavaScript SDK. Huh? Well, when you’re not developing a web page, it’s kind of tough to use that SDK, and any attempt would be pretty hacky and ugly and time consuming. And then again, there’s no guarantee that it would work either.

As such, I resorted to browser automation… Ick. Yucky. It’s prone to breakage and just all-round icky. So, here’s the basics on how I am logging out of Facebook…

private void wbrFacebookAuth_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
   if (_logout)
    HtmlElementCollection hec = wbrFacebookAuth.Document.GetElementsByTagName("a");
    foreach (HtmlElement elem in hec)
        // the logout link has a data-sigil="logout" attribute:
        string datasigil = elem.GetAttribute("data-sigil").ToLower();
        if (datasigil == "logout")

The code finds all the links in the page, then iterates through them to find the logout link, and then navigates to it. It works. But that’s all I can say about it.

It’s really rather unfortunate as the Facebook API documentation is simply some of the poorest I’ve ever seen. There are many comments from developers in every section of the documentation asking for better docs as the documentation available right now doesn’t answer much of anything.

They don’t have any low-level documentation that would allow you to simply look up an issue, then create a solution for it. If there were, I would have been able to quickly write something that wasn’t a horrendous hack like the abomination above.

I suppose that in some ways I’ve simply got more of a desktop/server mentality now, and just don’t have that hoodoo magic needed to divine WTF comes next in the web world.

Maybe I should head out to see if I can buy some chickens to sacrifice… Maybe that will help…

But for now, the Facebook functionality in the Super Simple Photo Resizer is working.



Getting the Album ID with the Facebook C# SDK


Posted by Cynic | Posted in .NET, Alcohol, C#, Software, Solutions to Problems, Super Simple | Posted on 09-06-2011

Tags: ,

I really shouldn’t drink & post like last night… Anyways, cynicism and rantiness wane as sobriety returns, and here’s some code that illustrates uploading a photo to a specific album:

// This is directly out of the Facebook C# SDK sample code (FacebookInfoDialog.cs)
private void btnPostPicture_Click(object sender, EventArgs e)
    var ofd = new OpenFileDialog
                      Filter = "JPEG Files|*.jpg",
                      Title = "Select picture to upload"
    if (ofd.ShowDialog() == DialogResult.OK)
        var picture = File.ReadAllBytes(ofd.FileName);

        var fb = new FacebookClient(_accessToken);

        fb.PostCompleted +=
            (o, args) =>
                if (args.Error == null)
                    FacebookClient tmpClient = (FacebookClient)o;
                    JsonObject jo = (JsonObject)args.GetResultData();


                    MessageBox.Show("Picture posted to wall successfully.");

        dynamic parameters = new ExpandoObject();
        parameters.caption = txtMessage.Text;
        parameters.method = "";
        // See below for how to get the album ID value:
        parameters.aid = "123456"; // <== This is the album ID.

        var mediaObject = new FacebookMediaObject
                                  FileName = Path.GetFileName(ofd.FileName),
                                  ContentType = "image/jpeg"
        parameters.source = mediaObject;


// This shows a quick & dirty way to get the album ID:

dynamic jobj = arraySerializer.Deserialize(json, typeof(object));
int counter = 0;
Dictionary<string, string> albums = new Dictionary<string, string>();
// This loop is a sin, but don't get side-tracked.
while (true)
        // The link to the album has it's ID:
        string link = Convert.ToString([counter].link);
        // Convert that to a URI:
        Uri url = new Uri(link);
        // Get the query string:
        string query = url.Query;
        // Put the query string into a quick & easy collection:
        NameValueCollection nvc = HttpUtility.ParseQueryString(query);
        // Extract the album ID using the literal variable name, "aid":
        string aid = nvc["aid"]; // <== The correct album ID.
        // Add the album ID (aid) and the album name to a dictionary:
        // If you were to do this, you wouldn't have an album ID that you can use
        // because the "id" in the JSON doesn't return the album:
        // albums.Add([counter].id,[counter].name);

It’s not hard at all. But the lack of decent documentation makes it painful at best.

I’ve been harping on this for a long time: In software components, the real product isn’t *just* the component… It’s the documentation.  The best software in the world is no better than the worst if you can’t use it effectively. That’s what documentation is for.

I hope that helps save someone some time.



Where People Use Photo Resizer – Korea #1


Posted by Cynic | Posted in Business, OpenCandy, Super Simple | Posted on 18-05-2011


It looks like I have quite a few users in South Korea for Super Simple Photo Resizer.

Super Simple Photo Resizer, Apr 1st 2011 – May 17th 2011

1. Korea, Republic of
2. United States
3. India
4. Germany
5. Taiwan, Province of China
6. Indonesia
7. United Kingdom
8. Australia
9. Canada
10. Mexico
11. Other

Where people are using Photo Resizer

The big slice there represents the rest of the word, which is larger, but still, Korea and the US account for the top 2 with India very close behind the US. (Statistics and graphic are thanks to the OpenCandy control panel. It includes initiated and completed installations.)

I rather like that as I have a very special place in my heart for Korea. (I lived there for almost 14 years.)

I don’t think I should be too surprised though. Having lived in Korea for so long, I’ve adopted quite a few Korean attitudes, and, looking back at things, Photo Resizer really is a reflection of that. It is designed to get a job done, and to do it well, without bogging you down with meaningless details. So I can see why Korean users would be attracted to it. They’re some of the most tech-savvy people in the world, which only adds to my pleasant surprise at seeing them as my #1 users!

The only unfortunate thing is that revenue for South Korea is very low:

1. United States
2. Germany
3. United Kingdom
4. Australia
5. Spain
6. Netherlands
7. Canada
8. Switzerland
9. Korea, Republic of
10. France
11. Other

Photo Resizer revenue

As you can see, revenue from the US takes up a very large portion of total revenue, and well over 50%.

I suppose OpenCandy just needs some good Korean advertisers! 🙂




A Kick-Ass Article on Asynchronous Operations


Posted by Cynic | Posted in .NET, C#, Software, Super Simple | Posted on 01-05-2011

Tags: ,

Oh No! - Warning smiley used in asynchronous operationsAs I am virtually incapable of doing anything the same way twice, I had to go out and find another way to deal with blocking operations (blocking as in network blocking), and came across Asynchronous Method Invocation at the Code Project. Perfect. The author, Mike Peretz, does an excellent job of explaining Begin/EndInvoke, delegates, catching errors, and the Command Pattern. Even if you’re fine with asynchronous operations, invocations, and delegates, it’s a good read.

The reason I wanted a new way is because I’ve been adding some new features to my Super Simple Photo Resizer: cropping and uploading photos to TwitPic and then tweeting them on Twitter. I’ve been having a lot of fun with it, and you can check out some of my testing pictures of a cute possum here.

Photo Resizer is very quick in resizing and cropping photos, so there really isn’t any need to bother with dealing with saving asynchronously. However, the new upload features and tweeting features take more than the blink of an eye, and they require asynchronicity to maintain a nice, fluid user experience. I had a bit of fun with it too. In a “cancel” warning screen, instead of a regular, boring yellow triangle and exclamation mark warning/caution symbol, I used the “Oh no!” smiley you can see in the upper right here. Again, that was one of the graphics I purchased at Vector Stock.

I opted to run with Begin/EndInvoke and delegate callbacks this time around. It works well, and the UI remains smooth and easy to use.

However, the Command Pattern really looked a lot better. But there was just so much good stuff in the article that I decided to just put it to memory and save the Command Pattern for another day. So next time, rather than look around to figure out a new way to do the same old thing, I’ll already have something new to try.


Passing Information Between Winforms the Sneaky Way


Posted by Cynic | Posted in C#, Software, Solutions to Problems, Super Simple | Posted on 29-04-2011

There are many ways to pass data between form in .NET. This article, Passing Data Between Forms, at the Code Project is an excellent one that shows 4 ways to do it. My favorite way to do it is with delegates and events.

However, very often you simply need a quick and dirty solution where you open up a quick data entry form and get the data back. Using delegates and events is overkill.

Well, I needed to do it yet once again for some software for Super Simple, and while looking at some past code of mine, I thought, “Wow! Man, that’s sneaky!” So, here I’ll explain a quick and dirty little way to get some fast data with minimal coding and almost zero effort.

The basic method is to:

  1. Open a new form
  2. The user enters the data and closes the form
  3. In the OnClosing event, save the data to Properties.Settings.Default.SomeVariable
  4. In the main form, get the data back from the settings

So, in code, that looks like this:

In Form1 (the main form):

Form2 form2 = new Form2();
string myVariable = Settings.Default.SomeVariable;

In Form2 (the data entry form):

private void btnOk_Click(object sender, EventArgs e)
    Properties.Settings.Default.SomeVariable = txtSomeVariable.Text.Trim();

Quick, easy and just a little bit sneaky~!