Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Creating Library problem [SOLVED]

    SDK Help
    0
    27
    15.7k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      On 08/09/2014 at 10:28, xxxxxxxx wrote:

      well I understand your point, but what I sense is that you should have an instance of the class somewhere, so:

      myclassFunction() {myclass mC; /* .....some stuff */ ; return mC.privateMember;}

      other than that, when doing something similar in a DLL for an API, just giving the user a function is fine as long as this function will create its own work

      other than that I think it is out of my knowledge

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 08/09/2014 at 10:45, xxxxxxxx wrote:

        The class is instanced! The scene hook "MyHook" is implemented in my plugin (and the library from above as well), compiled as: myhook.cdl64.
        So whenever a user opens a scene in C4D an instance of that hook is allocated by Cinema 4D! This instance is retrieved by using "FindSceneHook" as shown above.

        The purpose however is that the user can load the library headers into his own c4d plugin project (for example compiling into: myplugin.cdl64).  He should then also be able to use FindSceneHook (see my first posting, second code) and cast it to MyHook_mirror* (That's also how the Thinking Particles library does it btw to retrieve the TP_MasterSystem Scene hook...check out the docs for TP_MasterSystem).

        When he then calls the function MyHook_mirror::get_value in his plugin project, the function pointer will instead "jump" to the original member function of that hook provided by the library (myhook.cdl64), so granting him outside access to the other dll.

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 08/09/2014 at 10:59, xxxxxxxx wrote:

          ops, well sorry for my previous posts then 😊

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 08/09/2014 at 11:26, xxxxxxxx wrote:

            No problem. It's good to discuss this stuff (also for me it's a proof reading of my own understanding...and apparently I am not right about something). Still hopefully someone out there can shed some light on what I am doing wrong or what I am missing or even what I got wrong here? 😞

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 09/09/2014 at 08:22, xxxxxxxx wrote:

              Hi Katachi, the following works for me (tested on Mac R15 only).
              You can download the four files from here.

              main.cpp

              /* Copyright (C) 2014  Niklas Rosenstein
               * All rights reserved. */
                
              #include "c4d.h"
              #include "library.h"
                
              extern Bool RegisterTestHook();
                
              class TestCommand : public CommandData
              {
              public:
                
                virtual Bool Execute(BaseDocument* doc)
                {
                  TestSceneHook* hook = TestSceneHook::Get(doc);
                  if (!hook)
                  {
                    GePrint("No TestSceneHook found in the document.");
                    return true;
                  }
                
                  Int value = hook->GetValue();
                  GePrint("TestSceneHook::GetValue() returned " + String::IntToString(value));
                  return true;
                }
              };
                
                
              Bool PluginStart()
              {
                if (!RegisterTestHook())
                  GePrint("Failed to register Test Scene Hook.");
                if (!RegisterCommandPlugin(
                  1000009, "Test Scene Hook Command", 0, nullptr, "",
                  NewObj(TestCommand)))
                {
                  GePrint("Failed to register Test Scene Hook Command.");
                }
                return true;
              }
                
              Bool PluginMessage(Int32 type, void* pData)
              {
                switch (type)
                {
                  case C4DPL_INIT_SYS:
                    return ::resource.Init();
                };
                return true;
              }
                
              void PluginEnd()
              {
              }
              

              library.h

              /* Copyright (C) 2014  Niklas Rosenstein
               * All rights reserved. */
                
              #pragma once
                
              #include "c4d.h"
                
              static const Int32 ID_LIBRARY_TEST = 1000005; // Test ID
              static const Int32 ID_SCENEHOOK_TEST = 1000007; // Test ID
                
              struct TestLibrary : public C4DLibrary
              {
                Int (*TestSceneHook_GetValue)(const BaseSceneHook* );
              };
                
              TestLibrary* GetTestLibrary(Int offset);
                
              #ifdef TESTLIB_CALL_MACROS
                #define CallTestLibR(func) \n    TestLibrary* _lib_ = GetTestLibrary(LIBOFFSET(TestLibrary, func)); \n    if (_lib_ && _lib_->func) \n      return _lib_->func
              #endif
                
              class TestSceneHook : public BaseSceneHook
              {
                TestSceneHook();
                ~TestSceneHook();
              public:
                
                Int GetValue() const;
                
                static TestSceneHook* Get(BaseDocument* doc);
              };
              

              library.cpp

              /* Copyright (C) 2014  Niklas Rosenstein
               * All rights reserved. */
                
              #define TESTLIB_CALL_MACROS
              #include "library.h"
                
              TestLibrary* GetTestLibrary(Int offset)
              {
                static C4DLibrary* cache = nullptr;
                return static_cast<TestLibrary*>(
                  CheckLib(ID_LIBRARY_TEST, offset, &cache));
              }
                
              Int TestSceneHook::GetValue() const
              {
                CallTestLibR(TestSceneHook_GetValue)(this);
                return -1;
              }
                
              TestSceneHook* TestSceneHook::Get(BaseDocument* doc)
              {
                return static_cast<TestSceneHook*>(doc->FindSceneHook(ID_SCENEHOOK_TEST));
              }
              

              internal.cpp

              /* Copyright (C) 2014  Niklas Rosenstein
               * All rights reserved. */
                
              #include "c4d.h"
              #include "library.h"
                
              class TestSceneHookData : public SceneHookData
              {
                Int m_value;
                
              public:
                
                static NodeData* Alloc() { return NewObj(TestSceneHookData); }
                
                TestSceneHookData() : SceneHookData(), m_value(42) { }
                
                Int GetValue() const { return m_value; }
              };
                
              Int TestSceneHook_GetValue(const BaseSceneHook* hook)
              {
                TestSceneHookData* data =
                  static_cast<TestSceneHookData*>(hook->GetNodeData());
                if (!data) return -1;
                return data->GetValue();
              }
                
              Bool RegisterTestHook()
              {
                static TestLibrary lib;
                ClearMem(&lib, sizeof(lib));
                lib.TestSceneHook_GetValue = &TestSceneHook_GetValue;
                
                Bool success = InstallLibrary(ID_LIBRARY_TEST, &lib, 1000, sizeof(lib));
                if (!success) return false;
                
                success = RegisterSceneHookPlugin(
                  ID_SCENEHOOK_TEST, "Test Scene Hook", 0, TestSceneHookData::Alloc,
                  0, 0, nullptr);
                
                return success;
              }
              

              Best,
              -Niklas

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 09/09/2014 at 12:52, xxxxxxxx wrote:

                Niklas, using a function layer taking the hook directly...thanks! So obvious but it was so hidden to me. 🙂 You made my day! Appreciate the help, this gets me going.

                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  On 09/09/2014 at 14:08, xxxxxxxx wrote:

                  You're welcome. 🙂
                  Btw, I think to make your original example work, you were indeed doing something
                  wrong with calling the pointer-to-member function.

                  Especially this looks strange to me:  lib->mHook.get_value()

                  I think the right code would be something like this:

                  class MyHookLib : public C4DLibrary
                  {
                  public:
                    int ( **SceneHookData** ::*get_value)() const;
                  };
                    
                  class MyHookMirror : public BaseSceneHook
                  {
                  public:
                    int get_value() const
                    {
                      SceneHookData* data = static_cast<SceneHookData*>(GetNodeData());
                      MyHookLib* lib = CheckLib(...);
                      if (data && lib && lib->get_value)
                        return **(data- >*lib->get_value)();**
                      return -1;
                    }
                  }
                  

                  Note that it's using a pointer-to-member function of a SceneHookData class as your own
                  SceneHookData subclass will not be visible to users of your library (and it should work
                  though!).

                  See also: http://www.parashift.com/c++-faq-lite/pointers-to-members.html

                  Best,
                  -Niklas

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    On 09/09/2014 at 14:55, xxxxxxxx wrote:

                    Originally posted by xxxxxxxx

                    You're welcome. 🙂
                    Btw, I think to make your original example work, you were indeed doing something
                    wrong with calling the pointer-to-member function.

                    Especially this looks strange to me:  lib->mHook.get_value()

                    return (data- >*lib->get_value)();

                    Thanks, but that was not my code but the changed code of Mohamed. My code is the one in the initial thread posting (and does already as you suggest) 🙂

                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      On 09/09/2014 at 15:02, xxxxxxxx wrote:

                      Originally posted by xxxxxxxx

                      int ( SceneHookData ::*get_value)() const;

                      Note that it's using a pointer-to-member function of a SceneHookData class as your own
                      SceneHookData subclass will not be visible to users of your library (and it should work
                      though!).

                      So you are saying that when I am using (MyHook::*get_value) instead of its base class it won't work? I will read up on this link tommorrow (unbelievably tired..), but that would be a bummer. (I mean it would be great if that was the issue, I am all for anything that fixes my problem..hehe)

                      My thoughts were that I can forward declare the class to use for the pointer-to-member function declaration (just as it is done with the iMy1DVector taking the SDK example as refernce). imo that should work. Really must read up on that link. This feels strange (especially as get_value is not defined in SceneHookData).. 🙂 But I'll try it out.

                      1 Reply Last reply Reply Quote 0
                      • H
                        Helper
                        last edited by

                        On 09/09/2014 at 15:44, xxxxxxxx wrote:

                        Originally posted by xxxxxxxx

                        Originally posted by xxxxxxxx

                        You're welcome. 🙂
                        Btw, I think to make your original example work, you were indeed doing something
                        wrong with calling the pointer-to-member function.

                        Especially this looks strange to me:  lib->mHook.get_value()

                        return  (data- >*lib->get_value)();

                        Thanks, but that was not my code but the changed code of Mohamed. My code is the one in the initial thread posting (and does already as you suggest) 🙂

                        Oh sorry, you are right 🙂 But  (((MyHook* )this)->*(lib->get_value))();  is not right either.
                        this is not MyHook (SceneHookData subclass) but MyHook_mirror (BaseSceneHook subclass), it
                        is therefore undefined to cast it into a MyHook pointer. 🙂

                        Originally posted by xxxxxxxx

                        Originally posted by xxxxxxxx

                        int ( SceneHookData ::*get_value)() const;

                        Note that it's using a pointer-to-member function of a SceneHookData class as your own
                        SceneHookData subclass will not be visible to users of your library (and it should work
                        though!).

                        So you are saying that when I am using (MyHook::*get_value) instead of its base class it won't work? I will read up on this link tommorrow (unbelievably tired..), but that would be a bummer. (I mean it would be great if that was the issue, I am all for anything that fixes my problem..hehe)

                        My thoughts were that I can forward declare the class to use for the pointer-to-member function declaration (just as it is done with the iMy1DVector taking the SDK example as refernce). imo that should work. Really must read up on that link. This feels strange (especially as get_value is not defined in SceneHookData).. 🙂 But I'll try it out.

                        I'm not sure what you're trying to say, so I'll try to clarify what I meant: I think that you usually
                        don't expose the SceneHookData subclass declaration to the third party that uses the functionality
                        of your plugin provided by your C4DLibrary. The MyHook class will therefore not be defined at this
                        point in the code.

                        Originally posted by xxxxxxxx

                        This feels strange (especially as get_value is not defined in SceneHookData)..

                        The syntax is confusing. For pointer-to-member functions you have to declare the type of the
                        object that you will call the function for. The part after :: does not need to be a member of
                        the class, but it is the name of the declaration (variable or typedef name).

                        typedef int (*some_func_t)(FooClass* );
                        typedef int (FooClass::*some_member_func_t);

                        some_func_t           func        = &SomeGlobalFunction;
                        some_member_func_t    member_func = &FooClass::SomeFunction;

                        Best,
                        -Niklas

                        1 Reply Last reply Reply Quote 0
                        • H
                          Helper
                          last edited by

                          On 10/09/2014 at 00:47, xxxxxxxx wrote:

                          Hey Niklas!

                          Originally posted by xxxxxxxx

                          Oh sorry, you are right 🙂 But  (((MyHook* )this)->*(lib->get_value))();  is not right either.
                          this is not MyHook (SceneHookData subclass) but MyHook_mirror (BaseSceneHook subclass), it
                          is therefore undefined to cast it into a MyHook pointer. 🙂

                          This should be a pointer to the class (http://www.parashift.com/c++-faq-lite/dotstar-vs-arrowstar.html).
                          Hmm, then I don't understand the libs used in the C4D API (and the SDK example for creating a library is wrong then?). For example, check out lib_batchrender:

                          class BatchRender
                          {
                          	private:
                          		BatchRender();
                          		~BatchRender();
                          	public:
                          		Bool Open(void);
                          };
                           
                          //---------------------------------------------------
                          //	---INTERNAL STUFF
                           
                          class iBatchRender; //Forward Declaration!
                           
                          struct BatchRenderLibrary : public C4DLibrary
                          {
                           Bool					(iBatchRender::\*Open)	  
                          };
                          

                          Here iBatchRender is forward declared and still used for defining the according member function call. It is also not visible to the third party (me in this case 😄 ) but is simply forward declared in order to make the definition. This is the classic C++ class layering to me.

                          and check out how the lib now does the library call:

                          Bool BatchRender::Open()
                          {
                          	BatchRenderLibrary \*lib = CheckBatchRenderLib(LIBOFFSET(BatchRenderLibrary, Open));
                          	if (!lib || !lib->Open) return FALSE;
                          	return (((iBatchRender\* )this)->\*(lib->Open))(); 
                          }  
                            
                          It uses iBatchRender here as well (though it's not defined).  
                          To me this looks fine (as forward declared) and should still point correctly to the member function. Can you elaborate a bit more? Thanks!  
                          However, I have definetly not taken into the account the GetNodeData call as you have it. This is a potential gap in my code!!  
                          Thanks!  
                          

                          Originally posted by xxxxxxxx

                          I'm not sure what you're trying to say, so I'll try to clarify what I meant: I think that you usually
                          don't expose the SceneHookData subclass declaration to the third party that uses the functionality
                          of your plugin provided by your C4DLibrary. The MyHook class will therefore not be defined at this
                          point in the code.

                          Yeah, although true, what I mean is that the definition does not need to be available at this point but only at the point when I assign the member function pointer (which happens in the internal.cpp to stay with your code example file names).
                          Just like with any other forward declaration of classes, as long as I don't call member functions of the pointer (etc.), I can easily use it's declaration in my code even if the class is not yet defined). As all I need here is a pointer-to-class if you want so (since all object pointers are of same size, the compiler shouldn't care).

                          The syntax is confusing. For pointer-to-member functions you have to declare the type of the
                          object that you will call the function for. The part after :: does not need to be a member of
                          the class, but it is the name of the declaration (variable or typedef name).

                          typedef int (*some_func_t)(FooClass* );
                          typedef int (FooClass::*some_member_func_t);

                          some_func_t           func        = &SomeGlobalFunction;
                          some_member_func_t    member_func = &FooClass::SomeFunction;

                          thanks for this one, I wasn't aware of that actually (or misinterpreted that is was only a declaration name). This is still nightmare syntax and I hate C++ for it as it confuses me 😠 😂

                          1 Reply Last reply Reply Quote 0
                          • H
                            Helper
                            last edited by

                            On 10/09/2014 at 01:31, xxxxxxxx wrote:

                            Originally posted by xxxxxxxx

                            However, I have definetly not taken into the account the GetNodeData call as you have it. This is a potential gap in my code!!
                            Thanks!

                            Yes, yes, yes! Thanks so much Niklas. This little thingy seems to have been the culprit!! If I change the code to   
                            (((const MyHook\* )this->GetNodeData())->\*(vlib->get_value))(); 
                              
                            then it works!! I now get the correct value :) Of course it then works. It was stupid of me to cast directly to the SceneHookData without using GetNodeData...sigh, I need more sleep!  
                            I will change the other code of mine and see if this works for the other member functions I have as well, but you definetly deserve a beer (was trinkt man bei euch so?)! ;)  
                              
                            I report back if everything works now as expected  
                            
                            1 Reply Last reply Reply Quote 0
                            • H
                              Helper
                              last edited by

                              On 10/09/2014 at 04:24, xxxxxxxx wrote:

                              Yep, now it all works like a charm. 👍 it was well worth the discussion!

                              Sigh, such a minor mistake of mine cost me 3 days...always the same with this coding 😄

                              1 Reply Last reply Reply Quote 0
                              • First post
                                Last post