Passing Commandline args?



  • On 29/12/2014 at 17:34, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   13 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    Hi,
    I've been trying to understand how to pass command line arguments to C4D in C++. But nothing I'm trying is working.

    Every time I try to pass a value to args->argv _C4D crashes when it starts.
    And this code that Maxon put there does not print anything no matter how I edit the code.

      case C4DPL_COMMANDLINEARGS:  
              {  
                  C4DPL_CommandLineArgs *args = (C4DPL_CommandLineArgs* )data;  
                               
                  for (LONG i=0;i<args->argc;i++)  
                  {                      
                      if (!args->argv[i]) continue;  
                        
                      if (!strcmp(args->argv[i],"--help") || !strcmp(args->argv[i],"-help"))  
                      {  
                          // do not clear the entry so that other plugins can make their output!!!  
                          GePrint("\x01-SDK is here :-)");  
                      }  
                      else if (!strcmp(args->argv[i],"-SDK"))  
                      {  
                          args->argv[i] = NULL;  
                          GePrint("\x01-SDK executed:-)");  
                      }  
                      else if (!strcmp(args->argv[i],"-plugincrash"))  
                      {  
                          args->argv[i] = NULL;  
                          *((LONG* )0) = 1234;  
                      }  
                  }  
              }  
              break;
    

    I'm reading how to use commandline arguments in raw C++ code. But they never seem to work in C4D. It always crashes.

    Can someone please shed some light how how these things work. And tell me how to pass values into them in C4D so that they print to the console when C4D launches?

    Thanks,
    -ScottA



  • On 29/12/2014 at 18:20, xxxxxxxx wrote:

    The fundamental thing is that command line arguments need to exist at the call to run C4D so that the command line executer can pass them into C4D.  I do not think that one can 'add' or 'change' command line arguments from a plugin since C4D has already started running.  Reading the information for C4DPL_COMMANDLINEARGS, it simply allows a plugin to parse the command line arguments.  You can't pass some to it or make alterations.  I suspect that your

    args->argv[i] _= NULL
    

    is  a no-no.

    You will need to pass the arguments in the command line (or in the Shortcut Target of the icon - in Windows, for instance), unfortunately.  Or, you need to write a system-dependent C++ program that runs C4D with the desired arguments and process-detaches so that your program can close while C4D continues to run.

    Also remember that argv[0] is always the executable (that is, "Cinema4D.exe --help" is argv[0] = "Cinema4D.exe" and argv[1] = "--help").
    _



  • On 29/12/2014 at 19:01, xxxxxxxx wrote:

    Hi Robert.

    The for() loop never returns any data inside of it.
    And I can't even get the default value in argv[0] to print without crashing.

      
          case C4DPL_COMMANDLINEARGS:  
              {  
                  C4DPL_CommandLineArgs *args = (C4DPL_CommandLineArgs* )data;  
                  GePrint(args->argv[0]); //<---crashes!!  
                  ...  
    

    args->argv[0] is a char array.
    I wonder if I need to cast it to as String type somehow to stop it from crashing?

    I don't understand how this example that Maxon wrote is suppose to help?
    The code never does anything! Confused

    In Python we can add data elements into the argv[] array like this:

    import c4d  
    import sys  
      
    def PluginMessage(id, data) :  
      
      if id==c4d.C4DPL_COMMANDLINEARGS:  
            
          #Create some arguments and assign values to them  
          myList = ['first', 33]  
          myValue = 199          
            
          #Assign the above arguments to argv  
          sys.argv = [myList, myValue]           
             
          #The total number of args  
          total = len(sys.argv)  
       
          #Get the arguments list in string format  
          #Print them to the console when C4D starts up  
          cmdargs = str(sys.argv)  
          print "The total numbers of args: %d " % total  
          print "Args list: %s " % cmdargs          
            
          return True  
      
      return False
    

    How do I do this same thing with C++?

    -ScottA



  • On 29/12/2014 at 19:16, xxxxxxxx wrote:

    A simple observation: you don't check that 'data' is not NULL (neither does the example code - shame).  This is something I do for all data coming into Message() in my plugins, for example.  The data should exist but best to check nonetheless.  It may be as simple as that and then you need to find out why it is NULL if that is the case.

    If it is non-null, then I would print out the args->orig to see the entire command line string.

    I do *love* the fact that the example of this in main.cpp for the cinema4dsdk is commented out.  Not very reassuring.  We might need to wait for an 'official' response to know the facts here.



  • On 29/12/2014 at 19:29, xxxxxxxx wrote:

    Quick news: If there are *NO* arguments, C4DPL_COMMANDLINEARGS *never* gets called.  Arguments must exist and it appears that the executable (argv[0]) is automatically stripped.  So, I called C4D with "_<_path_>_/Cinema4D.exe" --hello and "--hello" was printed with GePrint(args->orig).  Therefore I would definitely check for data != NULL and make sure to have arguments on the command line.  Do not understand your crash though.  I did not crash in either case (no argument or an argument with the modification in the example code).  Even using "-SDK" worked.  As per the example code, I would 'return True;' instead of using break and returning False.



  • On 29/12/2014 at 19:42, xxxxxxxx wrote:

    As usual. I have no idea what you're saying.LOL
    You called C4D with <path>/ .... <--- Ummm  whut? Wacko

    -ScottA

    Oh wait...you mean the path that's in your icon that launches C4D?
    I tried adding --hello and the used this:
    if (!strcmp(args->argv[0], "--hello") )  GePrint(args->argv[0] );

    It prints ok to the console now. But it also gives an unknown arguments error too



  • On 29/12/2014 at 20:10, xxxxxxxx wrote:

    That is okay.  I think that is just an automatic response to an 'unknown' argument.  You will need to 'parse' (and possibly return True) it for it be considered a 'known' argument.  Now you are getting there. :)



  • On 29/12/2014 at 20:14, xxxxxxxx wrote:

    Thanks for the help Robert.
    I have added a -hello argument to the "target" field in my C4D desktop icon.
    And this code prints it in the console when C4D launches

           case C4DPL_COMMANDLINEARGS:  
             {  
                 C4DPL_CommandLineArgs *args = (C4DPL_CommandLineArgs* )data;  
      
                  for (LONG i=0;i<args->argc;i++)  
                 {                      
                     if (!args->argv[i]) continue;  
      
                     if (!strcmp(args->argv[i],"-hello"))  
                     {  
                          args->argv[i] = NULL;  //Kills the unknown argument console error  
                          GePrint("found -hello argument in the C4D icon taget field");             
                     }  
              }  
              break;
    

    But now how do I get the data from some other source like that python file?
    And how do I use this kind of thing: *((LONG* )0) = 1234;
    Usually this kind of code is used to cast void *data to a  LONG data type.
    But how do I use this with command line arguments?

    -ScottA



  • On 30/12/2014 at 05:32, xxxxxxxx wrote:

    Hello,

    when you pass the command line argument " -plugincrash " the line

      
    *((Int32* )0) = 1234;  
    

    will – as the name suggests – cause a crash (as you assign a value to a nullptr). What do you mean with "how do I get the data from some other source like that python file?"

    best wishes,
    Sebastian



  • On 30/12/2014 at 08:25, xxxxxxxx wrote:

    Hi Sebastian.
    I'm trying to understand what use these command line args can be.
    It's been said that it can be used to communicate with other programs. But I don't understand how that works?

    I did finally manage to figure out how to insert values into the args array:

    //Add -a1 and -a2 arguments to the "target" field in your C4D desktop icon  
    //This code assigns values to them and prints it in the console when C4D launches  
      
          case C4DPL_COMMANDLINEARGS:  
          {  
              char *myString = "Text is fun";  
              LONG myValue = NULL;  
      
              C4DPL_CommandLineArgs *args = (C4DPL_CommandLineArgs* )data;  
      
              for (LONG i=0;i<args->argc;i++)  
              {                      
                  if (!args->argv[i]) continue;  
      
                  //If this argument is found in the program's shortcut  
                  if (!strcmp(args->argv[i],"-a1") || !strcmp(args->argv[i],"-a2"))  
                  {  
                      args->argv[i] = NULL;  //Kills the "unknown argument" console error  
      
                      GePrint("found -a1 and -a2 arguments in the C4D icon's target field");  
      
                      //This puts the myString char value into the args array at index 0  
                      args->argv[0] = myString;  
                             
                      //This puts numbers (as chars) into the args array at index 1  
                      char *myArr = {"5555"};  
                      args->argv[1] = myArr;  
      
                      //This will convert the chars to a LONG if needed                          
                      String s = String(myArr, STRINGENCODING_8BIT);                          
                      GeData num = StringToNumber(s, FORMAT_LONG, NULL, NULL);  
                      myValue = num.GetLong();  
                  }  
      
                  //Finally...Print all the values we stored in the args array when C4D launches  
                  GePrint("args[] index# " + LongToString(i) + " : " + args->argv[i]);  
              }  
                    
          }  
          break;
    

    I'm still missing the big picture though.
    How can doing this allow me to communicate with other programs?

    -ScottA



  • On 31/12/2014 at 08:34, xxxxxxxx wrote:

    Hello,

    Computers can execute computer programs. One way to interact with your computer is the command line (like cmd.exe on windows, or   the terminal on mac).

    Using the command line you can start and use computer programs. If it is a well known program it's enough to call the program by it's name. For other programs you have to call the "exe" file.

    For example you can call "tracert www.plugincafe.com". This will call the program "tracert". The string "www.plugincafe.com" is the first argument of this call, so it is a command line argument. You can also start Cinema from the command line; navigating to the Cinema folder and calling "CINEMA 4D.exe".

    So when you start a program (using a double click on an icon or starting a program from another program) you can hand over command line arguments that will tell the computer program something. The list of command line arguments can be found in an array that is handed to the program in it's main function (like this). So adding anything to that array inside you program is not really useful.

    best wishes,
    Sebastian



  • On 31/12/2014 at 11:17, xxxxxxxx wrote:

    I've been searching around the web for the possible uses for these things. But the only things I've seen them used for are:
    -To set options when a program launches
    -To launch another program at the same time

    I personally don't consider launching another application as "communication" with it.
    So once again. I think I'm a victim of misleading terms.
    To me. The word "communication" means that the two programs can share data with each other.
    Like for example. When using pipes.

    I've been looking for a way to get two programs to really "communicate" with each other easier than using clumsy things like pipes and ports. And I was hoping this might be an option.
    I'm still trying to figure out how to get a Qt gui to communicate with C4D.
    But sadly, this is another dead end.

    I did learn something new from this though.
    These commandline args are good for creating launch options for C4D. Like letting you launch to a custom layout. So it wasn't a complete waste of time.

    //This is how to set a custom layout when C4D launches using a commandline argument  
    //The arg -Lscripting needs to be added to your C4D desktop icon's target field  
      
      case C4DPL_COMMANDLINEARGS:  
      {  
          C4DPL_CommandLineArgs *args = (C4DPL_CommandLineArgs* )data;  
      
          for(LONG i=0;i<args->argc;i++)  
          {                      
              if(!args->argv[i]) continue;  
      
              //If there's an argument named -Lscripting in your C4D desktop icon's target field  
              if(!strcmp(args->argv[i],"-Lscripting"))  
              {  
                  args->argv[i] = NULL;  //Kills the unknown argument console error  
                            
                  //Look for a custom layout named "scripting.l4d" in the AppData's library\layout folder  
                  //If it exists then set this layout when C4D launches  
                  BaseDocument *doc = GetActiveDocument();  
                  Filename file = GeGetC4DPath(C4D_PATH_LIBRARY_USER) + "/layout/scripting.l4d";   
                  Bool fileExists = GeFExist(file, FALSE);  
                  if(fileExists) LoadFile(file);  
                  else GePrint("Layout file was not found!!");  
              }  
              else GePrint("-Lscripting Commandline Arg Was Not Found!");  
      
          }break;
    

    Thanks for the help,
    -ScottA


Log in to reply