Starting C++ SDK Tutorial
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 22/01/2003 at 13:22, xxxxxxxx wrote:
ok, sorry I wanted to post this in a daily order, but I'm too busy at the moment.
Today there's just a short explanation about Plugin IDs.
"Plugin IDs 1000001-1000010 are reserved for development. You may use these freely to test scripts, but must request an ID in order to release them. "
Every plugin loaded from Cinema needs a unique ID that it can be referenced. If you try to load 2 plugins with the same ID Cinema refuses to load the 2. plugin. For your own plugin you need to get a unique plugin ID.more here:
[URL-REMOVED]
[URL-REMOVED]Sneaker
[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 24/01/2003 at 06:24, xxxxxxxx wrote:
Hi Sneaker,
I did a BCC tutorial some time ago but had to stop working on it because of compatibility issues in R8. Well, I would like to participate, but haven't done much at last. Do you plan to set up a web page for this?
There are some topics I would add: SDK-Setup for a stand-alone library and some facts to the internal calling mechanisms.
Ciao,
Marcus -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 24/01/2003 at 13:30, xxxxxxxx wrote:
Yes, of course, a web page will follow after the tutorial is done here in plugincafe. There are too many things I don't know right now and hope that someone helps me when i got stuck.
You're very welcome.
What do you mean with "SDK-Setup for a stand-alone library "?
greetings
Sneaker -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 24/01/2003 at 14:15, xxxxxxxx wrote:
Hi Sneaker.
With "SDK-setup for a stand-alone library" I mean that I copy all API files from ...\Resources\... to my specific (from Cinema isolated) project-directory and build the static library in this place. There are some reasons for that:
- If you update your Cinema it might change the API. If you're just in a project, compatibility issues might arise.
- The former SDK was an own package not integrated into the Cinema directory structure. Because I'm a friend of modular solutions, I prefer the old way to the integrated package.
- Then there was a practical reason: I had to correct the line endings of the source files but I didn't want to replace the original ones. So I had to move them to a new place anyway.BTW: For the last point I've written a tool that converts between UNIX and DOS style line-endings and corrects that way the SDK-line-endings. It is also able to convert the tabulators to spaces (not everybody uses the same tab-sizes...).
For the tutorial I think a modular approach should be used, because this way you can add the topics as your time allows. There will be always something to explain...
The first plugin should be a simpel "Hello world." Then there should be some dialog tests just to get the feet wet. I've written a spline-align COFFEE expression I would like to port to the C++-SDK. And I usually write my tutorials in HTML. I've some Arcor web space where I can set up a simple page if you like.
Ciao,
Marcus -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 25/01/2003 at 12:27, xxxxxxxx wrote:
that all sounds really good, and when you look at the 2. reply of that thread, you'll see a "Hello World" is planned.
Web space is no problem, but I want to finish the tutorial and then use this to make it. And of course translate it to German.
greets,
Sneaker -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 28/01/2003 at 16:00, xxxxxxxx wrote:
this is sounds very interesting and useful... keep it up, and post everything on a website somewhere when you've got those tutorials done. i'm sure i'm not the only one who's been befudled by the sdk and could do with all the help and guidance they can get.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 29/01/2003 at 14:59, xxxxxxxx wrote:
hi I'm back.
here comes the next part: A clean Project.
Before I start I have to thank Marcus Spranger for his great support.
He's really pushing me forward. Actually he's doing the tutorial and I try to
understand and then post it here :o))).
Marcus did a superb easy to use template for Visual C++ V7.
I tried to do the same for V6, but I think V6 isn't as flexible as V7.
(Please help if someone knows a better way)
first here are the files:
V7: http://www.sneaker3.de/Tutorials/Cpp-SDK/empty.vcproj
V6: http://www.sneaker3.de/Tutorials/Cpp-SDK/empty.dsp
Installation:
It's a good idea to make a second installation of Cinema, where you develop your plugins. (You don't collide with other plugins and if a Cinema update is available, you don't have to worry about api changes.)
Now create a folder under plugins (MyPlugins), where you develop your plugins. Here is a good place to have the template.
No! don't open it with VC for now. The template ist made for a deeper folder level.
Let's make a folder in MyPlugins called Hello. This should look like this so far:
CINEMA_4D_R8
-Plugins
--MyPlugins
---HelloCopy empty.* into "Hello"
Rename empty.* to Hello.*
For V7 everything necessary is done - cool huh!
V6 needs some additional changes:
open Hello.dsp with Notepad, replace all "empty" with "Hello" and save it. Close Notepad.
Now we're ready to open the files with VC. VC6 complains to create and open a Workspace instead, that's ok.
Check the active configuration and set it to Hello - Release.
Create a File Hello.cpp and add the following code (from Marcus) :#include "c4d.h" /** * This function is called by the API initialization mechanism * when Cinema4D loads the plugin. */ Bool PluginStart() { GePrint ("Hello World :))))))"); return TRUE; } /** * This function is called by Cinema4D-API when it unloads the plugin. */ void PluginEnd(void) { } /** * This function is used for low-level message passing. */ Bool PluginMessage(LONG id, void *data) { switch (id) { case C4DMSG_PRIORITY: GePrint ("C4DMSG_PRIORITY has been sent"); break; case C4DMSG_OS: GePrint ("C4DMSG_OS has been sent"); break; case C4DPL_STARTACTIVITY: GePrint ("C4DPL_STARTACTIVITY has been sent"); break; case C4DPL_ENDACTIVITY: GePrint ("C4DPL_ENDACTIVITY has been sent"); break; default: GePrint (LongToString (id) + " has been sent"); } return FALSE; }
Build Hello.cdl. It should work directly. If not, please check everything what have been discussed before (api, dependencies, actice configuration etc..)
The template is made for a precompiled api/lib.
Else open Cinema and have a look at the Console (Menu/Window/Console) - surprise it worked without a PluginId.
Homework: Read the code and understand what's going on :o). The SDK files may help. I'll do the same.Marcus thank you very much.
Sneaker
PS: here is Hello.zip:
http://www.sneaker3.de/Tutorials/Cpp-SDK/Hello.zipPPS: If someone knows a better way for the V6 template please help
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 30/01/2003 at 01:56, xxxxxxxx wrote:
Hi folks.
What we did to create the templates: We simply took the project file of the SDK-examples, removed all file entries and adapted the directory/file options. In VC7 you can use macros for this, so you don't have to touch these options anymore. It would be great if there is a Mac user who could do the same for the Macintosh-SDK.
By the way: An explanation of the initialization mechanism will follow soon - it has just to be translated. A second more elaborated Hello-World (using a message box and string resources) will follow too. And yes we've got a first example plugin with some usability in the pipeline. Into this we will also look in detail.
Happy hacking. Ciao,
Marcus -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 05/02/2003 at 16:48, xxxxxxxx wrote:
Hi,
I've written up a tutorial describing how to go about isolating a single plugin from the SDK, so that you can use it as a base framework for building your own plugins. This also includes some explanation of what various the files are for in a plugin.I was originally going to post it here, but then it got long, so I've put it on my website instead.
Goto www.astrofish.com and pick option 4 (Tutorial).
Anyway, hope it's useful to someone.
Any Mac users who look at it - I'd appreciate it if you'd let me know whether my pre-built 'xdl' file actually works on a Mac, since it was built on a PC...
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 06/02/2003 at 14:45, xxxxxxxx wrote:
Hi Steve,
thanks a lot for your efforts. Your tutorial is great for people looking for a fast entry into SDK programming.
Thumbs up. Ciao,
MarcusPS: I have done some work on describing the API structure, but due to time constraints don't make much progress. At the weekend I hope to find some time for the tutorials.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 06/02/2003 at 23:55, xxxxxxxx wrote:
Hi Marcus,
it's incredible, but you just post the nearly same I wanted to post today.
I'm really busy at the moment and hope to find more time on Sunday to go on with the tutorial.
Steve, it's good to have more ways to get to similar results, and I'm still learning.
cu
Sneaker -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 10/02/2003 at 02:01, xxxxxxxx wrote:
ok, here is the way to our first real plugin.
Marcus, thanks again to provide me with the code and additional information.
There is one thing I didn't change, but I think it's better to change it in future.
You stored the PluginID in c4d_symbols.h. This file must be distributed to the end user
and therefore every end-user can change it. This might help during development, but I don't
think that anybody should be able to change a unique PluginID given to the author.so, the first thing we need is a plan what we're going to do.
It's an easy plugin so we don't need a big plan:
Plugin to send a Hello World message box and write some info into console
here are the steps to do this:
- create a subfolder Hello2 under "MyPlugins"
- copy our empty project to Hello2 and rename it like describe above
- create necessary subfolders in project and file system
- res
- strings_de
- strings_us
- ..... (whatever strings_lang you want)
- src
good.
now we need some files.create a new file in "res" folder called "c4d_symbols.h" and fill in this code:
enum { IDS_PLUGIN_NAME = 0, IDS_PLUGIN_DESCR, IDS_MESSAGE, IDS_ERR_CONSTR, PLUGIN_ID = 1009173 };
create a new file in "strings_us" folder called "c4d_strings.str" and fill in this code
STRINGTABLE { IDS_PLUGIN_NAME "Hello World Advanced ;)"; IDS_PLUGIN_DESCR "Prints out a Hello World message"; IDS_MESSAGE "Hello World!"; IDS_ERR_CONSTR "Construction of HelloWorld object failed"; }
if you like to you can create additional files in the language folders. example for "strings_de":
create a file called "c4d_strings.str" and fill in:STRINGTABLE { IDS_PLUGIN_NAME "Hallo Welt Erweitert ;)"; IDS_PLUGIN_DESCR "Gibt eine 'Hallo Welt'-Nachricht aus"; IDS_MESSAGE "Hallo Welt!"; IDS_ERR_CONSTR "Es konnte kein HelloWorld-Objekt erzeugt werden"; }
and now the very important plugin code itself. Create a new file in "src" folder called "Hello2.cpp"
and fill in:#include "c4d.h" #include "c4d_symbols.h" /** * */ class HelloWorld : public CommandData { public: virtual Bool Execute(BaseDocument* doc); }; /// Bool HelloWorld::Execute (BaseDocument* doc) { String wind0 = "Windows"; GeOutString (GeLoadString (IDS_MESSAGE), GEMB_OKCANCEL); GePrint ("Hello World Advanced :))))))"); if (GeGetCurrentOS() == GE_WIN){ GePrint ("Hello World "+wind0); } else { GePrint ("Hello World Mac :))))))"); } return (TRUE); } /** * */ Bool PluginStart () { HelloWorld *helloWorld = NULL; // initialize global resource object if (!resource.Init()) return FALSE; // create new instance of HelloWorld class, if not done already if ((helloWorld = new HelloWorld) == NULL) { GePrint (GeLoadString (IDS_PLUGIN_NAME) + ": " + GeLoadString (IDS_ERR_CONSTR)); return (FALSE); } // register hook and return return (RegisterCommandPlugin (PLUGIN_ID, GeLoadString (IDS_PLUGIN_NAME), 0, GeLoadString (IDS_PLUGIN_DESCR), helloWorld)); } /** * */ void PluginEnd () { } /** * */ Bool PluginMessage(LONG id, void* data) { return (FALSE); }
----------------------------
compile it and if error free start cinema. Open Menu/Plugins/Hello World Advanced (or similar depending on your language settings).
A dialog box appears with our "Hello World" message. Open the console window and see the additional info.
The next time we'll try to describe some background information how plugins work. Marcus supplied me with some html pages I'd like to publish.
No this time no download! Do your homework ;o).
good luck,
Sneaker -
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 10/02/2003 at 02:17, xxxxxxxx wrote:
Well done! Just one comment though...
> Quote: There is one thing I didn't change, but I think it's better to change it in future.
>
> * * *
>
> You stored the PluginID in c4d_symbols.h. This file must be distributed to the end user
> and therefore every end-user can change it. This might help during development, but I don't
> think that anybody should be able to change a unique PluginID given to the author.
>
> * * *I would DEFINATELY change this. If the PluginID is unique already, which it should be, then there is no reason why the end user should need to change it.
The fact that they _can_ change it means that some people will put in arbitrary values, and sooner or later it will conflict with someone else's plugin number.
With more complex plugins that store information in the document, the result of two different plugins sharing an ID number could be severe corruption of scene files, as one plugin modifies data that it thinks is its own, but actually belongs to another plugin.
I don't see any reason to have it in the symbols file, even during development.
I don't mean to sound critical, but this is a very important issue. If end users start changing plugin ID numbers (e.g. 'just to see what it does'), then you can wave goodbye to the stability that we enjoy at the moment.
Always use unique ID numbers assigned by PluginCafe, and NEVER let the end user change them - they don't need to, and it's dangerous!
Cheers - Steve
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 10/02/2003 at 06:15, xxxxxxxx wrote:
Hi Steve and Sneaker,
yep you both are right. I did this to make the ID easy modifyable for me. But you're right the data issue is very serious - I didn't think about it. I will change it.
Thanks for the comments. As you see, some comments are missing ... the documentation will follow. I swear! The weekend I was installing LINUX and still am, so please be patient
Ciao,
Marcus -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 10/02/2003 at 08:08, xxxxxxxx wrote:
With more complex plugins that store information in the document, the result of two different plugins sharing an ID number could be severe corruption of scene files, as one plugin modifies data that it thinks is its own, but actually belongs to another plugin.
---------------------------------
That is actually not possible IMO. Any other plugin with a different ID has access to "public" values created by another plugin. And private data can´t be changed (if not specificaly arranged) by any plugin anyway. Changing data isn´t really linked to PluginIDs. The main reason is to prevent collisions between the registration and for dialog IDs. So if you create a key with your plugin, any other plugin can find this key in the timeline and change the data if possible to change it.
Best
Samir -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 10/02/2003 at 09:23, xxxxxxxx wrote:
Hi,
I'm referring to private plugin data stored within the document.PluginID values can be used to uniquely identify a subcontainer stored within an object's base container, in which the plugin can safely store arbitrary information for its own purposes.
My understanding is that this is the recommended method for storing such private information.
If another plugin uses the same ID value then both plugins would have access to the same subcontainer, but both would believe that it belonged to them only - as a result they could interact with each other in unpredictable ways.
In this way, different plugins _can_ mess up each others private data.
Cheers - Steve
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 10/02/2003 at 09:33, xxxxxxxx wrote:
I'm referring to private plugin data stored within the document.
PluginID values can be used to uniquely identify a subcontainer stored within an object's base container, in which the plugin can safely store arbitrary information for its own purposes.
--------------------------------------------
1. Could you explain that "subcontainer" method a bit more detailed? I didn´t know this is a prefered method for using "private" data... two or three lines of code explaining what you mean would be appreciated.
2. private data can´t be accessed by other plugins for it is declared as "private". Maybe you are talking something else?
--------------------------------------------My understanding is that this is the recommended method for storing such private information.
--------------------------------------------
I don´t think so. I have a thousand times the same IDs for basecontainer values in my plugins and none of them did ever collide. So I don´t get the point here really. Maybe someone from the dev support could help us find out what´s going on with stored data in basecontainers... But I can´t imagine it is possible.
---------------------------------------------If another plugin uses the same ID value then both plugins would have access to the same subcontainer, but both would believe that it belonged to them only - as a result they could interact with each other in unpredictable ways.
----------------------------------------------
Sorry, I don´t believe that. Then it would be easily possible to exchange data thru a subcontainer but afaik that´s not possible but only over the PluginMessage Port....?!
Best
Samir -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 10/02/2003 at 10:11, xxxxxxxx wrote:
Two plugins with the same plugin ID can -not- run at the same time.
However, lets say you have PluginA and PluginB, they both share the same ID (for whatever reason), a user creates a document with PluginA, sends this to someone with PluginB. When they open it, CINEMA will try and find the plugin with the matching ID that is of the same type, if say PluginA and pluginB are both plugin objects, then when PluginB tries to access the basecontainer data the values it reads back will make no/little sense to it, at best the plugin will just behave odd, at worst it could lead to serious problems (maybe a freeze or crash). This is the -only- way two plugins with the same ID could interact, plugins with different IDs (so they can run at the same time), can interact in many ways.
Sharing plugin IDs is NOT advised, they -must- be unique, if during development you use a set of fixed IDs or the temporary IDs, then that is your choice, I never do this, I'd rather start off with my real IDs.
BaseContainer data can be accessed by any plugin, there is no such thing as private, you don't even need to know the IDs of the data, you can enum the data elements.
You can use a subcontainer if you wish, but you don't have to, each type of object has its own basecontainer, the data is per object. Storing data in a BaseContainer is recommended simply because CINEMA will handle read/write and clone, if you have the data in your class then you need to handle the read/write/clone of any data the plugin needs.
I think there is some confusion in what you are both talking about, I couldn't really follow either of you -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 10/02/2003 at 10:17, xxxxxxxx wrote:
BaseContainer data can be accessed by any plugin, there is no such thing as private, you don't even need to know the IDs of the data, you can enum the data elements.
You can use a subcontainer if you wish, but you don't have to, each type of object has its own basecontainer, the data is per object. Storing data in a BaseContainer is recommended simply because CINEMA will handle read/write and clone, if you have the data in your class then you need to handle the read/write/clone of any data the plugin needs.
-------------------------------------------
Ah ok, this makes things clearer. Thanks for clarification.
-------------------------------------------
I think there is some confusion in what you are both talking about, I couldn't really follow either of you
-------------------------------------------
lol, I didn´t even know myself what we were talking.
Best
Samir -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 10/02/2003 at 12:26, xxxxxxxx wrote:
David: The A/B plugin situation you described was what I meant regarding potential conflict between plugins - but you explained it much more clearly!
3D: Ok, I shouldn't really have referred to it as 'private', because it's not actually private - it's just data that is only _meant_ to be accessed by one particular plugin. There isn't actually anything to stop it though.
From the SDK (R7 and R8), under 'BaseContainer':
"It is recommended that you use the available containers to store your own values as well. That way they will be automatically saved. However, if you want to store values in the top level of for example an object container, you'll have to use a unique id. You can use a plugin id from http://www.plugincafe.com for this. A good way is to store a sub-container with this id. Inside this sub-container you can use whatever ids you want."If you follow this advice, and use the PluginID as a unique ID number to identify 'your' sub-container, then the A/B situation David described means that one plugin could see the sub-container that the other one wrote, and chaos _may_ then ensue...
One final note - the docs say that using a plugin ID number is a good way of getting a unique number. It seems to me that it is the _only_ way of getting a number that you know is unique.