Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Need help embedding python script in c++


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
6 replies to this topic

#1 Vortez   Crossbones+   -  Reputation: 2705

Like
0Likes
Like

Posted 10 March 2014 - 08:06 AM

Hi, i want to learn how to use a simple python script from c++ but the documentation is a little bit lacking imo. So far i looked here and here, but it's not very clear how it work. For example, do i use PyRun_SimpleString() or PyRun_String()? What's the difference between the two?

 

What im trying to do is, i have this program that can rename files using lua scripts, and it work perfectly, and i now want to add python as another option to the mix. The job of the script is simple, call a function called convert() that take a given filename as a string and return a modified filename. That way i can rename a batch of files based on a simple script. In lua i had to use globals since trying to push a string before the function call caused problem randomly so if i could do the same in python that would be great.

 

That's the code im trying to make work (work in progress from my lua code, i want to replace the remaining lua code for python code)

#include "PythonPlugin.h"
#include <string>

string LanguageName = "";

// Those are defined in the script, i need a way to access them
string ScriptName = "";
string InitialDirectory = "";

/**************************************************
main procedure.....................................
**************************************************/
BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fdwreason, LPVOID lpReserved)
{
    switch(fdwreason)
	{
    case DLL_PROCESS_ATTACH: InitializePython(); break;
    case DLL_PROCESS_DETACH: ShutdownPython();   break; 
    case DLL_THREAD_ATTACH:  break;
    case DLL_THREAD_DETACH:  break;
    }
    return TRUE;
}

///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////

void InitializePython()
{
	Py_Initialize();
}

void ShutdownPython()
{
	Py_Finalize();
}

///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////

char* EXP_FUNC _GetLanguageName()
{
	LanguageName = "Python";
	return (char*)LanguageName.c_str();
}

///////////////////////////////////////////////////////////////////////////////////////////////

bool EXP_FUNC _LoadScript(char *txt)
{
	//return PyRun_SimpleString(txt) == ;
	return false;
}

///////////////////////////////////////////////////////////////////////////////////////////////

char* EXP_FUNC _GetScriptName()
{
	//ScriptName = LuaScript.GetGlobalString("ScriptName");
	//return (char*)ScriptName.c_str();
	return NULL;
}

///////////////////////////////////////////////////////////////////////////////////////////////

char* EXP_FUNC _GetInitialDirectory()
{
	//InitialDirectory = LuaScript.GetGlobalString("InitialDirectory");
	//return (char*)InitialDirectory.c_str();
	return NULL;
}

///////////////////////////////////////////////////////////////////////////////////////////////

bool EXP_FUNC _Convert(char *in, char *out, char *err)
{
	/*bool res = false;
	ZeroMemory(out, MAX_PATH);
	ZeroMemory(err, 1024);

	LuaScript.SetGlobalString("Input", in); 
	if(LuaScript.SafeCallFunction("Convert", err)){
		
		string Output = LuaScript.GetGlobalString("Output");

		res = Output.length() > 0;
		if(res){
			memcpy(out, Output.c_str(), Output.length()); 
		} else {
			sprintf(err, "%s", "Error: Convert() returned null output.");
		}
	}

	return res;*/
	return false;
}


Edited by Vortez, 10 March 2014 - 08:23 AM.


Sponsor:

#2 Vortez   Crossbones+   -  Reputation: 2705

Like
0Likes
Like

Posted 10 March 2014 - 08:24 AM

For example, this is a lua script that rename a batch of files with randoms 16 alphanumerics characters, but keep the extention intact. Notice the globals at the start, i want to be able to access those after calling the Convert function from the script.

ScriptName = "Random"
InitialDirectory = ""

Input = ""
Output = ""

--------------------------------------------------------------------------------------------------------------------
-- Return the char at positon i in s
--------------------------------------------------------------------------------------------------------------------
function GetChar(s, i)
	return string.sub(s, i, i)
end

--------------------------------------------------------------------------------------------------------------------
-- tell if a sub string is withing a string at a given position
--------------------------------------------------------------------------------------------------------------------
function ConcatStr(s1, s2)
	return string.format("%s%s", s1, s2)
end

--------------------------------------------------------------------------------------------------------------------
-- Return the extention of a given file name
--------------------------------------------------------------------------------------------------------------------
function GetExtention(s)
	local sLen = string.len(s)

	local found = false
	local tmp = ""
	local i = sLen
	local j = 0
	while(i > 1) do
		tmp = ""
		tmp = string.sub(s, i, i)
		if(tmp == ".") then
			found = true
			break
		end
		i = i - 1;
	end;

	tmp = ""
	if(found == true) then
		while(i <= sLen) do
			tmp = tmp..string.sub(s, i, i)
			i = i + 1;
		end;
	end;

	return tmp
end


--------------------------------------------------------------------------------------------------------------------
-- Convert the file name (Called from c++)
--------------------------------------------------------------------------------------------------------------------
function Convert(FileName)
	local FileName = Input
	Output = ""

	-- Extract the file extention
	local ext = GetExtention(FileName)

	local tmp = ""
	local i = 1;
	local r = 0
	local c = ""

	while(i <= 16) do

		local k = math.random(2)
		if(k == 1) then
			r = math.random(65,90)
			c = string.char(r)
			tmp = string.format("%s%s", tmp, c)
		end
		if(k == 2) then
			r = math.random(48,57)
			c = string.char(r)
			tmp = string.format("%s%s", tmp, c)
		end

		i = i + 1
	end

	Output = string.format("%s%s", tmp, ext)

	print(Output)
end

math.randomseed(os.time())

That's just an example though, the script can do whatever it want.

 

For Example, a script that do nothing

ScriptName = "Example"
InitialDirectory = ""

Input = ""
Output = ""

--------------------------------------------------------------------------------------------------------------------
-- Convert the file name (Called from c++)
--------------------------------------------------------------------------------------------------------------------
function Convert(FileName)
	Output = Input
	print(Output)
end

I can make a similar python scripts, im just not sure how to start on the c++ side.

 

To resume, i need a way to:

 -Extract a string value to c++ from python script

 -Pass a string value from c++ to python

 -Load the script from a char*

 -Call the Convert function located in the script


Edited by Vortez, 10 March 2014 - 08:37 AM.


#3 Vortez   Crossbones+   -  Reputation: 2705

Like
0Likes
Like

Posted 10 March 2014 - 09:58 AM

The main problem im having so far is that all the examples seem to load the script from a file, but id like to be able to do it with a char* containing the entire script.

 

PyRun_SimpleString seem not well suited for what i want to do since it just run a single line of python script at once, or maybe i need to call that for each line of script?

Guess ill start experimenting.


Edited by Vortez, 10 March 2014 - 09:58 AM.


#4 ColinDuquesnoy   Members   -  Reputation: 1162

Like
1Likes
Like

Posted 10 March 2014 - 01:10 PM

I am a bit rusty on embedding python but I think PyRun_String should do what you want if you pass Py_eval_input or Py_file_input for the start parameter.



#5 DoctorGlow   Members   -  Reputation: 912

Like
2Likes
Like

Posted 10 March 2014 - 02:21 PM

Probably not a help with your current problem, but I have used boost python on several occasions embedding in different professional engines and always had good experience. Of course YMMV.



#6 Vortez   Crossbones+   -  Reputation: 2705

Like
0Likes
Like

Posted 10 March 2014 - 06:53 PM

Ok, after playing a bit with this and some extensive googling, i got this test code to work:

#include "Windows.h"
#include "stdio.h"

#include "Python.h"

UINT GetScriptSize(char *pFileName)
{
	char Buf[MAX_PATH];
	ZeroMemory(Buf, sizeof(Buf));
	sprintf(Buf, "%s", pFileName);
    
	WIN32_FIND_DATA Data;
 	ZeroMemory(&Data, sizeof(WIN32_FIND_DATA));
        HANDLE h = FindFirstFile(Buf, &Data);
	if(h != INVALID_HANDLE_VALUE)
		FindClose(h);

	return Data.nFileSizeLow;
}

bool ReadScript(char *pFileName, char *pScriptBuffer)
{
	const int LineBufSize = 4096;
	
	FILE *f = fopen(pFileName, "rt"); 
	if(f){
		char txtline[LineBufSize];
		ZeroMemory(txtline, LineBufSize);
		
		while(fgets(txtline, LineBufSize, f) != NULL)
			strcat(pScriptBuffer, txtline);

		fclose(f);
		return true;
	}

	return false;
}

int main()
{
    // Script file name
    LPCSTR FileName = "C:\\Temp\\Batch Files Renamer\\ScriptTest.py";

    // Extract the text from the file
    const int ScriptBufSize = GetScriptSize((char*)FileName)+1;
    char *pScriptBuffer = new char[ScriptBufSize];
    ZeroMemory(pScriptBuffer, ScriptBufSize);
    
    ReadScript((char*)FileName, pScriptBuffer);

    // Initialize Python
    Py_Initialize();

    // Create module and dictionary
    PyObject* module = PyImport_AddModule("__main__");
    PyObject* dictionary = PyModule_GetDict(module);

    // Run the script
    PyRun_String(pScriptBuffer, Py_file_input, dictionary, dictionary);

    // Call the Convert() function
    PyObject* pFunc = PyObject_GetAttrString(module, "Convert");
    PyObject* result = PyObject_CallObject(pFunc, 0);

    // Retreive the Output variable
    PyObject* output = PyDict_GetItemString(dictionary, "Output");
    PyObject *outconv = PyUnicode_AsEncodedString(output, "utf-8", "Error ~");
    const char *out = PyBytes_AS_STRING(outconv);

    // Print it
    printf("%s\n", out);

    // Shutdown Python
    Py_Finalize();

    // Free allocated memory
    if(*pScriptBuffer)
        delete [] pScriptBuffer;

    // Wait before closing the console window
    system("PAUSE");

    return 0;
}

Now i just need to clean that up and add this to my real code. Thx for pointing out PyRun_String. I still need to find how to modify the "Input" variable in the script but that shouldn't be too hard. Forget that, it works now.


Edited by Vortez, 10 March 2014 - 07:30 PM.


#7 EvanZhao   Members   -  Reputation: 106

Like
0Likes
Like

Posted 11 March 2014 - 01:47 AM

I use ffpython for embeding & extending.

https://github.com/fanchy/ffpython

support python 2.x, only one header files.






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS