0

Licensing Plugins – Part III – License integration

Writing a plugin that extends the functionality of CINEMA 4D is often only the first step towards a finished product. At one point or another during the work on your plugin you will have to spend some thought a proper license system.

This third article shows how to integrate a license check in your plugin, using the license class that we created in part II.

Using the license

As I might have mentioned before, there are two common ways to go for license validation: Using the SNHook class, or using a license file. Both are shown in this article:

SNHook

The following code can all be put into one single file “serialhook.cpp”:

#include "c4d.h"
#include "lib_sn.h"
#include "license.h"

class MySerialHook : public SNHookClass
{
private:
  String name;
  MyLicense license;

public:
  MySerialHook() : name("My Plugin 1.0")
  { }

  virtual LONG SNCheck(const String& c4dsn, const String& sn, LONG regdate, LONG curdate)
  {
    return license.CheckLicense(sn);
  }

  virtual const String& GetTitle()
  {
    return name;
  }
};

That’s already all we need to do for our SNHook implementation.

The next step is some code for registration. This also goes into the same file.

MySerialHook *snhook = NULL;

// Plugin ID (please get one from PluginCafé.com!)
#define ID_MY_SNHOOK   123456789

Bool RegisterSNHook(void)
{
  if (IsDemo() || IsCommandLine() || IsNet()) return TRUE;

  snhook = gNew MySerialHook;
  if (!snhook || !snhook->Register(ID_MY_SNHOOK, SNFLAG_OWN))
    return FALSE;

  return TRUE;
}

void FreeSNHook(void)
{
  if (snhook)
  gDelete(snhook);
}

The last thing we need to do is to make the calls for registration and unregistration, and to actually use the result of the license check to decide whether to register the plugin or not.

Here is the main.cpp:

#include "license.h";

Bool RegisterMyPluginObject();
Bool RegisterSomePluginTag();
Bool RegisterSNHook();
void FreeSNHook();

Bool PluginStart(void)
{
  GePrint("My Plugin 1.0 starting...");
  if (valid)
  {
    GePrint("Registering plugins..");
    if (!RegisterMyPluginObject()) goto Error;
    if (!RegisterSomePluginTag()) goto Error;
    GePrint("...successful!");
  }
  else
  {
    GePrint("...invalid license!");
  }
  return TRUE;

Error:
  GePrint("Oops, something went wrong during plugin registration.");
  return FALSE;
}

Bool PluginMessage(LONG id, void *data)
{
  switch (id)
  {
    case C4DPL_INIT_SYS:
      if (!resource.Init()) return FALSE;    // don't start plugin without resource
      if (!RegisterSNHook()) return FALSE;
      return TRUE;

    case C4DPL_ENDACTIVITY:
      FreeSNHook();
      return TRUE;
  }
  return FALSE;
}

Bool valid

This is the external Bool variable that we declared in license.h. It contains the result of the license check.

PluginMessage

In PluginMessage() we register and free the SNHook.
Since C4DPL_INIT_SYS is called before PluginStart(), we need to register the SNHook here. Later, when PluginStart() is called, we have the result of the license check already stored in ‘valid’.

FreeSNHook

Don’t forget to call this, otherwise you will have memory leaks.

This should already work. After building the project, run CINEMA 4D and you will be presented a request for a license key for your plugin. But since we don’t have generated a license key yet, our plugin should not be registered and not appear in the Plugins menu.

License files

If you choose to use license files instead of the SNHook class, you don’t need all that stuff from the chapter above.
You just need a function to read a line from a text file, and then use it in PluginStart() in main.cpp to read the license key, validate it and decide whether to register the plugins or not.

This is how it could look like in main.cpp:

#include "lib_sn.h"

#define MYLICENSE_LICFILENAME    String("license.txt")

Bool PluginStart(void)
{
  MyLicense license;
  GePrint("My Plugin 1.0 starting...");
  String licStr = ReadLineFromFile(GeGetPluginPath() + MYLICENSE_LICFILENAME);

  if (!licStr.Content()))
  {
    GePrint("No license file found, or file corrupted.");
    return FALSE;
  }
  else if (license.CheckLicense(licStr) != SN_WRONGNUMBER)
  {
    GePrint("Registering plugins...");
    if (!RegisterMyPluginObject()) goto Error;
    if (!RegisterSomePluginTag()) goto Error;
    GePrint("...successful!");
  }
  else
  {
    GePrint("...invalid license!");
    return FALSE;
  }
  return TRUE;

Error:
  GePrint("Oops, something went wrong during plugin registration.");
  return FALSE;
}

It’s as simple as that.

The function used for reading from the file is defined as follows:

String ReadLineFromFile(const Filename &filepath)
{
  LONG pos = 0;
  CHAR ch;
  String str, readstr;
  BaseFile *bf = BaseFile::Alloc();
  if (!bf) return String();

  if (!bf->Open(filepath, FILEOPEN_READ, FILEDIALOG_NONE))
    goto Error;
  while (pos < bf->GetLength())
  {
    if (!bf->ReadChar(&ch))
      goto Error;
    readstr.SetCString(&ch, 1);
    str += readstr;
    pos = bf->GetPosition();
  }
  bf->Close();

  BaseFile::Free(bf);
  return str;

Error:
  if (bf) BaseFile::Free(bf);
  return String();
}

Conclusion

Now we have implemented a license check (either via SNHook or using a license file, depending in which way you chose to go). So we are basically locked out of our own plugin. Time to write a license generator! Read on in the next chapter.

Related articles

Frank Willeke

worked with computers since more than 20 years | got hooked on computer graphics back on the AMIGA | started programming at the age of 13 | relesed some successful plugins for cinema 4d | started working for maxon computer gmbh in 2009 | now contributing to cinema 4d as a senior developer

making electronic music since 1993 | playing the electric guitar since 1995 age of 14 | first live gigs in 1997 | playing the bass guitar 2005 | playing keyboards and synths since 2012

experimenting with photography since 2003

Leave a Reply

Your email address will not be published. Required fields are marked *