calling class method requiring LPCSTR (MFC)

Started by
6 comments, last by WitchLord 19 years, 9 months ago
Hello, I'm french and using AngelScript for 3 days now because I get enought of lua that is good be not as easy to integrate as AngelScript is event with lua++. I am using AngelScript to execute "something" using MFC CDatabase class, and other. In CDatabase class you've got a method : BOOL CDatabase::OpenEx(LPCTSTR, DWORD) That I have translated to : in_pAsEngine->RegisterObjectMethod("CDatabase", "int OpenEx(bstr, uint32)",asMETHOD(CDatabase,OpenEx), asCALL_THISCALL); And used un AngelScript as : CDatabase *pDatabase = CDatabase_new(); int iRet; iRet = pDatabase->OpenEx("DSN=MyDatabase;", 0); CDatabase_delete(pDatabase); This work fine, really fine ! The probelm comes when the application terminate. The bstr that has been sent to CDatabase::OpenEx is not freed. Question : Is this normal ? Do I make some mistake in then RegisterObjectMethod declaration ? By the way, I have found a workaround as AngelScript is delivered with the source code : in bstr.cpp : #include <map> using namespace std; map<asBSTR, asBSTR> g_mapBstrPointers; asBSTR asBStrAlloc(asUINT length) { unsigned char *str = new unsigned char[length+4+1]; *((asUINT*)str) = length; // Length of string str[length+4] = 0; // Null terminated -----------------------> This is new g_mapBstrPointers.insert(map<asBSTR, asBSTR>::value_type(str, str)); ------------------------ return str + 4; } void asBStrFree(asBSTR str) { if( str == 0 ) return; unsigned char *p = str-4; ------------------------> This is new map<asBSTR, asBSTR>::iterator it; if ((it = g_mapBstrPointers.find(p)) != g_mapBstrPointers.end()) g_mapBstrPointers.erase(it); -------------------------- delete[] p; } ------------------------> This is new void asBStrCollectFree() { map<asBSTR, asBSTR>::iterator it; for (it = g_mapBstrPointers.begin(); it != g_mapBstrPointers.end(); it++) delete[] (it->second); g_mapBstrPointers.clear(); } -------------------------- Then in my application, AFTER having released the engine, i call asBStrCollectFree . Question : Is it good ? Thank's for any answer. Thank you Andreas for this library. AbrKen
Advertisement
You've registered the method correctly, although you might want to register it with a const bstr as the parameter.

The real problem is that since the method takes a bstr by value the engine makes a copy of the string before passing it to the method. The method will be the owner of this string and should call asBStrFree() on it before returning.

I realise that this might not be possible since it is a library function, but you can write a wrapper function to handle it for you. If you do I suggest you do it like this:

BOOL WrapCDatabaseOpenEx(asBSTR *bstr, DWORD flags, CDatabase *obj)
{
// No need to free the bstr since we receive it by reference
return obj->OpenEx(*bstr, flags);
}

Register the wrapper function like this:

in_pAsEngine->RegisterObjectMethod("CDatabase", "int OpenEx(const bstr&, uint32)", asFUNCTION(WrapCDatabaseOpenEx), asCALL_CDECL_OBJLAST);

You don't have to change your script. The wrapper function will be called just like before, except that the bstr will be sent by reference. The engine will still be the owner of the bstr and will thus free it when it is no longer used.

Your solution, while working, may not be the best choice. The problem is that you only free the bstrs once you've finished all the work. You could potentially end up with a lot of unused memory in that map structure.

Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

The problem you are pointing about map growing is true, but at this time, it's enought.

I think i'm going to "rafine" the map code to have transaction that will give me the ability to rollback to certain point and this way free memory.

As a lazy programmer I don't think i will make wrapper function since i've got really a lot of methods using LPCSTR.

Thank you for your answer, it help.

Regards,
AbrKen.
It might be possible to define another string type for the scripts, one that don't make a copy when sending a char pointer to the host function. Though I'm not sure how exactly that would be done.

You could also define another type for char *, and write a function for asBSTR that returns it's char* without making a copy of it. This would however incomodate script writers.

If someone can come up with a better string class than asBSTR I would be very grateful if you let me know.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Now I'm ok with map that have transaction.

The only left "problem" is about using transaction.

This is an example that works fine :

if (iRet == 1) {
rSet.SetDatabase(myDb);
iRet = rSet.Open("SELECT * FROM PP_PARAMETRES", uiOpt, 0);
--Transaction Name must be allocated outside the transaction scope -------------------------------->
bstr bstrTrans = "TOTO";
-----------------------------------
if (iRet == 1) {
----------- Transaction Begin ------------------>
asBStrSetTransaction(bstrTrans);
while (rSet.IsEOF() == 0) {
CString csNom = rSet.GetString("PARAM_NOM");
bstr bstrNom;
string strNom;
bstrNom = csNom;
strNom = csNom;
bstrNom = strNom;
PrintTrace(csNom);
PrintTrace(bstrNom);
rSet.MoveNext();
}
------------ Transaction End ------------------>
asBStrFreeTransaction(bstrTrans);
----------- At this point, all temporary allocated asBSTR are freed, and transaction is back to global transaction -----------
rSet.Close();
}
string strNom;
strNom = "BIL";
iRet = rSet.Open("SELECT * FROM PP_PARAMETRES", uiOpt, 0);
rSet.Close();
}

As you can see there is a "little" to do but it works !

You can also see that CDatabase and CRecordset are fully integrated in AngelScript, also string and CString that are commonly MFC programmer tools !

What are the differences for registering the different string types? Are they all freed correctly after use? If you assign one to another, do they share memory or is the memory copied?

Which type do you recommend? Can you show us the code for registering it?

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game


Quote:What are the differences for registering the different string types?


First, I would like to say :
- I'm a lazy programmer.
- I don't like to reinvent wheel everyday.
Giving those facts why do I implemented CString and string in angel code ?
Because I didn't want to write wrappers for all of my (and other) class that use CString or string as parameter or return value.
Because using knowed objects is easy.

Why converting CString to asBSTR and vice versa ?
Because CString implement a lot of features that are very usefull (MakeUpper, ReverseFind, Replace, ...)

eg :
class CXmlValue : public CObject {public:	//! Nom de la Valeur	string m_strName,	//! Contenu de la valeur				 m_strValue;	CXmlValue();	CXmlValue(const CXmlValue &);	virtual ~CXmlValue();	const string &getName()const{ return m_strName ; };	const bool getValueAsBool()const;	const DWORD getValueAsDWORD()const;	const string &getValueAsString()const;	const CString getValueAsCString()const;	const CTime getValueAsDate(LPCTSTR in_szDateFormat, bool &out_bGoodFmt) const;	const CTime getValueAsTime(LPCTSTR in_szTimeFormat, bool &out_bGoodFmt) const;	void Serialize(CArchive &ar);	CXmlValue &operator =(const CXmlValue&);	bool operator ==(const CXmlValue&in_xmlValue) const {return (m_strName == in_xmlValue.m_strName && m_strValue == in_xmlValue.m_strValue); };	bool operator !=(const CXmlValue&in_xmlValue) const {return (m_strName != in_xmlValue.m_strName || m_strValue != in_xmlValue.m_strValue); };	DECLARE_SERIAL(CXmlValue);private:	string Uppercase(const string & in_str)const;};


As you can see this class is using both CString and string.

Quote:Are they all freed correctly after use?


Of course those objects are freed after use (It took me some time to understand how to make it, and after reading your AngelScript overview, i've made it).

Quote:If you assign one to another, do they share memory or is the memory copied?


No they are not sharing their values, copying is made.

Quote:Which type do you recommend?


I do recommend none of them. If you have, like me, reasons to use them, then, just do it, else forgget about them, especially with CString that are Windows only.

And finally, the implementation :

#define asMETHOD4(c,r,m,p) asSMethodPtr<sizeof(void (c::*)())>::Convert((r (c::*)p)(&c::m))extern asBSTR *asBStrCopy(const asBSTR *src, asBSTR *dst);///////////////////////////////////////////////////////////////////// string //void string_Constructor(string &o){	new (&o) string();}void string_Destructor(string &o){  o.~string();}void bstr2string(asBSTR &src, string &dst){	dst = (const char *)src;}void string2bstr(string &src, asBSTR &dst){	asBStrFree(dst);	// Make a copy of the source bstr	int len = src.size();	dst = asBStrAlloc(len);	memcpy(dst, src.c_str(), len);}void string2CString(string &src, CString &dst){	dst = src.c_str();}string *asStringCopy(const asBSTR *src, string *dst){	// Free the destination bstr	// Make a copy of the source bstr	TRACE("dst = %08lX %08lX %s %d\n", dst, dst->data(), dst->c_str(), dst->size());	int len = asBStrLength(*src);	char *srcc = new char[len+1];	memset(srcc, 0, len+1);	memcpy(srcc, (*src), len);	(*dst) = srcc;	delete[] srcc;	return dst;}string *asStringCopyString(const string *src, string *dst){	(*dst) = (*src);	return dst;}string *asStringCopyCString(const CString &src, string *dst){	(*dst) = src.operator LPCTSTR();	return dst;}string *asStringAppend(const asBSTR *other, string *self){	(*self) += (const char *)(*other);	return self;}string *asStringAppendString(const string *other, string *self){	(*self) += (*other);	return self;}string *asStringAppendBstr(string *self, const asBSTR *other){	(*self) += (const char *)(*other);	return self;}////////////////////////////////////////////////////////////////////////////////// CString proxy//void CString_Constructor(CString &o){	new (&o) CString();}void CString_Destructor(CString &o){  o.~CString();}void bstr2CString(asBSTR &src, CString &dst){	dst = (const char *)src;}void CString2bstr(CString &src, asBSTR &dst){	asBStrFree(dst);	// Make a copy of the source bstr	int len = src.GetLength();	dst = asBStrAlloc(len);	memcpy(dst, src.operator LPCTSTR(), len);}void CString2string(CString &src, string &dst){	dst = src.operator LPCTSTR();}CString *asCStringCopy(const asBSTR *src, CString *dst){	// Free the destination bstr	// Make a copy of the source bstr	TRACE("dst = %08lX %08lX %s %d\n", dst, dst->operator LPCTSTR(), dst->operator LPCTSTR(), dst->GetLength());	int len = asBStrLength(*src);	char *srcc = new char[len+1];	memset(srcc, 0, len+1);	memcpy(srcc, (*src), len);	(*dst) = srcc;	delete[] srcc;	return dst;}CString *asCStringCopyCString(const CString *src, CString *dst){	(*dst) = (*src);	return dst;}CString *asCStringCopyString(const string &src, CString *dst){	(*dst) = src.c_str();	return dst;}CString *asCStringAppend(const asBSTR *other, CString *self){	(*self) += (const char *)(*other);	return self;}CString *asCStringAppendCString(const CString *other, CString *self){	(*self) += (*other);	return self;}CString *asCStringAppendBstr(CString *self, const asBSTR *other){	(*self) += (const char *)(*other);	return self;}void PrintTrace(asBSTR s){	TRACE("bstr : %s\n", s);}void PrintTrace(CString s){	TRACE("CString : %s\n", s);}void PrintTrace(string s){	TRACE("string : %s\n", s.c_str());}void RegisterAsStringS(asIScriptEngine *in_pAsEngine){	if (in_pAsEngine == NULL)		return;	// Begin String stuff	in_pAsEngine->RegisterObjectType("CString", sizeof(string), asOBJ_IS_COMPLEX);	in_pAsEngine->RegisterObjectType("string", sizeof(string), asOBJ_IS_COMPLEX);	RegisterBStr(in_pAsEngine);	in_pAsEngine->RegisterTypeBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(string_Constructor), asCALL_CDECL_OBJLAST);	in_pAsEngine->RegisterTypeBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(string_Destructor), asCALL_CDECL_OBJLAST);	in_pAsEngine->RegisterTypeBehaviour("string", asBEHAVE_ASSIGNMENT, "string &f(const bstr &)", asFUNCTION(asStringCopy),      asCALL_CDECL_OBJLAST);	in_pAsEngine->RegisterTypeBehaviour("string", asBEHAVE_ASSIGNMENT, "string &f(const string &)", asFUNCTION(asStringCopyString),      asCALL_CDECL_OBJLAST);	in_pAsEngine->RegisterTypeBehaviour("string", asBEHAVE_ASSIGNMENT, "string &f(const CString &)", asFUNCTION(asStringCopyCString),      asCALL_CDECL_OBJLAST);	in_pAsEngine->RegisterTypeBehaviour("string", asBEHAVE_ADD_ASSIGN, "string &f(const bstr &)", asFUNCTION(asStringAppend),    asCALL_CDECL_OBJLAST);	in_pAsEngine->RegisterTypeBehaviour("string", asBEHAVE_ADD_ASSIGN, "string &f(const string &)", asFUNCTION(asStringAppendString),    asCALL_CDECL_OBJLAST);	in_pAsEngine->RegisterGlobalFunction("void bstr2string(bstr &, string &)", asFUNCTION(bstr2string), asCALL_CDECL);	in_pAsEngine->RegisterGlobalFunction("void string2bstr(string &, bstr &)", asFUNCTION(string2bstr), asCALL_CDECL);	in_pAsEngine->RegisterTypeBehaviour("CString", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CString_Constructor), asCALL_CDECL_OBJLAST);	in_pAsEngine->RegisterTypeBehaviour("CString", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CString_Destructor), asCALL_CDECL_OBJLAST);	in_pAsEngine->RegisterTypeBehaviour("CString", asBEHAVE_ASSIGNMENT, "CString &f(const bstr &)", asFUNCTION(asCStringCopy),      asCALL_CDECL_OBJLAST);	in_pAsEngine->RegisterTypeBehaviour("CString", asBEHAVE_ASSIGNMENT, "CString &f(const CString &)", asFUNCTION(asCStringCopyCString),      asCALL_CDECL_OBJLAST);	in_pAsEngine->RegisterTypeBehaviour("CString", asBEHAVE_ASSIGNMENT, "CString &f(const string &)", asFUNCTION(asCStringCopyString),      asCALL_CDECL_OBJLAST);	in_pAsEngine->RegisterTypeBehaviour("CString", asBEHAVE_ADD_ASSIGN, "CString &f(const bstr &)", asFUNCTION(asCStringAppend),    asCALL_CDECL_OBJLAST);	in_pAsEngine->RegisterTypeBehaviour("CString", asBEHAVE_ADD_ASSIGN, "CString &f(const CString &)", asFUNCTION(asCStringAppendCString),    asCALL_CDECL_OBJLAST);	in_pAsEngine->RegisterObjectMethod("CString", "int GetLength()",asMETHOD(CString,GetLength), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "int IsEmpty()",asMETHOD(CString,IsEmpty), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "void Empty()",asMETHOD(CString,Empty), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "int8 GetAt(int)",asMETHOD(CString,GetAt), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "void SetAt(int, int8)",asMETHOD(CString,SetAt), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "CString Mid(int)",asMETHOD4(CString,CString,Mid,(int) const), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "CString Mid(int, int)",asMETHOD4(CString,CString,Mid,(int,int) const), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "CString Left(int)",asMETHOD(CString,Left), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "CString Right(int)",asMETHOD(CString,Right), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "CString SpanIncluding(bstr)",asMETHOD(CString,SpanIncluding), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "CString SpanExcluding(bstr)",asMETHOD(CString,SpanExcluding), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "void MakeUpper()",asMETHOD(CString,MakeUpper), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "void MakeLower()",asMETHOD(CString,MakeLower), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "void MakeReverse()",asMETHOD(CString,MakeReverse), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "int Replace(bstr, bstr)",asMETHOD4(CString,int,Replace,(LPCTSTR, LPCTSTR)), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "int Replace(uint8, uint8)",asMETHOD4(CString,int,Replace,(TCHAR,TCHAR)), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "int Remove(uint8)",asMETHOD(CString,Remove), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "int Insert(int, bstr)",asMETHOD4(CString,int,Insert,(int, LPCTSTR)), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "int Insert(int, uint8)",asMETHOD4(CString,int,Insert,(int, TCHAR)), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "int Delete(int, int)",asMETHOD(CString,Delete), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "void TrimLeft(bstr)",asMETHOD4(CString,void,TrimLeft,(LPCTSTR)), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "void TrimLeft(uint8)",asMETHOD4(CString,void,TrimLeft,(TCHAR)), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "void TrimLeft()",asMETHOD4(CString,void,TrimLeft,()), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "void TrimRight(bstr)",asMETHOD4(CString,void,TrimRight,(LPCTSTR)), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "void TrimRight(uint8)",asMETHOD4(CString,void,TrimRight,(TCHAR)), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "void TrimRight()",asMETHOD4(CString,void,TrimRight,()), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "int Find(bstr, int)",asMETHOD4(CString,int,Find,(LPCTSTR,int) const), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "int Find(bstr)",asMETHOD4(CString,int,Find,(LPCTSTR) const), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "void SetAt(int, uint8)",asMETHOD4(CString,int,Find,(TCHAR, int) const), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "int Find(uint8)",asMETHOD4(CString,int,Find,(TCHAR) const), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "int ReverseFind(uint8)",asMETHOD(CString,ReverseFind), asCALL_THISCALL);	in_pAsEngine->RegisterObjectMethod("CString", "int FindOneOf(bstr)",asMETHOD(CString,FindOneOf), asCALL_THISCALL);	in_pAsEngine->RegisterGlobalFunction("void bstr2CString(bstr &, CString &)",asFUNCTION(bstr2CString), asCALL_CDECL);	in_pAsEngine->RegisterGlobalFunction("void CString2bstr(CString &, bstr &)",asFUNCTION(CString2bstr), asCALL_CDECL);	in_pAsEngine->RegisterGlobalFunction("void string2CString(string &, CString &)", asFUNCTION(string2CString), asCALL_CDECL);	in_pAsEngine->RegisterGlobalFunction("void CString2string(CString &, string &)",asFUNCTION(CString2string), asCALL_CDECL);	in_pAsEngine->RegisterGlobalFunction("void PrintTrace(bstr)", asFUNCTION((void(*)(asBSTR))PrintTrace), asCALL_CDECL);	in_pAsEngine->RegisterGlobalFunction("void PrintTrace(CString)", asFUNCTION((void(*)(CString))PrintTrace), asCALL_CDECL);	in_pAsEngine->RegisterGlobalFunction("void PrintTrace(string)", asFUNCTION((void(*)(string))PrintTrace), asCALL_CDECL);	in_pAsEngine->RegisterGlobalFunction("int MessageBeep(uint)", asFUNCTION(MessageBeep), asCALL_STDCALL);	in_pAsEngine->RegisterGlobalFunction("int MessageBox(uint32,bstr,bstr,uint)", asFUNCTION(MessageBox), asCALL_STDCALL);		// End String stuff}


asMETHOD4 macro has been copied from AngelScriptBind.

Then this are modifications made to bstr.cpp :

First the typedef and other vars :

typedef map<asBSTR, asBSTR> tplMapOfasBSTR;typedef map<CString, tplMapOfasBSTR> tplMapOfTransactionMapOfasBSTR;tplMapOfasBSTR g_mapBstrPointers;tplMapOfTransactionMapOfasBSTR g_mapTransBstrPointers;static bool g_bTransactionBstrPointersActive = false;static CString g_csActiveTransaction = _T("");bool asBStrCollectFreeTransaction(const int iTransactionId);void asBStrSetTransaction(const int iTransactionId);


The the registration (you MUST have RegisterObjectType CString and string BEFORE) :

	r = engine->RegisterTypeBehaviour("bstr", asBEHAVE_ASSIGNMENT, "bstr &f(const string &)", asFUNCTION(asBStrCopyFromString),      asCALL_CDECL_OBJLAST); assert( r >= 0 );	r = engine->RegisterTypeBehaviour("bstr", asBEHAVE_ASSIGNMENT, "bstr &f(const CString &)", asFUNCTION(asBStrCopyFromCString),      asCALL_CDECL_OBJLAST); assert( r >= 0 );	r = engine->RegisterGlobalFunction("void asBStrSetTransaction(const int)",            asFUNCTION(asBStrSetTransaction),       asCALL_CDECL); assert( r >= 0 );	r = engine->RegisterGlobalFunction("bool asBStrFreeTransaction(const int)",            asFUNCTION(asBStrCollectFreeTransaction),       asCALL_CDECL); assert( r >= 0 );


And the implementation :

asBSTR asBStrAlloc(asUINT length){	unsigned char *str = new unsigned char[length+4+1];	tplMapOfasBSTR *ptrMap = &g_mapBstrPointers;	tplMapOfTransactionMapOfasBSTR::iterator itTransaction;	*((asUINT*)str)  = length; // Length of string	str[length+4] = 0;      // Null terminated	if (g_bTransactionBstrPointersActive && g_csActiveTransaction.IsEmpty() == FALSE &&			(itTransaction = g_mapTransBstrPointers.find(g_csActiveTransaction)) != g_mapTransBstrPointers.end())		ptrMap = &(itTransaction->second);	ptrMap->insert(map<asBSTR, asBSTR>::value_type(str, str));	return str + 4;}void asBStrFree(asBSTR str){	tplMapOfasBSTR *ptrMap = &g_mapBstrPointers;	tplMapOfTransactionMapOfasBSTR::iterator itTransaction;	tplMapOfasBSTR::iterator itBSTR;	if( str == 0 ) return;	unsigned char *p = str-4;		if (g_bTransactionBstrPointersActive && g_csActiveTransaction.IsEmpty() == FALSE &&			(itTransaction = g_mapTransBstrPointers.find(g_csActiveTransaction)) != g_mapTransBstrPointers.end())		ptrMap = &(itTransaction->second);	if ((itBSTR = ptrMap->find(p)) != ptrMap->end())		ptrMap->erase(itBSTR);	TRACE("asBStrFree - %08lX : %s\n", p, p+4);	delete[] p;}bool asBStrCollectFreeTransaction(const int iTransactionId){	bool bRet = false;	tplMapOfTransactionMapOfasBSTR::iterator itTransaction;	tplMapOfasBSTR::iterator itBSTR;	TRACE("BSTR Begin FreeTransaction : %d\n", iTransactionId);	if (iTransactionId != 0) {		CString csTransactionId;		csTransactionId.Format("%d", iTransactionId);		itTransaction = g_mapTransBstrPointers.find(csTransactionId);		if (itTransaction != g_mapTransBstrPointers.end()) {			for (itBSTR = itTransaction->second.begin(); itBSTR != itTransaction->second.end(); itBSTR++) {				TRACE("  FreeTransaction %08lX : %s\n", itBSTR->second, itBSTR->second+4);				delete[] (itBSTR->second);			}			if (itTransaction->first == g_csActiveTransaction) {				g_csActiveTransaction.Empty();				g_bTransactionBstrPointersActive = false;			}			itTransaction->second.clear();			g_mapTransBstrPointers.erase(itTransaction);			bRet = true;		}	}	TRACE("BSTR End FreeTransaction : %d\n", iTransactionId);	return bRet;}void asBStrCollectFree(){	tplMapOfTransactionMapOfasBSTR::iterator itTransaction;	tplMapOfasBSTR::iterator itBSTR;	for (itBSTR = g_mapBstrPointers.begin(); itBSTR != g_mapBstrPointers.end(); itBSTR++)		delete[] (itBSTR->second);	g_mapBstrPointers.clear();	for (itTransaction = g_mapTransBstrPointers.begin(); itTransaction != g_mapTransBstrPointers.end(); itTransaction = g_mapTransBstrPointers.begin()) {		asBStrCollectFreeTransaction(atoi(itTransaction->first));	}}void asBStrSetTransaction(const int iTransactionId){	TRACE("BSTR SetTransaction : %d\n", iTransactionId);	if (iTransactionId != 0) {		if (g_bTransactionBstrPointersActive == false) {			tplMapOfasBSTR emptyTrans;			g_csActiveTransaction.Format("%d", iTransactionId);			g_bTransactionBstrPointersActive = true;			g_mapTransBstrPointers.insert(tplMapOfTransactionMapOfasBSTR::value_type(g_csActiveTransaction, emptyTrans));		}	}	else {		g_csActiveTransaction.Empty();		g_bTransactionBstrPointersActive = false;	}}asBSTR *asBStrCopyFromString(const string &src, asBSTR *dst){	// Free the destination bstr	asBStrFree(*dst);	// Make a copy of the source bstr	int len = src.size();	*dst = asBStrAlloc(len);	memcpy(*dst, src.c_str(), len);	return dst;}asBSTR *asBStrCopyFromCString(const CString &src, asBSTR *dst){	// Free the destination bstr	asBStrFree(*dst);	// Make a copy of the source bstr	int len = src.GetLength();	*dst = asBStrAlloc(len);	memcpy(*dst, src.operator LPCTSTR(), len);	return dst;}{/source]Note about the transactions :- It works with TransactionId as int and not bstr.- TransactionId is for debug purpose, because you cannot have multiple transaction pending (it crash)- use it just before entering block code asBStrSetTransaction(1);{Angelscript code}asBStrSetTransaction(1);


And don(t forget to call asBStrCollectFree after having released the AngelScript engine.
Thanks for letting us know how you've implemented it.

It seems to work just fine to register the strings like this. I think I'll write a mini lib for registering std::string like you've done. It is much easier to work with than asBSTR since it is automatically freed when going out of scope. Also the c_str() method of std::string can be exposed for those functions that take a normal const char*. This could be done for bstr as well.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

This topic is closed to new replies.

Advertisement