Using Lazarus Registration to implement "Try Before You Buy" style shareware

A lot of software, including Lazarus Registration, has a "try before you buy" feature. Implementing this can be a pain in the tail though. You must either build two versions of your software, or devise some way to check the registration code in your program. This is where the registration component steps in.

The first step is to not use the registration component in your installer. Instead, you're going to put an interface in your program to collect the registration information and write it out to a file. In my example code below that file is called registration.conf and uses the same format as the registration.conf file included with the registration component. Change the names to suit your own needs.

Next, you'll need to include the code below into your application. I provided examples in C, because that's what I'm most comfortable with and that's the easiest option when using the registration component. You can adapt this code to your own development environment as necessary.

/* Picks up definition of REGISTRATION_MD5 */
#include "regsanity.h"
#include "config.h"

int app_is_registered()
{
	const char *md5 = NULL;
	config_t conf = NULL;
	FILE *cfile = NULL;
	char *serial = NULL;
	char *regkey = NULL;

	md5 = getmd5("regmyapp.dll");
	if (strcmp(md5, REGISTRATION_MD5)) 
		return 0; /* Not the DLL we shipped, don't trust it */

	cfile = fopen("registration.conf", "r");
	if (!cfile)
		return 0; /* No config file, not registered */
	conf = config_read(cfile);
	fclose(cfile);

	serial = config_get_string(conf, "reg-serial");
	if (!serial)
		return 0; /* No registration information present */
	regkey = config_get_string(conf, "reg-key");
	if (!regkey)
		return 0; /* No registration information present */

	/* Actually confirm if the registration code is valid */
	return confirm_registered(serial, regkey);

}

const char* getmd5(const char* filename) {

	FILE* in;
	char* buffer;
	md5_state_t pms;
	md5_byte_t digest[16];
	static char key[33];
	int i;
	struct stat sb;
	char *pos;
	
	if (stat(filename, &sb)) {
		perror(filename);
		return NULL;
	}

	buffer = (char*)calloc(1, sb.st_size + 1);
	memset(key, 0, 33);
	in = fopen(filename, "rb");
	fread((void*)buffer, 1, sb.st_size, in);
	fclose(in);

	md5_init(&pms);
	md5_append(&pms, (const md5_byte_t *)buffer, sb.st_size);
	md5_finish(&pms, digest);

	pos = key;
	for(i=0; i < 16; ++i) {
		sprintf(pos, "%2.2x", digest[i]);
		pos += 2;
	}

	return key;

}

You should call app_is_registered() when your program first starts, to disable features or turn on the bits that mark your app as a demo. You might also want to run this check in multiple places, as Patrick McKenzie suggests in his excellent article on software registration systems.

Nothing could be simpler. Now you just release your application to the public, let them try it out, and when they register they get the full deal.