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

    Replace Plugins in a Running Cinema 4D Instance

    Cinema 4D SDK
    c++ r23 windows macos
    3
    12
    2.5k
    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.
    • Y
      yaya @ferdinand
      last edited by yaya

      Thank you @ferdinand . Sorry for my confused explanation, but yes, you understand perfectly correctly: I need to update the plugin file on the clients machine when the update-file is ready on my web-server.
      Right now I am able to send the message into my plugin instance from my server. My plugin listening my web-server and in some moment receives the message that the update is available. When plugin instance got this message, it starts the code function quoted above (i.e download the new .xdl64 file).

      So I can build the updates system through the notification to the client with the request to install this update manually. But I want to make it more easily and unnoticed by the client.

      Right now I've tried to simple replace my plugin-file (.xdl64) during C4DPL_ENDPLUGINACTIVITY2 via

      std::filesystem::copy_file(from, to, overwrite_existing);
      

      But I got the error and had not success.
      It seems that the .xdl64 file is still in use when C4DPL_ENDPLUGINACTIVITY2 make a call. During debugging I just got an error from <filesystem> and "plugin.xdl64" remain the same, which is understandable if the file is still in use:)

      So I will try your advice with the storing the data from new one .xdl64 to a Char*. But I have a doubt will it help if the .xdl64 is still busy during C4DPL_ENDPLUGINACTIVITY2.

      Thank you again @ferdinand .

      1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand
        last edited by ferdinand

        Hello @yaya,

        what you could try instead is try to rename the plugin files instead of overwriting them. I.e., simply rename myplugin.xdl64 to myplugin.old (or something like that) and then write your new data to myplugin.xdl64 and restart Cinema 4D. In in the startup of Cinema you can then remove all myplugin.old since they are the not in use anymore. This is how our CV-Toolboxd does it. This is however a Python plugin and Python can sometimes be weird with its file access. I only spoke yesterday after I did answer your posting with the author, sorry πŸ™‚

        Storing stuff as Char* won't help when you have no file access. I just mentioned this so that you do not rely on some fancy data structure which does not work anymore so deep down in the shutdown process.

        Cheers,
        Ferdinand

        MAXON SDK Specialist
        developers.maxon.net

        Y 1 Reply Last reply Reply Quote 0
        • Y
          yaya @ferdinand
          last edited by yaya

          Hi @ferdinand
          I've tried your advice with renaming the file. But it is still the same : (
          Am I doing it in a way it is intended?
          (this func is called when the C4DPL_ENDPLUGINACTIVITY2 occurs )

          Bool WriteUpdates()
          { 
          	Filename old_fn;	 
          	old_fn = GeGetPluginPath();
          	old_fn += Filename{ "firstplugin.xdl64" };
          	AutoAlloc<BaseFile> file;
          	if (file == nullptr)
          		return false;
                                         // if I change FILEOPEN::READ to WRITE, I get the error 
          	if (!file->Open(old_fn, FILEOPEN::READ , FILEDIALOG::ANY, BYTEORDER::V_INTEL, MACTYPE_CINEMA, MACCREATOR_CINEMA))
          		return false;
          
          	Filename new_fn;
          	new_fn = GeGetPluginPath();
          	new_fn += Filename{ "firstplugin.old" };
          	file->WriteFilename(new_fn); // here I got an error
          
                  // After that I`ve tried this line (with changing Alloc to Hyperfile), but also got an error
                  GeFKill(old_fn, GE_FKILL_FORCE); 
           
          	return true;
          }
          
          Y 1 Reply Last reply Reply Quote 0
          • Y
            yaya @yaya
            last edited by yaya

            Actually, after a lot of debugging I can see that the C4DPL_ENDPLUGINACTIVITY2 is called before the plugin registration destroyed. Contrary to the statement here: https://developers.maxon.net/docs/cpp/2023_2/group___c4_d_p_l___m_e_s_s_a_g_e_s.html#ga76cde585e6d5b223b10edcb6591a60ac
            After C4DPL_ENDPLUGINACTIVITY2 case sends its end
            we go to the c4d_pmain.cpp, where c4d starts to free the plugin resources:

            C4D_MAIN
            {
            	static Int32 init_count = 0;
            
            	switch (action)
            	{
            case C4DPL_END:
            			init_count -= 1;
            			if (init_count == 0)
            			{
            				PluginEnd();
            				FreeResource();
            				DeleteObj(path_storage);
            			}
            			return 1;
            

            So before that last line it is impossible to replace the plugin file. But after that line we don't go back anymore to our plugins functions where "replace" function exists.

            Maybe I am trying to do it entirely in a wrong way? And there is more smart way how others do the update system for their plugins?

            1 Reply Last reply Reply Quote 0
            • kbarK
              kbar
              last edited by

              From your C++ plugin call Python code to install your new plugin. Python doesn’t care if the file is in use so you can do what you want to it. I personally rename the existing ones then install the new one and when C4D is shut down I delete any renamed files.

              https://www.gamelogicdesign.com
              https://www.plugins4d.com

              Y 1 Reply Last reply Reply Quote 1
              • Y
                yaya @kbar
                last edited by yaya

                @kbar thanks for advice.
                Do you rename and delete in your case the .xdl64 file? Or the .pyp/.pypv ?

                1 Reply Last reply Reply Quote 0
                • ferdinandF
                  ferdinand
                  last edited by ferdinand

                  Hello @yaya,

                  I think what @kbar meant was that he uses a Python plugin to do the updating/replacing because of the non-strict manner Python does enforce read and write access to files (which was what I meant with "Python being weird with its file access" in may last posting). So, you write a Python plugin which does either download and swap or just swap xdl64 files by renaming them.

                  What you could also try when you do not want to give up immediately on C++, is to reverse the idea. So you download your plugin, call it myPlugin.new and on startup C4DPL_STARTACTIVITY you could try if you have write access for renaming myPlugin.xdl64.

                  Cheers,
                  Ferdinand

                  MAXON SDK Specialist
                  developers.maxon.net

                  1 Reply Last reply Reply Quote 1
                  • Y
                    yaya
                    last edited by yaya

                    This post is deleted!
                    1 Reply Last reply Reply Quote 0
                    • Y
                      yaya
                      last edited by yaya

                      Oh! Forget guys my message above!

                      The calling of Python code from C++ plugin in @kbar 's advice does the trick! πŸ™‚

                      If someone from the future who will read this thread will need the code example, I just use the code snippet from here: https://developers.maxon.net/docs/cpp/2023_2/page_maxonapi_python.html

                      and feed to it this code:

                      // call it from somewhere
                      String code = "import c4d\nimport maxon\nimport os    ";
                              code+= "\n\nprint(f'This is simple message')";
                              code += "\nos.rename('C:/Code/sdk/plugins/myPlugin/myPlugin.xdl64', 'C:/Code/sdk/plugins/myPlugin/old_myPlugin.old')"; 
                              
                      ExecutePythonScript(code, GetActiveDocument());
                      

                      πŸ˜„

                      1 Reply Last reply Reply Quote 1
                      • Y
                        yaya
                        last edited by

                        This post is deleted!
                        1 Reply Last reply Reply Quote 0
                        • First post
                          Last post