Command Line problem, Process not destroyed


#1

I’m writing some KeyGen for ShareIT, which runs as a command line on their servers. The keygen now works, but after calling it, its process stays in memory (you can see it in the Windows Task Manager), although otherwise everything works fine. What could be the reason for this? Here’s the code:

#include "juce.h" 

// the licese text to be encoded starts with this
#define BASETEXT T("licensed to: ")

// private key
#define PRIVATEKEY T("xxx (removed) xxx")

// error result codes supported by element 5
#define  ERC_SUCCESS       0
#define  ERC_SUCCESS_BIN   1
#define  ERC_ERROR        10
#define  ERC_MEMORY       11
#define  ERC_FILE_IO      12
#define  ERC_BAD_ARGS     13
#define  ERC_BAD_INPUT    14
#define  ERC_EXPIRED      15
#define  ERC_INTERNAL     16


//============================================================================== 
class AppClass : public JUCEApplication 
{ 
  
public: 
    //============================================================================== 
    AppClass() 
    {     
    } 

    ~AppClass() 
    {    
    } 

    //============================================================================== 
    void initialise (const String& commandLine) 
    { 
		StringArray args;
		int nArgs=args.addTokens(commandLine,true);

		// check if number of arguments is 3
		if (nArgs!=3)
		{
			setApplicationReturnValue(ERC_BAD_ARGS); // BAD ARGUMENTS
			if (nArgs>=2)
				errOut(args[1],T("Bad amount of arguments (not 3)!"));
			return;
		}

		// check if arg1 (input) file exists
		if (!File(args[0]).exists())
		{
			setApplicationReturnValue(ERC_FILE_IO); // BAD ARGUMENTS
			errOut(args[1],T("Input file not found!"));
			return;
		}

		// get input file and make a StringArray of it
		const String in=File(args[0]).loadFileAsString();
		StringArray lines;
		int nLines=lines.addLines(in);

		// check if all needed arguments are to be found in the lines stringarray
		String name=getArgument(lines,T("REG_NAME"));
		if (name==String::empty)
		{
			setApplicationReturnValue(ERC_BAD_INPUT);
			errOut(args[1],T("REG_NAME not found!"));
			return;
		}
	
		// get city of customer
		String city=getArgument(lines,T("CITY"));
		if (city==String::empty)
		{
			setApplicationReturnValue(ERC_BAD_INPUT);
			errOut(args[1],T("CITY not found!"));
			return;
		}

		// get country of customer
		String country=getArgument(lines,T("COUNTRY"));
		if (country==String::empty)
		{
			setApplicationReturnValue(ERC_BAD_INPUT);
			errOut(args[1],T("COUNTRY not found!"));
			return;
		}

		// create license text
		String RSAInput=BASETEXT;
		RSAInput+=name+T(", ")+city+T(", ")+country;
		String RSAOutput=RSAencode(RSAInput, PRIVATEKEY);
		
		// try to write output files
		if (!writeFile(args[1],T("application/octet-stream:Transient Shaper.lic")))
		{
			setApplicationReturnValue(ERC_FILE_IO);
			return;
		}

		if (!writeFile(args[2],RSAOutput))
		{
			errOut(args[1],T("Could no write second file (argument 3)!"));
			setApplicationReturnValue(ERC_FILE_IO);
			return;
		}

		setApplicationReturnValue(ERC_SUCCESS_BIN);
    } 
	//============================================================================== 
	void errOut(String filename, String errString)
	{
		writeFile(filename, errString);
	//	DBG(errString);
	}
	//============================================================================== 
	String getArgument(StringArray arr,String s)
	{
		for (int i=0; i<arr.size(); i++)
			if (arr[i].startsWith(s))
				return arr[i].fromFirstOccurrenceOf(s,false,false);
	
		return String::empty;
	}	
	//==============================================================================
	String RSAencode(String s, String privateKeyText)
	{
		RSAKey privateKey=RSAKey(privateKeyText);

		int nn=s.length()+1;
		const char *ps=(const char*)s;
		MemoryBlock b((const void*)ps,nn);
		int test=b.getSize();
		BitArray bi;
		bi.loadFromMemoryBlock(b);

		privateKey.applyToValue(bi);

		String encoded=bi.toString(16);

		return encoded;
	}
	//============================================================================== 
	bool writeFile(String filename, String text)
	{
		File f=File(filename);
		if (f.exists())								// if the file exists..
			if (!f.deleteFile()) return false;		// .. try to delete it
		
		if (f.create())								// try to create file
			return f.appendText(text);				// and try to append text
	
		return false;								// error
	}

	//============================================================================== 
    void shutdown() 
    { 
    
    } 

    //============================================================================== 
    const String getApplicationName() 
    { 
      return T("none"); 
    } 
	//============================================================================== 
    const String getApplicationVersion() 
    { 
      return T("0.1"); 
    } 
	//============================================================================== 
    bool moreThanOneInstanceAllowed() 
    { 
      return true; 
    } 
	//============================================================================== 
    void anotherInstanceStarted (const String& commandLine) 
    { 
    } 
	//============================================================================== 
}; 


//============================================================================== 
// This macro creates the application's main() function.. 
START_JUCE_APPLICATION(AppClass) 

#2

If you’re running as a command line, you’d really be better off using a normal main() function to run it. If you use an app class, you need to make sure you call JUCEApplication::quit() or it’ll go off into the dispatch loop.


#3

So just adding quit() at the end of initialize() will do the job?

Concerning using main: I thought that when using main(), JUCE will not be initialised, and there could be some errors resulting out of that?


#4

yes, quit() will do the job, as long as you make sure you always call it. But it’s a waste - main() is a simpler way. You do have to initialise the juce stuff, but it’s easy - have a look at binarybuilder.


#5

Ok, used quit(). As long as it works, I’m ok with it. This should be the first and last command line app I’ll ever have to write anyway .)


#6

Perhaps (entirely redundant, but for ‘a laugh’) there could be a JUCECommandLineApplication base for such things, so you never have to touch the juce initialisation stuff.