SOLVED Replace Plugins in a Running Cinema 4D Instance

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 .

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.

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

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;
}

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/Cinema4DCPPSDK/html/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?

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.

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

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

This post is deleted!

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/Cinema4DCPPSDK/html/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());

😄

This post is deleted!