SNHookClass & MultiLicense
-
On 01/02/2013 at 07:40, xxxxxxxx wrote:
User Information:
Cinema 4D Version: R14
Platform:
Language(s) : C++ ;---------
I'm implementing the SNHookClass to allow the user enter the license for my plugin. What is the
c4dsn String passed to ~:SNCheck(); when working on a MultiLicense environment?I'm asking because
- I can't test it (don't have a MultiLicense environment lying around..)
- GeGetSerialInfo() can be called for either retrieving the MutltiLicense or the
generous license.
Is it the 11 digits only and I have to manually check for a MultiLicense, or will be it be the 18
characters long MultiLicense string (12345678912-ABCDEF) ?Thank you,
Niklas -
On 01/02/2013 at 08:14, xxxxxxxx wrote:
Header
//////////////////////////////////////////////////////////////// // KDZSerial.h //////////////////////////////////////////////////////////////// // Serial Number handling //////////////////////////////////////////////////////////////// // V0.1 2011.04.21 Robert Templeton //////////////////////////////////////////////////////////////// // Includes #include "general.h" #include "lib_sn.h" // KDZSerial: Serial Number Hook Class class KDZSerial : public SNHookClass { private: // Data char pcode[6]; const String SNPluginName; // Methods Bool checkSerial(const String& c4dsn, const String& sn); public: // Data // - mode = 0 (not registered/not demo), 1 (demo), 2 (registered), 3 (C4D demo) UCHAR mode; LONG time; // Methods KDZSerial(); LONG SNCheck(const String& c4dsn, const String& sn, LONG regdate, LONG curdate); void setPluginCode(const char* t_pcode); const String& GetTitle(); };
//////////////////////////////////////////////////////////////// // KDZSerial.cpp //////////////////////////////////////////////////////////////// // Serial Number handling //////////////////////////////////////////////////////////////// // V0.1 2011.04.21 Robert Templeton //////////////////////////////////////////////////////////////// // Includes #ifdef MACOS #include "Rijndael_Mac.h" #else #include "Rijndael.h" #endif #include "KDZSerial.h" // Size of serial number string #define ENTRY_SIZE 17 // KDZSerial: Serial Number Hook Class // Methods // - Constructor //*---------------------------------------------------------------------------* KDZSerial::KDZSerial() : SNPluginName(GeLoadString(KDZS_PLUGIN_NAME)) //*---------------------------------------------------------------------------* { mode = 0; } // - KDZSerial.setPluginCode //*---------------------------------------------------------------------------* void KDZSerial::setPluginCode(const char* t_pcode) //*---------------------------------------------------------------------------* { memcpy(pcode, t_pcode, 6); } // - KDZSerial.checkSerial //*---------------------------------------------------------------------------* Bool KDZSerial::checkSerial(const String& c4dsn, const String& sn) //*---------------------------------------------------------------------------* { // Key is 11-Digit C4D SN + 5-Char PluginCode + NullTerminator char key[ENTRY_SIZE]; c4dsn.GetCString(&key[0], c4dsn.GetCStringLen()+1L, STRINGENCODING_7BIT); memcpy(&key[11], &pcode[0], 6); // Encrypt plugin serial no. using AES char dout[ENTRY_SIZE] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; // One block testing CRijndael oRijndael; if (!oRijndael.MakeKey(&key[0], "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16, 16)) { return MessageSystem::Throw(GeLoadString(KDZERR_GENERAL), GeLoadString(KDZERR_SNMAKEKEY)); } char din[ENTRY_SIZE]; memcpy(&din[0], &key[0], ENTRY_SIZE); if (!oRijndael.EncryptBlock(din, dout)) { return MessageSystem::Throw(GeLoadString(KDZERR_GENERAL), GeLoadString(KDZERR_SNENCRYPTION)); } dout[16] = 0; // Null-terminate UINT i; UCHAR val; // Convert to AlphaNumerics for user serial number entry for (i = 0; i != 16; ++i) { val = (UCHAR)dout[i]; // Beyond AlphaNumerics if (val > 122) val /= 3; // Below AlphaNumberics if (val < 48) val += 48; // Between numerals and UC Alpha if ((val > 57) && (val < 65)) val += 24; // Between UC Alpha and LC Alpha if ((val > 90) && (val < 97)) val += 12; dout[i] = (char)val; } dout[16] = 0; // Null-terminate sn.GetCString(&key[0], sn.GetCStringLen()+1L, STRINGENCODING_7BIT); //ENTRY_SIZE, St7bit); // Check sn against Encrypted-AlphaNumericized dout for (i = 0; i != 16; ++i) { //GePrint("key["+LongToString(i)+"]=\'"+LongToString(key[i])+"\' == chk["+LongToString(i)+"]=\'"+LongToString(dout[i])+"\'"); if (key[i] != dout[i]) { return MessageSystem::Throw(GeLoadString(KDZERR_GENERAL), GeLoadString(KDZERR_SNINVALID)); } } return TRUE; } // - SNHookClass.SNCheck //*---------------------------------------------------------------------------* LONG KDZSerial::SNCheck(const String& c4dsn, const String& sn, LONG regdate, LONG curdate) //*---------------------------------------------------------------------------* { if (!sn.Content()) return SN_WRONGNUMBER; // Demo mode (30 day trial) if (sn.GetLength() == 4L) { // Case-insensitive serial number 'demo' String demo = sn.ToLower(); if (demo.Compare("demo")) return SN_WRONGNUMBER; if (!regdate) { mode = 1; return SN_OKAY; } // Calculate timeout of Demo mode // - elapsed time since registering demo LONG exptime = curdate - regdate; // - Number of demo days LONG expiration = 30L; LONG timeout = expiration-exptime; if (timeout < 0L) return SN_EXPIRED; time = timeout; mode = 1; if (exptime >= (expiration-3L)) return SN_EXPIRE_14 - timeout; return SN_OKAY; } // Registered user else if (sn.GetLength() == 16L) { if (checkSerial(c4dsn, sn)) { mode = 2; return SN_OKAY; } } #ifdef C4D_R11 // Multi-License Server else { // Check for R11 Multi-License SerialInfo mlsn; GeGetSerialInfo(SERIALINFO_MULTILICENSE, &mlsn); if (mlsn.nr.Content()) { //-------------------------------------------------------------------------------- // Note that we also need to skip over the extra data added to the front of the // plugin's license key (11 digits/characters and a dash)... //-------------------------------------------------------------------------------- String plug_sn = sn; LONG dashPos; if (plug_sn.FindFirst("-", &dashPos, 0L)) { plug_sn = plug_sn.SubStr(dashPos+1L, plug_sn.GetLength()-dashPos-1L); if (checkSerial(mlsn.nr, plug_sn)) { mode = 2; return SN_OKAY; } } } } #else else MessageSystem::Throw(GeLoadString(KDZERR_GENERAL), GeLoadString(KDZERR_SNSIZE)); #endif return SN_WRONGNUMBER; } // - SNHookClass.GetTitle //*---------------------------------------------------------------------------* const String& KDZSerial::GetTitle() //*---------------------------------------------------------------------------* { return SNPluginName; }
//////////////////////////////////////////////////////////////// // Main.cpp //////////////////////////////////////////////////////////////// // SymMorphy //////////////////////////////////////////////////////////////// // V0.1 2011.05.25 Robert Templeton //////////////////////////////////////////////////////////////// // Includes #include "KDZSerial.h" // - To allow future demo for users who have already demoed a previous version // - Note that it is in the code to avoid user changing ID enum { ID_SYMMORPHY_DEMO = 1029219 }; static KDZSerial* kdzSerial = NULL; //*---------------------------------------------------------------------------* Bool RegisterKDZSerial() //*---------------------------------------------------------------------------* { kdzSerial = gNew KDZSerial(); if (!kdzSerial) return MessageSystem::Throw(GeLoadString(KDZERR_MEMORY), "Main.RegisterKDZSerial.kdzSerial"); char pcode[6] = "symmy"; kdzSerial->setPluginCode(&pcode[0]); if (!kdzSerial->Register(ID_SYMMORPHY, SNFLAG_OWN)) return kdzSerial->Register(ID_SYMMORPHY_DEMO, SNFLAG_OWN); return TRUE; } //*---------------------------------------------------------------------------* void FreeKDZSerial() //*---------------------------------------------------------------------------* { gDelete(kdzSerial); } // Plugin Functions ================================================================================================== #include "SymMorphyDoc.h" // Declare Global Plugin Registrants Bool RegisterSymMorphyTag(); SymMorphyDoc* RegisterSymMorphyDoc(); Bool RegisterSymMorphySceneHook(); static SymMorphyDoc* symmorphydoc = NULL; //*---------------------------------------------------------------------------* Bool PluginStart() //*---------------------------------------------------------------------------* { Bool network = FALSE; #ifdef C4D_R12 VERSIONTYPE vtype = GeGetVersionType(); SYSTEMINFO stype = GeGetSystemInfo(); if ((vtype == VERSIONTYPE_NET_SERVER_3) || (vtype == VERSIONTYPE_NET_SERVER_UNLIMITED) || (vtype == VERSIONTYPE_NET_CLIENT)) network = TRUE; if (stype & SYSTEMINFO_DEMO) GePrint("C4D Demo"); else if (stype & (SYSTEMINFO_SAVABLEDEMO|SYSTEMINFO_SAVABLEDEMO_ACTIVE)) GePrint("C4D Savable Demo"); #ifdef C4D_R13 else if (stype & (SYSTEMINFO_SAVABLEDEMO|SYSTEMINFO_STUDENT)) GePrint("C4D Student Demo"); #endif else if (stype & SYSTEMINFO_COMMANDLINE) GePrint("C4D CommandLine"); else if ((vtype == VERSIONTYPE_NET_SERVER_3) || (vtype == VERSIONTYPE_NET_SERVER_UNLIMITED)) GePrint("C4D Server"); else if (vtype == VERSIONTYPE_NET_CLIENT) GePrint("C4D Client"); else { // serial number check if (!(kdzSerial && kdzSerial->mode)) return ErrPrt(GeLoadString(KDZS_PLUGIN_NAME)+".Main.PluginStart:serial check failed!"); } #elif defined C4D_R11 LONG vtype = GeGetVersionType(); if ((vtype & VERSION_SERVER) || (vtype & VERSION_NET)) network = TRUE; if (vtype & VERSION_DEMO) GePrint("C4D Demo"); else if (vtype & VERSION_SAVABLE) GePrint("C4D Savable Demo"); else if (vtype & VERSION_SERVER) GePrint("C4D Server"); else if (vtype & VERSION_NET) GePrint("C4D Net"); // serial number check else if (!(kdzSerial && kdzSerial->mode)) return ErrPrt(GeLoadString(KDZS_PLUGIN_NAME)+".Main.PluginStart:serial check failed!"); #else LONG vtype = GeGetVersionType(); if ((vtype & VERSION_SERVER) || (vtype & VERSION_NET)) network = TRUE; if (!((vtype & VERSION_DEMO) || network)) { // serial number check if (!(kdzSerial && kdzSerial->mode)) return ErrPrt(GeLoadString(KDZS_PLUGIN_NAME)+".Main.PluginStart:serial check failed!"); } #endif GePrint(" "); GePrint(GeLoadString(KDZS_PLUGIN_BANNER)); GePrint("-- "+GeLoadString(KDZS_PLUGIN_NAME)+GeLoadString(KDZS_PLUGIN_EDITION)+"v"+GeLoadString(KDZS_PLUGIN_VERSION)+" "+GeLoadString(KDZS_PLUGIN_COPYRIGHT)); if (kdzSerial) { if (kdzSerial->mode == 1) GePrint("-- Trial: "+LongToString(kdzSerial->time)+" days left"); else if (kdzSerial->mode == 2) { SerialInfo si; GeGetSerialInfo(SERIALINFO_CINEMA4D, &si); GePrint("-- Licensed to: "+si.name); } } GePrint(GeLoadString(KDZS_PLUGIN_BANNER)); GePrint(" "); // Register hooks and return // - SymMorphy Demo or Registered symmorphydoc = RegisterSymMorphyDoc(); if (!symmorphydoc) return ErrPrt(GeLoadString(KDZS_PLUGIN_NAME)+".Main.PluginStart.RegisterSymMorphyDoc() failed!"); if (kdzSerial) { if (!symmorphydoc->Initialize(network, kdzSerial->mode, kdzSerial->time)) return ErrPrt(GeLoadString(KDZS_PLUGIN_NAME)+".Main.PluginStart.SymMorphyDoc.Initialize() failed!"); } // - Cinema 4D Demo else { if (!symmorphydoc->Initialize(network, 3L, 2147483647L)) return ErrPrt(GeLoadString(KDZS_PLUGIN_NAME)+".Main.PluginStart.SymMorphyDoc.Initialize() failed!"); } if (!RegisterSymMorphyTag()) return ErrPrt(GeLoadString(KDZS_PLUGIN_NAME)+".Main.PluginStart.RegisterSymMorphyTag() failed!"); if (!RegisterSymMorphySceneHook()) return ErrPrt(GeLoadString(KDZS_PLUGIN_NAME)+".Main.PluginStart.RegisterSymMorphySceneHook() failed!"); return TRUE; } //*---------------------------------------------------------------------------* void PluginEnd() //*---------------------------------------------------------------------------* { } //*---------------------------------------------------------------------------* Bool PluginMessage(LONG id, void* data) //*---------------------------------------------------------------------------* { if (id == C4DPL_INIT_SYS) { // initialize global resource object if (!resource.Init()) return ErrPrt("Main.PluginMessage.resource.Init() failed!"); Bool network = FALSE; Bool serial = TRUE; // initialize and register Serial Number Hook #ifdef C4D_R12 VERSIONTYPE vtype = GeGetVersionType(); SYSTEMINFO stype = GeGetSystemInfo(); if (stype & SYSTEMINFO_DEMO) { GePrint("C4D Demo"); serial = FALSE; } else if (stype & (SYSTEMINFO_SAVABLEDEMO|SYSTEMINFO_SAVABLEDEMO_ACTIVE)) { GePrint("C4D Savable Demo"); serial = FALSE; } #ifdef C4D_R13 else if (stype & (SYSTEMINFO_SAVABLEDEMO|SYSTEMINFO_STUDENT)) { GePrint("C4D Student Demo"); serial = FALSE; } #endif else if (stype & SYSTEMINFO_COMMANDLINE) { GePrint("C4D CommandLine"); serial = FALSE; } if ((vtype == VERSIONTYPE_NET_SERVER_3) || (vtype == VERSIONTYPE_NET_SERVER_UNLIMITED)) { GePrint("C4D Server"); serial = FALSE; network = TRUE; } else if (vtype == VERSIONTYPE_NET_CLIENT) { GePrint("C4D Net"); serial = FALSE; network = TRUE; } #elif defined C4D_R11 LONG vtype = GeGetVersionType(); if (vtype & VERSION_SERVER) { GePrint("C4D Server"); serial = FALSE; network = TRUE; } else if (vtype & VERSION_NET) { GePrint("C4D Net"); serial = FALSE; network = TRUE; } else if (vtype & VERSION_DEMO) { GePrint("C4D Demo"); serial = FALSE; } else if (vtype & VERSION_SAVABLE) { GePrint("C4D Savable Demo"); serial = FALSE; } #else LONG vtype = GeGetVersionType(); if (vtype & VERSION_SERVER) { serial = FALSE; network = TRUE; } else if (vtype & VERSION_NET) { serial = FALSE; network = TRUE; } else if (vtype & VERSION_DEMO) { serial = FALSE; } #endif // Allocate SymMorphy Data Storage if (serial) return RegisterKDZSerial(); else return TRUE; } else if (id == C4DPL_ENDACTIVITY) { FreeKDZSerial(); return TRUE; } else if (id == C4DMSG_PRIORITY) return TRUE; return FALSE; } // Return SymMorphyDoc* symmorphydoc - globally accessible //*---------------------------------------------------------------------------* SymMorphyDoc* GetSymMorphyDoc() //*---------------------------------------------------------------------------* { return symmorphydoc; }
-
On 01/02/2013 at 08:15, xxxxxxxx wrote:
Giblet has a very informative post here that outlines the required format of the serial number for the Maxon License Server for plugin registration. The post is: "R11 License Server & SNHookClass"
-
On 05/02/2013 at 15:09, xxxxxxxx wrote:
Here is the Link to "R11 License Server & SNHookClass", mentioned by Robert.
Indeed a very informative thread.And there is a 5 part tutorial about licensing plugins at the "C4D Programming Blog" that also might be interesting for you to read.
Even though there is no extra information about a License Server implementation to find.Thank you Robert for your whole licensing source code(s).
I already have a working solution for myself but I think I'll take a look at yours too and maybe could get some ideas for improvements of my own.
E.G. I still wasn't able to implement a time limited demo mode that really would work as expected. -
On 06/02/2013 at 03:33, xxxxxxxx wrote:
Great to have another open piece of source code for C4D !
Thank you! Lets lock what new I can learn from it.May be we could start GitHub for all the code?
-
On 06/02/2013 at 03:42, xxxxxxxx wrote:
Thank you very much for the reference, Robert!
>>> May be we could start GitHub for all the code?
+ 1 !!!!!
I already have some C4D related stuff on my GitHub profile: https://github.com/NiklasRosenstein
-
On 06/02/2013 at 04:00, xxxxxxxx wrote:
I have some code here:
http://code.google.com/p/code-editor-gui/source/browse/