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.
    • ferdinandF
      ferdinand @yaya
      last edited by ferdinand

      Hello @yaya,

      please remember to open a new topic for new questions. I have forked your question, since it had factually not much to do with the old thread.

      @yaya said in OpenInputStream() works incorrect.:

      One last question: does the way to rewrite the .xdl64 plugin file during Cinema 4D is going to work exist? (OR at least replace it after Cinema 4D was closed?)
      Or I will be needed to ask user to install updates manually?

      Hm, I am not 100% sure if I do understand you correctly here, but I assume you want to hot-swap a plugin file while Cinema is running. You cannot do this at any point, because the OS will deny write access when the file is still in use by Cinema 4D. And the SDK also did never offer such functionality.

      Your best bet would be to do this in Plugin Message() when C4DPL_ENDPLUGINACTIVITY2 is being emitted. For all prior messages the plugins are still registered, i.e., Cinema 4D might have still the files loaded. But be aware: With C4DPL_ENDPLUGINACTIVITY2 you are deep in the shut-down process of Cinema 4D, which means you cannot handle anything that is a plugin (many custom data types are for example) and also stuff like the active document is not available anymore. If you plan on using the maxon API, relevant registries might have been already shut down at this point too. Your best bet is here to use as much of the std library as possible for the writing of files.

      I haven't done this myself yet, but the way I would try, is to use our APIs to download and unpack the data with while Cinema is running. And then store that data as a Char* or something like that. When C4DPL_ENDPLUGINACTIVITY2 is then being emitted, you can write the data. You can restart Cinema 4D with RestartApplication(), i.e., after you are done downloading, etc., you can invoke a restart with that function, so that the plugin can be replaced. Depending on what you use in std, you might have to provide different code for Windows and MacOS.

      Cheers,
      Ferdinand

      MAXON SDK Specialist
      developers.maxon.net

      Y 1 Reply Last reply Reply Quote 0
      • 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