diff --git a/MUSHclient.dsp b/MUSHclient.dsp index 67f66cbc..384c24ea 100644 --- a/MUSHclient.dsp +++ b/MUSHclient.dsp @@ -51,7 +51,7 @@ BSC32=bscmake.exe LINK32=link.exe # ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 # SUBTRACT BASE LINK32 /pdb:none -# ADD LINK32 dsound.lib /nologo /subsystem:windows /debug /machine:I386 +# ADD LINK32 dsound.lib Shlwapi.lib /nologo /subsystem:windows /debug /machine:I386 # SUBTRACT LINK32 /profile !ELSEIF "$(CFG)" == "MUSHclient - Win32 Release" @@ -77,7 +77,7 @@ BSC32=bscmake.exe LINK32=link.exe # ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 # SUBTRACT BASE LINK32 /pdb:none -# ADD LINK32 dsound.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 dsound.lib Shlwapi.lib /nologo /subsystem:windows /machine:I386 # SUBTRACT LINK32 /pdb:none /debug !ENDIF @@ -267,6 +267,158 @@ SOURCE=.\worldsock.cpp SOURCE=.\dialogs\global_prefs\GlobalPrefsSheet.h # End Source File +# Begin Source File + +SOURCE=.\luacom\LuaAux.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\LuaAux.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\luabeans.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\luabeans.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\luacom_internal.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\luacom_internal.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\LuaCompat.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\LuaCompat.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\tCOMUtil.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\tCOMUtil.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\tLuaCOM.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaCOM.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\tLuaCOMClassFactory.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaCOMClassFactory.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\tLuaCOMConnPoints.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaCOMConnPoints.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\tLuaCOMEnumerator.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaCOMEnumerator.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\tLuaCOMException.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaCOMException.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\tLuaCOMTypeHandler.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaCOMTypeHandler.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\tLuaControl.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaControl.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\tLuaDispatch.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaDispatch.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\tLuaObject.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaObject.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\tLuaObjList.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaObjList.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\tLuaTLB.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaTLB.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\tLuaVector.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaVector.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\tStringBuffer.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\tStringBuffer.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\src\library\tUtil.h +# End Source File +# Begin Source File + +SOURCE=.\luacom\tUtil.h +# End Source File # End Group # Begin Group "Resource Files" @@ -1154,6 +1306,106 @@ SOURCE=.\lsqlite\lsqlite3.c # SUBTRACT CPP /YX /Yc /Yu # End Source File # End Group +# Begin Group "luacom" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\luacom\LuaAux.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\luabeans.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\luacom.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\LuaCompat.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\tCOMUtil.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaCOM.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaCOMClassFactory.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaCOMConnPoints.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaCOMEnumerator.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaCOMException.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaCOMTypeHandler.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaControl.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaDispatch.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaObject.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaObjList.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaTLB.cpp +# ADD CPP /GR +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\tLuaVector.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\tStringBuffer.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=.\luacom\tUtil.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group # Begin Source File SOURCE=.\.gitignore @@ -1171,6 +1423,19 @@ SOURCE=.\install\readme.txt # Section MUSHclient : {00000000-0001-0000-0000-000000000000} # 1:23:CG_IDR_POPUP_MAIN_FRAME:126 # End Section +# Section MUSHclient : {F3B1306C-16CC-11D0-B7D0-00A0247B3BFD} +# 0:8:Splash.h:D:\SOURCE\MUSHclient\Splash.h +# 0:10:Splash.cpp:D:\SOURCE\MUSHclient\Splash.cpp +# 1:10:IDB_SPLASH:102 +# 2:10:ResHdrName:resource.h +# 2:11:ProjHdrName:stdafx.h +# 2:10:WrapperDef:_SPLASH_SCRN_ +# 2:12:SplClassName:CSplashWnd +# 2:21:SplashScreenInsertKey:4.0 +# 2:10:HeaderName:Splash.h +# 2:10:ImplemName:Splash.cpp +# 2:7:BmpID16:IDB_SPLASH +# End Section # Section MUSHclient : {F3B13065-16CC-11D0-B7D0-00A0247B3BFD} # 0:8:TipDlg.h:D:\SOURCE\MUSHclient\TipDlg.h # 0:10:TipDlg.cpp:D:\SOURCE\MUSHclient\TipDlg.cpp @@ -1196,19 +1461,6 @@ SOURCE=.\install\readme.txt # 2:18:CG_IDS_FILE_ABSENT:CG_IDS_FILE_ABSENT # 2:10:TipDlg.cpp:TipDlg.cpp # End Section -# Section MUSHclient : {F3B1306C-16CC-11D0-B7D0-00A0247B3BFD} -# 0:8:Splash.h:D:\SOURCE\MUSHclient\Splash.h -# 0:10:Splash.cpp:D:\SOURCE\MUSHclient\Splash.cpp -# 1:10:IDB_SPLASH:102 -# 2:10:ResHdrName:resource.h -# 2:11:ProjHdrName:stdafx.h -# 2:10:WrapperDef:_SPLASH_SCRN_ -# 2:12:SplClassName:CSplashWnd -# 2:21:SplashScreenInsertKey:4.0 -# 2:10:HeaderName:Splash.h -# 2:10:ImplemName:Splash.cpp -# 2:7:BmpID16:IDB_SPLASH -# End Section # Section MUSHclient : {00000000-0000-0000-0000-000000000000} # 1:22:CG_IDR_POPUP_SEND_VIEW:124 # End Section diff --git a/install/mushclient.nsi b/install/mushclient.nsi index 4412f605..009ce0b5 100644 --- a/install/mushclient.nsi +++ b/install/mushclient.nsi @@ -96,7 +96,6 @@ Section "-MUSHclient program (required)" File "..\names.txt" File /oname=license.txt "..\docs\agreement.txt" File "..\Dina.fon" - File "..\install\luacom.dll" ; Write the installation path into the registry WriteRegStr HKCU "Software\Gammon Software Solutions\MUSHclient\General Options" "InstallDir" $INSTDIR @@ -345,7 +344,7 @@ SetOverwrite ifnewer File "..\lua\gauge.lua" File "..\lua\ppi.lua" File "..\lua\mapper.lua" - File "..\lua\com.lua" + File "..\luacom\luacom5.lua" ; LuaSocket @@ -521,11 +520,7 @@ Section Uninstall ; and Dina font Delete "$INSTDIR\Dina.fon" - - ; and LuaCOM dll - - Delete "$INSTDIR\luacom.dll" - + ; scripting stuff Delete "$INSTDIR\scripts\MUSHclient.tlb" Delete "$INSTDIR\scripts\exampscript.vbs" @@ -561,7 +556,7 @@ Section Uninstall Delete "$INSTDIR\lua\gauge.lua" Delete "$INSTDIR\lua\ppi.lua" Delete "$INSTDIR\lua\mapper.lua" - Delete "$INSTDIR\lua\com.lua" + Delete "$INSTDIR\lua\luacom5.lua" Delete "$INSTDIR\lua\socket.lua" Delete "$INSTDIR\lua\ltn12.lua" diff --git a/luacom/LuaAux.cpp b/luacom/LuaAux.cpp new file mode 100644 index 00000000..ad693817 --- /dev/null +++ b/luacom/LuaAux.cpp @@ -0,0 +1,144 @@ +// LuaAux.cpp: implementation of the LuaAux class. +// +////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include "LuaAux.h" + +extern "C" +{ +#include "LuaCompat.h" +} + + +// RCS Info +static char *rcsid = "$Id: LuaAux.cpp,v 1.13 2004/11/25 13:40:00 fqueiroz Exp $"; +static char *rcsname = "$Name: $"; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +LuaAux::LuaAux() +{ + +} + +LuaAux::~LuaAux() +{ + +} + +/* + * Prints the lua stack + */ + +void LuaAux::printLuaStack(lua_State *L) +{ + int size = lua_gettop(L); + int i = 0; + + for(i = size; i > 0; i--) + { + switch(lua_type(L,i)) + { + case LUA_TNUMBER: + printf("%d: number = %d", i, lua_tonumber(L, i)); + break; + + case LUA_TSTRING: + printf("%d: string = \"%s\"", i, lua_tostring(L, i)); + break; + + case LUA_TTABLE: + printf("%d: table, tag = %d", i, luaCompat_getType2(L, i)); + break; + + case LUA_TUSERDATA: + printf("%d: userdata = %p, tag = %d", i, + (long) luaCompat_getPointer(L, i), luaCompat_getType2(L, i)); + break; + + case LUA_TNIL: + printf("%d: nil", i); + break; + + case LUA_TBOOLEAN: + if(lua_toboolean(L, i)) + printf("%d: boolean = true", i); + else + printf("%d: boolean = false", i); + + break; + + default: + printf("%d: unknown type (%d)", i, lua_type(L, i)); + break; + } + + printf("\n"); + } + + printf("\n"); +} + +void LuaAux::printPreDump(int expected) { + printf("STACK DUMP\n"); + printf("Expected size: %i\n",expected); +} + +void LuaAux::printLuaTable(lua_State *L, stkIndex t) +{ + + lua_pushnil(L); /* first key */ + while (lua_next(L, t) != 0) { + /* `key' is at index -2 and `value' at index -1 */ + printf("%s - %s\n", + lua_tostring(L, -2), lua_typename(L, lua_type(L, -1))); + lua_pop(L, 1); /* removes `value'; keeps `index' for next iteration */ + } +} + +const char* LuaAux::makeLuaErrorMessage(int return_value, const char* msg) +{ + static char message[1000]; + message[0] = '\0'; + + if(return_value == 0) + return "No error"; + + switch(return_value) + { + case LUA_ERRRUN: + { + strncat(message, + "Lua runtime error", + sizeof(message) - strlen(message) - 1); + + if(msg) + { + strncat(message, ": ", sizeof(message) - strlen(message) - 1); + strncat(message, msg, sizeof(message) - strlen(message) - 1); + } + } + + break; + + case LUA_ERRMEM: + strcpy(message, "Lua memory allocation error."); + break; + + case LUA_ERRERR: + strcpy(message, "Lua error: error during error handler execution."); + break; + + default: + strcpy(message, "Unknown Lua error."); + break; + } + + return message; +} \ No newline at end of file diff --git a/luacom/LuaAux.h b/luacom/LuaAux.h new file mode 100644 index 00000000..beb96cab --- /dev/null +++ b/luacom/LuaAux.h @@ -0,0 +1,41 @@ +// LuaAux.h: interface for the LuaAux class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_LUAAUX_H__4C0212A0_1DD9_11D4_B880_0000B45D7541__INCLUDED_) +#define AFX_LUAAUX_H__4C0212A0_1DD9_11D4_B880_0000B45D7541__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +extern "C" +{ +#include "..\lua.h" +} + +typedef int stkIndex; + +class LuaAux +{ +public: + static void printLuaTable(lua_State *L, stkIndex index); + static void printLuaStack(lua_State *L); + static void printPreDump(int expected); + static const char* makeLuaErrorMessage(int return_value, const char* msg); + LuaAux(); + virtual ~LuaAux(); + +}; + +#include + +#define LUASTACK_SET(L) const int __LuaAux_luastack_top_index = lua_gettop(L) + +#ifdef NDEBUG +#define LUASTACK_CLEAN(L, n) lua_settop(L, __LuaAux_luastack_top_index + n) +#else +#define LUASTACK_CLEAN(L, n) if((__LuaAux_luastack_top_index + n) != lua_gettop(L)) { LuaAux::printPreDump(__LuaAux_luastack_top_index + n); LuaAux::printLuaStack(L); assert(0); } +#endif + +#endif // !defined(AFX_LUAAUX_H__4C0212A0_1DD9_11D4_B880_0000B45D7541__INCLUDED_) diff --git a/luacom/LuaCompat.c b/luacom/LuaCompat.c new file mode 100644 index 00000000..7f54cfd5 --- /dev/null +++ b/luacom/LuaCompat.c @@ -0,0 +1,860 @@ +/* + * LuaCompat.c + * + * Implementation of the class LuaCompat, + * which tries to hide almost all diferences + * between Lua versions + * + */ + + +#include +#include + +#include "..\lua.h" +#include "..\lauxlib.h" + +#ifdef COMPAT_5_1 +#include "compat-5.1.h" +#endif + +#include "LuaCompat.h" + +#define UNUSED(x) (void)(x) + +#define LUASTACK_SET(L) int __LuaAux_luastack_top_index = lua_gettop(L) + +#ifdef NDEBUG +#define LUASTACK_CLEAN(L, n) lua_settop(L, __LuaAux_luastack_top_index + n) +#else +#define LUASTACK_CLEAN(L, n) assert((__LuaAux_luastack_top_index + n) == lua_gettop(L)) +#endif + +#define LUACOMPAT_ERRORMESSAGE "__luacompat_errormesage" + + +/***************************** + * LUA 4 compatibility code + *****************************/ + +#ifdef LUA4 +#define __LUACOMPAT_OK + +/* lua4 version of API */ + +void luaCompat_openlib(lua_State* L, const char* libname, const struct luaL_reg* funcs) +{ /* lua4 */ + LUASTACK_SET(L); + + char funcname[1000]; + + lua_newtable(L); /* create it */ + lua_pushvalue(L, -1); + lua_setglobal(L, libname); /* register it with given name */ + + for (; funcs->name; funcs++) + { + int i; + lua_pushstring(L, funcs->name); + lua_pushcfunction(L, funcs->func); + lua_settable(L, -3); + + funcname[0] = '\0'; + + strncat(funcname, libname, 1000); + strcat(funcname, "_"); + strncat(funcname, funcs->name, 1000 - strlen(libname) - strlen(funcs->name) - 2); + lua_pushcfunction(L, funcs->func); + lua_setglobal(L, funcname); + } + + LUASTACK_CLEAN(L, 1); +} + + +void luaCompat_error(lua_State* L, const char* message) +{ /* lua4 */ + lua_error(L, message); +} + + +static int errorhandler(lua_State* L) +{ + lua_setglobal(L, LUACOMPAT_ERRORMESSAGE); + + return 0; +} + +int luaCompat_call(lua_State* L, int nargs, int nresults, const char **pErrMsg) +{ /* lua4 */ + int result = 0; + int user_func = 0; + + lua_getglobal(L, "_ERRORMESSAGE"); + lua_insert(L, 1); + + lua_register(L, "_ERRORMESSAGE", errorhandler); + + result = lua_call(L, nargs, nresults); + + if(result && pErrMsg) + { + lua_getglobal(L, LUACOMPAT_ERRORMESSAGE); + *pErrMsg = lua_tostring(L, -1); + lua_pop(L, 1); + } + + lua_pushvalue(L, 1); + lua_setglobal(L, "_ERRORMESSAGE"); + + lua_remove(L, 1); + + return result; +} + + +void luaCompat_newLuaType(lua_State* L, + const char* module_name, + const char* type_name) +{ /* lua4 */ + LUASTACK_SET(L); + + int tag = lua_newtag(L); + + lua_pushnumber(L, tag); + + luaCompat_moduleSet(L, module_name, type_name); + + LUASTACK_CLEAN(L, 0); +} + +void luaCompat_pushTypeByName(lua_State* L, + const char* module_name, + const char* type_name) +{ /* lua4 */ + LUASTACK_SET(L); + + luaCompat_moduleGet(L, module_name, type_name); + + if(lua_isnil(L, -1)) + { + lua_pop(L, 1); + luaCompat_newLuaType(L, module_name, type_name); + luaCompat_moduleGet(L, module_name, type_name); + } + + LUASTACK_CLEAN(L, 1); +} + + +int luaCompat_newTypedObject(lua_State* L, void* object) +{ /* lua4 */ + int newreference = 0; + int tag = 0; + + LUASTACK_SET(L); + + luaL_checktype(L, -1, LUA_TNUMBER); + + tag = (int) lua_tonumber(L, -1); + + lua_pop(L, 1); + + /* pushes userdata */ + lua_pushusertag(L, object, LUA_ANYTAG); + + if(lua_tag(L, -1) != tag) + { + /* this is the first userdata with this value, + so corrects the tag */ + lua_settag(L, tag); + newreference = 1; + } + + LUASTACK_CLEAN(L, 0); + + return newreference; +} + +void luaCompat_setType(lua_State* L, int index) +{ /* lua4 */ + + LUASTACK_SET(L); + + int tag = lua_tonumber(L, -1); + + lua_pushvalue(L, index); + + lua_settag(L, tag); + + lua_pop(L, 2); + + LUASTACK_CLEAN(L, -1); +} + + +void luaCompat_moduleSet(lua_State* L, const char* module, const char* key) +{ /* lua4 */ + LUASTACK_SET(L); + + lua_getglobal(L, module); + + lua_pushstring(L, key); + lua_pushvalue(L, -3); + lua_settable(L, -3); + + lua_pop(L, 2); + + LUASTACK_CLEAN(L, -1); +} + +void luaCompat_moduleGet(lua_State* L, const char* module, const char* key) +{ /* lua4 */ + LUASTACK_SET(L); + + lua_getglobal(L, module); + lua_pushstring(L, key); + + lua_gettable(L, -2); + + lua_remove(L, -2); + + LUASTACK_CLEAN(L, 1); +} + + +void* luaCompat_getTypedObject(lua_State* L, int index) +{ /* lua4 */ + return lua_touserdata(L, index); +} + +int luaCompat_isOfType(lua_State* L, const char* module, const char* type) +{ /* lua4 */ + int result = 0; + + LUASTACK_SET(L); + + luaCompat_getType(L, -1); + luaCompat_pushTypeByName(L, module, type); + + result = lua_equal(L, -1, -2); + + lua_pop(L, 2); + + LUASTACK_CLEAN(L,0); + + return result; +} + +void luaCompat_getType(lua_State* L, int index) +{ /* lua4 */ + LUASTACK_SET(L); + + int tag = lua_tag(L, index); + lua_pushnumber(L, tag); + + LUASTACK_CLEAN(L, 1); +} + +long luaCompat_getType2(lua_State* L, int index) +{ /* lua4 */ + int tag = lua_tag(L, index); + return tag; +} + + + +void luaCompat_handleEqEvent(lua_State* L) +{ /* lua4 */ + LUASTACK_SET(L); + + /* lua4 does not have eq event */ + lua_pop(L, 1); + + LUASTACK_CLEAN(L, -1); +} + + + +void luaCompat_handleGettableEvent(lua_State* L) +{ /* lua4 */ + LUASTACK_SET(L); + + int tag = lua_tonumber(L, -2); + + lua_settagmethod(L, tag, "gettable"); + + LUASTACK_CLEAN(L, -1); +} + +void luaCompat_handleSettableEvent(lua_State* L) +{ /* lua4 */ + LUASTACK_SET(L); + + int tag = lua_tonumber(L, -2); + + lua_settagmethod(L, tag, "settable"); + + LUASTACK_CLEAN(L, -1); + +} + +void luaCompat_handleNoIndexEvent(lua_State* L) +{ /* lua4 */ + LUASTACK_SET(L); + + int tag = lua_tonumber(L, -2); + + lua_settagmethod(L, tag, "index"); + + LUASTACK_CLEAN(L, -1); +} + +void luaCompat_handleGCEvent(lua_State* L) +{ /* lua4 */ + LUASTACK_SET(L); + + int tag = lua_tonumber(L, -2); + + lua_settagmethod(L, tag, "gc"); + + LUASTACK_CLEAN(L, -1); +} + +void luaCompat_handleFuncCallEvent(lua_State* L) +{ /* lua4 */ + LUASTACK_SET(L); + + int tag = lua_tonumber(L, -2); + + lua_settagmethod(L, tag, "function"); + + LUASTACK_CLEAN(L, -1); +} + + +int luaCompat_upvalueIndex(lua_State* L, int which, int num_upvalues) +{ /* lua4 */ + return lua_gettop(L) + which - num_upvalues; +} + +int luaCompat_getNumParams(lua_State* L, int num_upvalues) +{ /* lua4 */ + return lua_gettop(L) - num_upvalues; +} + +void luaCompat_moduleCreate(lua_State* L, const char* module) +{ /* lua4 */ + LUASTACK_SET(L); + + // tests whether module already exists + lua_getglobal(L, module); + + if(lua_isnil(L, -1)) + { + lua_pop(L, 1); + + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setglobal(L, module); + } + + LUASTACK_CLEAN(L, 1); +} + +void luaCompat_pushPointer(lua_State* L, void *pointer) +{ /* lua4 */ + lua_pushuserdata(L, pointer); +} + +void* luaCompat_getPointer(lua_State* L, int index) +{ /* lua4 */ + return lua_touserdata(L, index); +} + +void luaCompat_pushBool(lua_State* L, int value) +{ /* lua4 */ + LUASTACK_SET(L); + + if(value) + lua_pushnumber(L, 1); + else + lua_pushnil(L); + + LUASTACK_CLEAN(L, 1); +} + +void luaCompat_pushCBool(lua_State* L, int value) +{ /* lua4 */ + LUASTACK_SET(L); + + if(value) + lua_pushnumber(L, 1); + else + lua_pushnumber(L, 0); + + LUASTACK_CLEAN(L, 1); +} + +int luaCompat_toCBool(lua_State* L, int index) +{ /* lua4 */ + int value = lua_tonumber(L, index); + + return value; +} + + +void luaCompat_needStack(lua_State* L, long size) +{ /* lua4 */ + assert(lua_stackspace(L) >= size); +} + + +void luaCompat_getglobal(lua_State* L) +{ /* lua4 */ + lua_getglobal(L, lua_tostring(L, -1)); + lua_remove(L, -2); +} + +void luaCompat_setglobal(lua_State* L) +{ /* lua4 */ + lua_setglobal(L, lua_tostring(L, -2)); +} + +int luaCompat_checkTagToCom(lua_State *L, int luaval) +{ /* lua4 */ + int tag; + + if((tag = lua_tag(L, luaval)) == LUA_NOTAG) return 0; + + lua_gettagmethod(L, tag, "tocom"); + if(lua_isnil(L,-1)) { + lua_pop(L,1); + return 0; + } + + return 1; +} + + +#endif /* lua4 */ + + + + + + + + + + + + + + + + + + + +/******************************** + * LUA 5 section + ********************************/ + +#ifdef LUA5 +#define __LUACOMPAT_OK + +/* Lua 5 version of the API */ + +void luaCompat_openlib(lua_State* L, const char* libname, const struct luaL_reg* funcs) +{ /* lua5 */ + LUASTACK_SET(L); + +#ifdef COMPAT_5_1 + luaL_module(L, libname, funcs, 0); +#else + luaL_openlib(L, libname, funcs, 0); +#endif + + LUASTACK_CLEAN(L, 1); +} + +void luaCompat_error(lua_State* L, const char* message) +{ /* lua5 */ + lua_pushstring(L, message); + lua_error(L); +} + +int luaCompat_call(lua_State* L, int nargs, int nresults, const char** pErrMsg) +{ /* lua5 */ + int result = lua_pcall(L, nargs, nresults, 0); + + if(result) + { + if(pErrMsg) + *pErrMsg = lua_tostring(L, -1); + + lua_pop(L, 1); + } + + return result; +} + + +void luaCompat_newLuaType(lua_State* L, const char* module, const char* type) +{ /* lua5 */ + LUASTACK_SET(L); + + lua_newtable(L); + + /* stores the typename in the Lua table, allowing some reflexivity */ + lua_pushstring(L, "type"); + lua_pushstring(L, type); + lua_settable(L, -3); + + /* stores type in the module */ + luaCompat_moduleSet(L, module, type); + + LUASTACK_CLEAN(L, 0); +} + +void luaCompat_pushTypeByName(lua_State* L, + const char* module_name, + const char* type_name) +{ /* lua5 */ + LUASTACK_SET(L); + + luaCompat_moduleGet(L, module_name, type_name); + + if(lua_isnil(L, -1)) + { + lua_pop(L, 1); + luaCompat_newLuaType(L, module_name, type_name); + luaCompat_moduleGet(L, module_name, type_name); + } + + LUASTACK_CLEAN(L, 1); +} + +#ifndef lua_boxpointer +#define lua_boxpointer(L,u) \ + (*(void **)(lua_newuserdata(L, sizeof(void *))) = (u)) +#define lua_unboxpointer(L,i) (*(void **)(lua_touserdata(L, i))) +#endif + +int luaCompat_newTypedObject(lua_State* L, void* object) +{ /* lua5 */ + LUASTACK_SET(L); + + luaL_checktype(L, -1, LUA_TTABLE); + + lua_boxpointer(L, object); + + lua_insert(L, -2); + + lua_setmetatable(L, -2); + + LUASTACK_CLEAN(L, 0); + + return 1; +} + +void luaCompat_setType(lua_State* L, int index) +{ /* lua5 */ + + LUASTACK_SET(L); + + lua_setmetatable(L, index); + + LUASTACK_CLEAN(L,-1); +} + + + +void luaCompat_moduleSet(lua_State* L, const char* module, const char* key) +{ /* lua5 */ + LUASTACK_SET(L); + + lua_pushstring(L, module); + lua_gettable(L, LUA_REGISTRYINDEX); + + lua_pushstring(L, key); + lua_pushvalue(L, -3); + lua_settable(L, -3); + + lua_pop(L, 2); + + LUASTACK_CLEAN(L, -1); +} + +void luaCompat_moduleGet(lua_State* L, const char* module, const char* key) +{ /* lua5 */ + LUASTACK_SET(L); + + lua_pushstring(L, module); + lua_gettable(L, LUA_REGISTRYINDEX); + + lua_pushstring(L, key); + lua_gettable(L, -2); + + lua_remove(L, -2); + + LUASTACK_CLEAN(L, 1); +} + + +void* luaCompat_getTypedObject(lua_State* L, int index) +{ /* lua5 */ + void **pObj = (void **) lua_touserdata(L, index); + + void *Obj= *pObj; + + return Obj; +} + + +int luaCompat_isOfType(lua_State* L, const char* module, const char* type) +{ /* lua5 */ + int result = 0; + LUASTACK_SET(L); + + luaCompat_getType(L, -1); + luaCompat_pushTypeByName(L, module, type); + + result = (lua_equal(L, -1, -2) ? 1 : 0); + + lua_pop(L, 2); + + LUASTACK_CLEAN(L, 0); + + return result; +} + +void luaCompat_getType(lua_State* L, int index) +{ /* lua5 */ + LUASTACK_SET(L); + int result = lua_getmetatable(L, index); + + if(!result) + lua_pushnil(L); + + LUASTACK_CLEAN(L, 1); +} + +long luaCompat_getType2(lua_State* L, int index) +{ /* lua5 */ + long result = 0; + + LUASTACK_SET(L); + + if(!lua_getmetatable(L, index)) + lua_pushnil(L); + + result = (long) lua_topointer(L, -1); + lua_pop(L, 1); + + LUASTACK_CLEAN(L, 0); + + return result; +} + + +void luaCompat_handleEqEvent(lua_State* L) +{ /* lua5 */ + LUASTACK_SET(L); + + lua_pushstring(L, "__eq"); + lua_insert(L, -2); + + lua_settable(L, -3); + + LUASTACK_CLEAN(L, -1); +} + + +void luaCompat_handleGettableEvent(lua_State* L) +{ /* lua5 */ + // there is no gettable_event in Lua5 with the semantics of + // Lua4 +} + +void luaCompat_handleSettableEvent(lua_State* L) +{ /* lua5 */ + LUASTACK_SET(L); + + lua_pushstring(L, "__newindex"); + lua_insert(L, -2); + + lua_settable(L, -3); + + LUASTACK_CLEAN(L, -1); + +} + + +void luaCompat_handleNoIndexEvent(lua_State* L) +{ /* lua5 */ + LUASTACK_SET(L); + + lua_pushstring(L, "__index"); + lua_insert(L, -2); + + lua_settable(L, -3); + + LUASTACK_CLEAN(L, -1); +} + + +void luaCompat_handleGCEvent(lua_State* L) +{ /* lua5 */ + LUASTACK_SET(L); + + lua_pushstring(L, "__gc"); + lua_insert(L, -2); + + lua_settable(L, -3); + + LUASTACK_CLEAN(L, -1); +} + +void luaCompat_handleFuncCallEvent(lua_State* L) +{ /* lua5 */ + LUASTACK_SET(L); + + lua_pushstring(L, "__call"); + lua_insert(L, -2); + + lua_settable(L, -3); + + LUASTACK_CLEAN(L, -1); +} + + +int luaCompat_upvalueIndex(lua_State* L, int which, int num_upvalues) +{ /* lua5 */ + UNUSED(num_upvalues); + + return lua_upvalueindex(which); +} + +int luaCompat_getNumParams(lua_State* L, int num_upvalues) +{ /* lua5 */ + UNUSED(num_upvalues); + return lua_gettop(L); +} + +void luaCompat_moduleCreate(lua_State* L, const char* module) +{ /* lua5 */ + LUASTACK_SET(L); + + lua_pushstring(L, module); + lua_gettable(L, LUA_REGISTRYINDEX); + + if(lua_isnil(L, -1)) + { + lua_pop(L, 1); + lua_newtable(L); + lua_pushstring(L, module); + lua_pushvalue(L, -2); + + lua_settable(L, LUA_REGISTRYINDEX); + } + + LUASTACK_CLEAN(L, 1); +} + +void luaCompat_pushPointer(lua_State* L, void *pointer) +{ /* lua5 */ + lua_pushlightuserdata(L, pointer); +} + +void* luaCompat_getPointer(lua_State* L, int index) +{ /* lua5 */ + if(!lua_islightuserdata(L, index)) + return NULL; + + return lua_touserdata(L, index); +} + +void luaCompat_pushBool(lua_State* L, int value) +{ /* lua5 */ + LUASTACK_SET(L); + + lua_pushboolean(L, value); + + LUASTACK_CLEAN(L, 1); +} + +void luaCompat_pushCBool(lua_State* L, int value) +{ /* lua5 */ + LUASTACK_SET(L); + + lua_pushboolean(L, value); + + LUASTACK_CLEAN(L, 1); +} + +int luaCompat_toCBool(lua_State* L, int index) +{ /* lua5 */ + int value = lua_toboolean(L, index); + + return value; +} + + +void luaCompat_needStack(lua_State* L, long size) +{ /* lua5 */ + lua_checkstack(L, size); +} + + +void luaCompat_getglobal(lua_State* L) +{ /* lua5 */ + lua_gettable(L, LUA_GLOBALSINDEX); +} + +void luaCompat_setglobal(lua_State* L) +{ /* lua5 */ + lua_settable(L, LUA_GLOBALSINDEX); +} + + +int luaCompat_checkTagToCom(lua_State *L, int luaval) +{ /* lua5 */ + + if(!lua_getmetatable(L, luaval)) return 0; + + lua_pushstring(L, "__tocom"); + lua_gettable(L, -2); + if(lua_isnil(L,-1)) { + lua_pop(L, 2); + return 0; + } + + lua_remove(L,-2); + return 1; +} + + + + +#endif /* LUA5 */ + + + + + + + + + + + + + + + +#ifndef __LUACOMPAT_OK +#error Lua version not specified +#endif + diff --git a/luacom/LuaCompat.h b/luacom/LuaCompat.h new file mode 100644 index 00000000..3da80e79 --- /dev/null +++ b/luacom/LuaCompat.h @@ -0,0 +1,84 @@ +/* + * LuaCompat.h + * + * Library that tries to hide almost all diferences + * between Lua versions + * + */ + +#ifndef __LUACOMPAT_H +#define __LUACOMPAT_H + +#define LUA5 + +void luaCompat_openlib(lua_State* L, const char* libname, const struct luaL_reg* funcs); +void luaCompat_error(lua_State* L, const char* message); +int luaCompat_call(lua_State* L, int nargs, int nresults, const char** pErrMsg); + +void luaCompat_newLuaType(lua_State* L, const char* module_name, const char* name); +void luaCompat_pushTypeByName(lua_State* L, const char* module, const char* type_name); +int luaCompat_newTypedObject(lua_State* L, void* object); +void luaCompat_setType(lua_State* L, int index); +void* luaCompat_getTypedObject(lua_State* L, int index); +int luaCompat_isOfType(lua_State* L, const char* module, const char* type); +void luaCompat_getType(lua_State* L, int index); +long luaCompat_getType2(lua_State* L, int index); + +void luaCompat_pushPointer(lua_State* L, void *pointer); +void* luaCompat_getPointer(lua_State* L, int index); + +void luaCompat_pushCBool(lua_State* L, int value); +int luaCompat_toCBool(lua_State* L, int index); +void luaCompat_pushBool(lua_State* L, int value); + +void luaCompat_handleEqEvent(lua_State* L); +void luaCompat_handleGettableEvent(lua_State* L); +void luaCompat_handleSettableEvent(lua_State* L); +void luaCompat_handleNoIndexEvent(lua_State* L); +void luaCompat_handleGCEvent(lua_State* L); +void luaCompat_handleFuncCallEvent(lua_State* L); + + +void luaCompat_moduleCreate(lua_State* L, const char* module); +void luaCompat_moduleSet(lua_State* L, const char* module, const char* key); +void luaCompat_moduleGet(lua_State* L, const char* module, const char* key); + +int luaCompat_upvalueIndex(lua_State* L, int which, int num_upvalues); +int luaCompat_getNumParams(lua_State* L, int num_upvalues); + +void luaCompat_needStack(lua_State* L, long size); + +void luaCompat_setglobal(lua_State* L); +void luaCompat_getglobal(lua_State* L); + +int luaCompat_checkTagToCom(lua_State *L, int luaval); + +#ifdef __cplusplus +extern "C" +{ +#endif +#include "..\lua.h" +#ifdef __cplusplus +} +#endif + +// defined just to avoid compiler erros +#ifdef LUA4 +#define LUA_TBOOLEAN 0xabcdef +#define lua_toboolean(x,y) lua_tonumber((x),(y)) + +#ifdef __cplusplus +extern "C" +{ +#endif +#include +#ifdef __cplusplus +} +#endif +#endif + + + + +#endif /* __LUACOMPAT_H */ + diff --git a/luacom/luabeans.cpp b/luacom/luabeans.cpp new file mode 100644 index 00000000..bb5ad945 --- /dev/null +++ b/luacom/luabeans.cpp @@ -0,0 +1,181 @@ +#include +#include +#include +extern "C" +{ +#include "..\lua.h" +#include "..\lauxlib.h" +#include "LuaCompat.h" +} +#include "luabeans.h" + + +#include "tLuaCOMException.h" +#include "LuaAux.h" +#include "tUtil.h" + +char* LuaBeans::tag_name = NULL; +char* LuaBeans::udtag_name = NULL; +LuaBeans::Events* LuaBeans::pEvents = NULL; +const char* LuaBeans::module_name = NULL; + +#define luaL_arg_check luaL_argcheck + +void LuaBeans::createBeans(lua_State *L, + const char* p_module_name, + const char* name) +{ + LUASTACK_SET(L); + + char lua_name[500]; + + module_name = tUtil::strdup(p_module_name); + + sprintf(lua_name, "%s" ,name); + tag_name = tUtil::strdup(lua_name); + luaCompat_newLuaType(L, module_name, tag_name); + + sprintf(lua_name,"%s_UDTAG",name); + udtag_name = tUtil::strdup(lua_name); + luaCompat_newLuaType(L, module_name, udtag_name); + LUASTACK_CLEAN(L, 0); +} + + +void LuaBeans::Clean() +{ + free(LuaBeans::tag_name); + free(LuaBeans::udtag_name); +} + +void LuaBeans::registerObjectEvents(lua_State* L, class Events& events) +{ + LUASTACK_SET(L); + + luaCompat_pushTypeByName(L, module_name, tag_name); + + if(events.gettable) + { + lua_pushcfunction(L, events.gettable); + luaCompat_handleGettableEvent(L); + } + + if(events.settable) + { + lua_pushcfunction(L, events.settable); + luaCompat_handleSettableEvent(L); + } + + if(events.noindex) + { + lua_pushcfunction(L, events.noindex); + luaCompat_handleNoIndexEvent(L); + } + + if(events.call) + { + lua_pushcfunction(L, events.call); + luaCompat_handleFuncCallEvent(L); + } + + if(events.gc) + { + lua_pushcfunction(L, events.gc); + luaCompat_handleGCEvent(L); + } + + lua_pop(L, 1); + + LUASTACK_CLEAN(L, 0); +} + +void LuaBeans::registerPointerEvents(lua_State* L, class Events& events) +{ + LUASTACK_SET(L); + + luaCompat_pushTypeByName(L, module_name, udtag_name); + + if(events.gettable) + { + lua_pushcfunction(L, events.gettable); + luaCompat_handleGettableEvent(L); + } + + if(events.settable) + { + lua_pushcfunction(L, events.settable); + luaCompat_handleSettableEvent(L); + } + + if(events.noindex) + { + lua_pushcfunction(L, events.noindex); + luaCompat_handleNoIndexEvent(L); + } + + if(events.gc) + { + lua_pushcfunction(L, events.gc); + luaCompat_handleGCEvent(L); + } + + lua_pop(L, 1); + + LUASTACK_CLEAN(L, 0); +} + +void LuaBeans::push(lua_State* L, void* userdata ) +{ + LUASTACK_SET(L); + + lua_newtable(L); + + lua_pushstring(L, "_USERDATA_REF_"); + + luaCompat_pushTypeByName(L, module_name, udtag_name); + luaCompat_newTypedObject(L, userdata); + + lua_settable(L, -3); + + luaCompat_pushTypeByName(L, module_name, tag_name); + luaCompat_setType(L, -2); + + LUASTACK_CLEAN(L, 1); +} + +void* LuaBeans::check_tag(lua_State* L, int index) +{ + void* userdata = from_lua(L, index); + + luaL_arg_check(L, (userdata!=NULL), index, "Object type is wrong"); + + return userdata; +} + +void* LuaBeans::from_lua(lua_State* L, int index) +{ + LUASTACK_SET(L); + + void *obj = NULL; + + lua_pushvalue(L, index); + if (lua_istable(L, -1) && luaCompat_isOfType(L, module_name, tag_name)) + { + lua_pushstring(L, "_USERDATA_REF_"); + lua_gettable(L, index); + obj = luaCompat_getTypedObject(L, -1); + lua_pop(L, 1); + } + lua_pop(L, 1); + + LUASTACK_CLEAN(L, 0); + + return obj; +} + + +/*lua_State* LuaBeans::getLuaState() +{ + return L; +}*/ + diff --git a/luacom/luabeans.h b/luacom/luabeans.h new file mode 100644 index 00000000..95f98db9 --- /dev/null +++ b/luacom/luabeans.h @@ -0,0 +1,44 @@ +#ifndef LUABEANS_H +#define LUABEANS_H + +class LuaBeans +{ +public: + + class Events + { + public: + lua_CFunction gettable; + lua_CFunction settable; + lua_CFunction noindex; + lua_CFunction call; + lua_CFunction gc; + + Events() + { + gettable = settable = noindex = call = gc = NULL; + } + }; + + //lua_State* getLuaState(void); + + static void createBeans( + lua_State *L, + const char* module_name, + const char* name); + + static void Clean(void); + + static void registerObjectEvents(lua_State* L, class Events& events); + static void registerPointerEvents(lua_State* L, class Events& events); + static void push(lua_State* L, void* userdata); + static void* check_tag(lua_State* L, int index); + static void* from_lua(lua_State* L, int index); + +protected: + static char* tag_name; + static char* udtag_name; + static Events* pEvents; + static const char* module_name; +}; +#endif diff --git a/luacom/luacom.cpp b/luacom/luacom.cpp new file mode 100644 index 00000000..64811e7b --- /dev/null +++ b/luacom/luacom.cpp @@ -0,0 +1,2674 @@ +/* + * LUACOM.cpp + * + * Bind de Lua com COM/OLE + * + * Renato Cerqueira + * Vinicius Almendra + * + */ + +// RCS Info +static char *rcsid = "$Id: luacom.cpp,v 1.61 2005/01/06 18:41:49 fqueiroz Exp $"; +static char *rcsname = "$Name: $"; +static char *g_version = "1.2b"; + +#include +#include + +#include +#include + +#include +#include +#include + +#pragma warning(disable: 4800) + +extern "C" +{ +#include "..\lua.h" +#include "..\lauxlib.h" +#include "LuaCompat.h" +} + +#include "luabeans.h" +#include "luacom.h" +#include "tLuaDispatch.h" +#include "tLuaControl.h" +#include "tLuaCOM.h" +#include "tLuaCOMException.h" +#include "tCOMUtil.h" +#include "tLuaCOMClassFactory.h" +#include "tLuaCOMTypeHandler.h" +#include "tLuaCOMConnPoints.h" + +#include "luacom_internal.h" + +#include "LuaAux.h" +#include "tUtil.h" + +#include "tLuaCOMEnumerator.h" +#include "tLuaTLB.h" + + +#define luaL_check_lstr luaL_checklstring +#define luaL_opt_lstr luaL_optlstring +#define luaL_check_number +// some string constants + +#define GET_PREFIX "get" +#define PUT_PREFIX "set" + +static bool luacom_runningInprocess(lua_State* L); + +HINSTANCE g_hInstance; +CRITICAL_SECTION g_CriticalSection; +HWND g_hwndParking; + + +//////////////////////// +// // +// FUNCOES INTERNAS // +// // +//////////////////////// + + +static tLuaCOM* ImplInterface(lua_State* L, + ITypeLib* typelib, + CLSID clsid, + const char* interface_name, + int unlocked_ref + ) +{ + CHECKPARAM(typelib && interface_name && L); + + ITypeInfo* interface_typeinfo = + tCOMUtil::GetInterfaceTypeInfo(typelib, interface_name); + + if(interface_typeinfo == NULL) + return NULL; + + tLuaDispatch* iluacom = + tLuaDispatch::CreateLuaDispatch(L, interface_typeinfo, unlocked_ref); + + if(iluacom == NULL) + { + COM_RELEASE(interface_typeinfo); + return NULL; + } + + tLuaCOM *lcom = NULL; + + try + { + lcom = + tLuaCOM::CreateLuaCOM(L, iluacom, clsid, interface_typeinfo); + } + catch(class tLuaCOMException& e) + { + UNUSED(e); + lcom = NULL; + } + + COM_RELEASE(interface_typeinfo); + COM_RELEASE(iluacom); + + return lcom; +} + + +// deals with runtime errors, calling lua_error or +// logging them, depending on the client's choice +// The message string is left on the top of the +// stack, to allow passing it to the caller + +static void luacom_err(lua_State* L, const char* message, bool is_API_function) +{ + LUASTACK_SET(L); + + lua_pushstring(L, message); + luaCompat_moduleSet(L, MODULENAME, LUACOM_LAST_ERROR); + + if(is_API_function) + luaCompat_moduleGet(L, MODULENAME, LUACOM_SHOULD_ABORT_API); + else + luaCompat_moduleGet(L, MODULENAME, LUACOM_SHOULD_ABORT); + + if(luaCompat_toCBool(L, -1)) + { + luaCompat_error(L, message); + } + + lua_pop(L, 1); + + LUASTACK_CLEAN(L, 0); +} + +void luacom_error(lua_State* L, const char* message) +{ + luacom_err(L, message, false); +} + +static void luacom_APIerror(lua_State* L, const char* message) +{ + luacom_err(L, message, true); +} + + + + +/////////////////////////////////// +// // +// FUNCOES EXPORTADAS PARA LUA // +// // +/////////////////////////////////// + +/* + * luacom_ShowHelp + * + * Parametros: + * + * (1) objeto luacom + * + * Mostra Help da type library associada ao objeto + * luacom + */ + +static int luacom_ShowHelp(lua_State *L) +{ + char *pHelpFile = NULL; + unsigned long context = 0; + + tLuaCOM* luacom = (tLuaCOM *) LuaBeans::check_tag(L, 1); + + luacom->getHelpInfo(&pHelpFile, &context); + + if(pHelpFile != NULL) + { + if(context != 0) + WinHelp(NULL, pHelpFile, HELP_CONTEXT, context); + else + WinHelp(NULL, pHelpFile, HELP_FINDER, 0); + } + + return 0; +} + +/* + * luacom_Connect + * + * Parametros (Lua): + * + * objeto luacom + * tabela que implementara a interface de conexao + * + * Retorno + * objeto luacom que encapsula objeto luacom implementado pela + * tabela fornecida ou nil se nao for possível estabelecer a + * conexao + * cookir do connection point + * + * Cria um connection point utilizando a tabela + * passada como parametro e o conecta com o objeto + * passado tambem como parametro + */ + +static int luacom_Connect(lua_State *L) +{ + tLuaDispatch *server_disp = NULL; + ITypeInfo *pTypeinfo = NULL; + + // check parameters + tLuaCOM* client = (tLuaCOM *) LuaBeans::check_tag(L, 1); + + if(lua_type(L, 2) != LUA_TTABLE && lua_type(L, 2) != LUA_TUSERDATA) + { + luaL_argerror(L, 2, "Implementation must be a table or a userdata"); + } + + tLuaCOM* server = NULL; + DWORD cookie; + + try + { + pTypeinfo = client->GetDefaultEventsInterface(); + + CHK_LCOM_ERR(pTypeinfo, "Could not get default events interface."); + + /* gets a reference to the implementation */ + lua_pushvalue(L, 2); + int ref = lua_ref(L, 1); + + server_disp = + tLuaDispatch::CreateLuaDispatch(L, pTypeinfo, ref); + + lua_unref(L, ref); + + CHECKPOSCOND(server_disp); + + server = tLuaCOM::CreateLuaCOM(L, server_disp); + + CHECKPOSCOND(server); + + cookie = client->addConnection(server); + CHECKPOSCOND(cookie); + } + catch(class tLuaCOMException& e) + { + COM_RELEASE(server_disp); + COM_RELEASE(pTypeinfo); + + luacom_APIerror(L, e.getMessage()); + + return 0; + } + + LuaBeans::push(L, server); + lua_pushnumber(L, cookie); + + COM_RELEASE(server_disp); + COM_RELEASE(pTypeinfo); + + return 2; +} + +/* + * luacom_ImplInterfaceFromTypelib (Lua2C) + * + * Parametros: + * 1. Tabela de implementacao + * 2. Nome da type library + * 3. Nome da interface a ser implementada + * 4. (Opcional) Nome da CoClass da qual a interface faz parte + * necessario no caso de se querer expor objetos implementados + * com essa interface ou no caso de se querer localizar uma + * interface source (eventos) + * + * Retorno: + * 1. Objeto LuaCOM que encapsula a implementacao via Lua + * ou nil em caso de erro + * + * Implementa uma interface descrida em uma type library + * dada + */ +static tLuaCOM *luacom_ImplInterfaceFromTypelibHelper(lua_State *L) +{ + if(lua_type(L, 1) != LUA_TTABLE && lua_type(L,1) != LUA_TUSERDATA) + { + luaL_argerror(L, 1, "Implementation must be a table or a userdata"); + } + + lua_pushvalue(L, 1); + const int ref = lua_ref(L, 1); + + const char* typelib_name = luaL_check_lstr(L, 2, NULL); + const char* pcInterface = luaL_check_lstr(L, 3, NULL); + const char* coclassname = luaL_opt_lstr(L, 4, NULL, NULL); + + tLuaCOM* lcom = NULL; + ITypeLib* typelib = NULL; + CLSID clsid = IID_NULL; + + try + { + // gets typelib + typelib = tCOMUtil::LoadTypeLibByName(typelib_name); + CHK_LCOM_ERR(typelib, "Could not load type library."); + + + // gets coclass typeinfo + + if(coclassname) + { + ITypeInfo* coclassinfo = + tCOMUtil::GetCoClassTypeInfo(typelib, coclassname); + CHK_LCOM_ERR(coclassinfo, "Could not get ccoclass typeinfo."); + + clsid = tCOMUtil::GetCLSID(coclassinfo); + COM_RELEASE(coclassinfo); + } + + lcom = + ImplInterface(L, typelib, clsid, pcInterface, ref); + + lua_unref(L, ref); + + CHECKPOSCOND(lcom); + } + catch(class tLuaCOMException& e) + { + COM_RELEASE(typelib); + + luacom_APIerror(L, e.getMessage()); + + return 0; + } + + COM_RELEASE(typelib); + + return lcom; +} + +static int luacom_ImplInterfaceFromTypelib(lua_State *L) +{ + tLuaCOM *lcom = luacom_ImplInterfaceFromTypelibHelper(L); + if(lcom) { + LuaBeans::push(L, lcom); + return 1; + } else return 0; +} + +/* + * luacom_ImplInterface (Lua2C) + * + * Cria uma implementacao IDispatch para um + * objeto Lua dado um ProgID e o nome da + * interface + * + * In: Implementation: table, + * ProgID: string, + * Interface: string, + * + * Out: LuaCOM_obj (table with tag LuaCOM) +*/ +static tLuaCOM *luacom_ImplInterfaceHelper(lua_State *L) +{ + // gets parameters + if(lua_type(L, 1) != LUA_TTABLE && lua_type(L,1) != LUA_TUSERDATA) + { + luaL_argerror(L, 1, "Implementation must be a table or a userdata"); + } + + // pushes lua table on top of stack + lua_pushvalue(L, 1); + const int ref = lua_ref(L, 1); + + const char* pcProgID = luaL_check_lstr(L, 2, NULL); + const char* pcInterface = luaL_check_lstr(L, 3, NULL); + + tLuaCOM* lcom = NULL; + ITypeLib* typelib = NULL; + + try + { + // gets typelib + CLSID clsid = IID_NULL; + HRESULT hr = S_OK; + + hr = tCOMUtil::ProgID2CLSID(&clsid, pcProgID); + + CHK_COM_CODE(hr); + + + typelib = tCOMUtil::LoadTypeLibFromCLSID(clsid); + + CHK_LCOM_ERR(typelib, "Could not load type library."); + + lcom = + ImplInterface(L, typelib, clsid, pcInterface, ref); + + lua_unref(L, ref); + + COM_RELEASE(typelib); + + CHECKPOSCOND(lcom); + } + catch(class tLuaCOMException& e) + { + COM_RELEASE(typelib); + + luacom_APIerror(L, e.getMessage()); + + return 0; + } + + COM_RELEASE(typelib); + + return lcom; +} + +static int luacom_ImplInterface(lua_State *L) +{ + tLuaCOM* lcom = luacom_ImplInterfaceHelper(L); + + if(lcom) { + LuaBeans::push(L, lcom); + return 1; + } else return 0; +} + +/* + * luacom_CLSIDfromProgID + * Retorna string contendo CLSID associado a um ProgID + */ + +static int luacom_CLSIDfromProgID(lua_State *L) +{ + const char* str = luaL_check_lstr(L, 1, NULL); + wchar_t* clsid_str = NULL; + wchar_t* progId = NULL; + CLSID clsid = IID_NULL; + HRESULT hr = S_OK; + + char* id_str = NULL; + + try + { + progId = (wchar_t*) malloc( (strlen(str) + 1) * sizeof(wchar_t)); + mbstowcs(progId,str,strlen(str)+1); + + hr = CLSIDFromProgID(progId, &clsid); + CHK_COM_CODE(hr); + + hr = StringFromCLSID(clsid, &clsid_str); + CHK_COM_CODE(hr); + + id_str = (char*) malloc( (wcslen(clsid_str) + 1) * sizeof(char)); + wcstombs(id_str,clsid_str,wcslen(clsid_str)+1); + } + catch(class tLuaCOMException& e) + { + SAFEFREE(progId); + SAFEFREE(id_str); + + luacom_APIerror(L, e.getMessage()); + + return 0; + } + + lua_pushstring(L, id_str); + + SAFEFREE(progId); + SAFEFREE(id_str); + + return 1; +} + +/* + * luacom_ProgIDfromCLSID + * Retorna string contendo o ProgID associado a um CLSID + */ + +static int luacom_ProgIDfromCLSID(lua_State *L) +{ + const char* str = luaL_check_lstr(L, 1, NULL); + wchar_t* clsid_str = NULL; + LPOLESTR progId = NULL; + CLSID clsid = IID_NULL; + HRESULT hr = S_OK; + char* id_str = NULL; + + try + { + clsid_str = (wchar_t*) malloc( (strlen(str) + 1) * sizeof(wchar_t)); + mbstowcs(clsid_str,str,strlen(str)+1); + + hr = CLSIDFromString(clsid_str, &clsid); + CHK_COM_CODE(hr); + + hr = ProgIDFromCLSID(clsid, &progId); + CHK_COM_CODE(hr); + + id_str = (char*) malloc( (wcslen(progId) + 1) * sizeof(char)); + wcstombs(id_str,progId,wcslen(progId)+1); + } + catch(class tLuaCOMException& e) + { + SAFEFREE(progId); + SAFEFREE(clsid_str); + + luacom_APIerror(L, e.getMessage()); + + return 0; + } + + lua_pushstring(L, id_str); + + SAFEFREE(progId); + SAFEFREE(clsid_str); + + return 1; +} + +/* + * luacom_CreateObject + * Retorna um objeto LuaCOM que instancia o objeto + * COM identificado pelo ProgID dado + */ + +static int luacom_CreateObject(lua_State *L) +{ + HRESULT hr = S_OK; + LPDISPATCH pdisp = NULL; + tLuaCOM* lcom = NULL; + IPersistStreamInit* psi = NULL; + DWORD context = CLSCTX_SERVER; + + const char *progId = luaL_check_lstr(L, 1, NULL); + const char *creation_mode = lua_tostring(L, 2); + const bool untyped = lua_toboolean(L, 3); + + if(creation_mode != NULL) + { + if(strcmp(creation_mode, "local_server") == 0) + context = CLSCTX_LOCAL_SERVER; + else if(strcmp(creation_mode, "inproc_server") == 0) + context = CLSCTX_INPROC_SERVER; + } + + CLSID clsid = IID_NULL; + IClassFactory* pCF = NULL; + + try + { + hr = tCOMUtil::ProgID2CLSID(&clsid, progId); + CHK_COM_CODE(hr); + + hr = CoCreateInstance(clsid, + NULL, + context, + IID_IDispatch, + (void**)&pdisp); + CHK_COM_CODE(hr); + + // Initializes object (some require this step to work) + hr = pdisp->QueryInterface(IID_IPersistStreamInit, (void**) &psi); + if(SUCCEEDED(hr)) + psi->InitNew(); + + lcom = tLuaCOM::CreateLuaCOM(L, pdisp, clsid, NULL, untyped); + } + catch(class tLuaCOMException& e) + { + COM_RELEASE(psi); + COM_RELEASE(pdisp); + + luacom_APIerror(L, e.getMessage()); + + return 0; + } + + COM_RELEASE(psi); + COM_RELEASE(pdisp); + + LuaBeans::push(L, lcom); + + return 1; +} + + +/* + * luacom_GetObject + * Cria um objeto LuaCOM associado a uma instancia + * ja' existente do objeto COM identificado pelo + * ProgID dado + */ + +static int luacom_GetObject(lua_State *L) +{ + HRESULT hr = S_OK; + IDispatch* pdisp = NULL; + IUnknown* punk = NULL; + CLSID clsid = IID_NULL; + + const char *progId = luaL_check_lstr(L, 1, NULL); + + tLuaCOM* lcom = NULL; + IBindCtx* pbc = NULL; + IMoniker* pmk = NULL; + + try + { + hr = tCOMUtil::ProgID2CLSID(&clsid, progId); + + if(SUCCEEDED(hr)) + { + hr = GetActiveObject(clsid,NULL,&punk); + CHK_COM_CODE(hr); + } + else // tests whether the user passed in a DisplayName of a moniker + { + BSTR bstr = NULL; + ULONG chEaten = 0; + + hr = CreateBindCtx(0, &pbc); + CHK_COM_CODE(hr); + + bstr = tUtil::string2bstr(progId); + hr = MkParseDisplayName(pbc, bstr, &chEaten, &pmk); + SysFreeString(bstr); + CHK_COM_CODE(hr); + + hr = pmk->BindToObject(pbc, NULL, IID_IUnknown, (void **) &punk); + CHK_COM_CODE(hr); + } + + hr = punk->QueryInterface(IID_IDispatch, (void **) &pdisp); + CHK_COM_CODE(hr); + + lcom = tLuaCOM::CreateLuaCOM(L, pdisp, clsid); + CHECKPOSCOND(lcom); + } + catch(class tLuaCOMException& e) + { + COM_RELEASE(punk); + COM_RELEASE(pdisp); + COM_RELEASE(pbc); + COM_RELEASE(pmk); + + luacom_APIerror(L, e.getMessage()); + + return 0; + } + + LuaBeans::push(L, lcom); + + COM_RELEASE(punk); + COM_RELEASE(pdisp); + COM_RELEASE(pbc); + COM_RELEASE(pmk); + + return 1; +} + +/* + * luacom_addConnection + * Associa um connection point de um objeto COM com + * outro objeto COM + */ + +static int luacom_addConnection(lua_State *L) +{ + tLuaCOM* client = (tLuaCOM*) LuaBeans::check_tag(L, 1); + tLuaCOM* server = (tLuaCOM*) LuaBeans::check_tag(L, 2); + + DWORD cookie = client->addConnection(server); + + if(cookie == NULL) + { + luacom_APIerror(L, "Could not establish connection"); + return 0; + } + + lua_pushnumber(L, cookie); + + return 1; +} + +/* + * luacom_releaseConnection + * Desfaz connection point associado a um objeto LuaCOM + */ + +static int luacom_releaseConnection(lua_State *L) +{ + tLuaCOM* lcom = (tLuaCOM*) LuaBeans::check_tag(L, 1); + if(lua_gettop(L) > 1) { + tLuaCOM* server = (tLuaCOM*) LuaBeans::check_tag(L, 2); + DWORD cookie = (DWORD)lua_tonumber(L, 3); + + try + { + lcom->releaseConnection(server, cookie); + } + catch(class tLuaCOMException& e) + { + luacom_APIerror(L, e.getMessage()); + + return 0; + } + } else { + try + { + lcom->releaseConnection(); + } + catch(class tLuaCOMException& e) + { + luacom_APIerror(L, e.getMessage()); + + return 0; + } + } + + return 0; +} + +// +// luacom_isMember +// +// Informa se existe algum metodo ou propriedade com +// o nome passado como parametro em lua +// + +static int luacom_isMember(lua_State *L) +{ + // objeto luacom + tLuaCOM* lcom = (tLuaCOM*) LuaBeans::check_tag(L, 1); + const char* member_name = luaL_check_lstr(L, 2, NULL); + + luaCompat_pushBool(L, lcom->isMember(member_name)); + + return 1; +} + +/* + * luacom_NewObject + * + * Creates a Component Object implemented in luacom + * + */ + +static int luacom_NewObjectOrControl(lua_State *L, int type) +{ + tLuaDispatch* iluacom = NULL; + ITypeLib* typelib = NULL; + ITypeInfo* interface_typeinfo = NULL; + ITypeInfo* coclassinfo = NULL; + tLuaCOM *lcom = NULL; + HRESULT hr = S_OK; + tLuaCOMConnPointContainer *cpc = NULL; + tLuaCOMConnPoint *cp = NULL; + + // gets parameters + + if(lua_type(L, 1) != LUA_TTABLE && lua_type(L,1) != LUA_TUSERDATA) + { + luaL_argerror(L, 1, "Implementation must be a table or a userdata"); + } + + // pushes lua table on top of stack + lua_pushvalue(L, 1); + const int ref = lua_ref(L, 1); + + const char* pcProgID = luaL_check_lstr(L, 2, NULL); + + try + { + // gets typelib + CLSID clsid = IID_NULL; + + hr = tCOMUtil::ProgID2CLSID(&clsid, pcProgID); + CHK_COM_CODE(hr); + + typelib = tCOMUtil::LoadTypeLibFromCLSID(clsid); + CHK_LCOM_ERR((long)typelib, "Could not load type library."); + + + // gets coclass typeinfo + + coclassinfo = tCOMUtil::GetCoClassTypeInfo(typelib, clsid); + CHK_LCOM_ERR(coclassinfo, "CoClass not found in type library."); + + + // gets the default interface typeinfo + interface_typeinfo = + tCOMUtil::GetDefaultInterfaceTypeInfo(coclassinfo, false); + + CHK_LCOM_ERR(interface_typeinfo, + "Could not find a suitable default interface."); + + + // Creates IDispatch implementation + if(type) // Control + iluacom = + (tLuaDispatch*)tLuaControl::CreateLuaControl(L, interface_typeinfo, ref); + else // Object + iluacom = + tLuaDispatch::CreateLuaDispatch(L, interface_typeinfo, ref); + + lua_unref(L, ref); + + + // Creates associated luacom object + lcom = tLuaCOM::CreateLuaCOM(L, iluacom, clsid); + + + // Informs tLuaDispatch of coclassinfo (this allows implementation of + // IProvideClassInfo[x] + iluacom->SetCoClassinfo(coclassinfo); + + + // Create connection points container and tells it to initialize + // itself from coclassinfo and exports connection point for + // default source + + iluacom->BeConnectable(); + + if(iluacom->GetConnPointContainer()) + { + cp = iluacom->GetConnPointContainer()->GetDefault(); + } + else + cp = NULL; + } + catch(class tLuaCOMException& e) + { + // releases pointers + COM_RELEASE(iluacom); + COM_RELEASE(interface_typeinfo); + COM_RELEASE(coclassinfo); + COM_RELEASE(typelib); + + luacom_APIerror(L, e.getMessage()); + + return 0; + } + + COM_RELEASE(iluacom); + COM_RELEASE(interface_typeinfo); + COM_RELEASE(coclassinfo); + COM_RELEASE(typelib); + + // returns LuaCOM object and connection point + // for default source interface + + int retvals = 1; + LuaBeans::push(L, lcom); + + if(cp) + { + cp->push(); + retvals++; + } + + return retvals; +} + +static int luacom_NewObject(lua_State *L) { + return luacom_NewObjectOrControl(L, 0); +} + +static int luacom_NewControl(lua_State *L) { + return luacom_NewObjectOrControl(L, 1); +} + + +/* + * luacom_ExposeObject + * + * Creates a class factory that exposes a + * COM object + * + * Parameters: + * + * 1. LuaCOM object + * + * Return values + * + * 1. Cookie to unexpose object + * + */ + +static int luacom_ExposeObject(lua_State *L) +{ + tLuaCOMClassFactory* luacom_cf = NULL; + DWORD cookie = -1; + + // check parameters + tLuaCOM* luacom = (tLuaCOM *) LuaBeans::check_tag(L, 1); + + try + { + CLSID clsid = IID_NULL; + HRESULT hr = S_OK; + + if(luacom_runningInprocess(L)) { + // Inprocess "registration": stores object in the Lua registry + lua_getregistry(L); + lua_pushstring(L,"object"); + luaCompat_pushPointer(L,(void*)luacom->GetIDispatch()); + lua_settable(L,-3); + lua_pop(L,1); + } else { + luacom_cf = + new tLuaCOMClassFactory(luacom->GetIDispatch()); + luacom_cf->AddRef(); + + clsid = luacom->GetCLSID(); + CHK_LCOM_ERR(clsid != IID_NULL, + "Object does not have coclass type information"); + + hr = CoRegisterClassObject( + clsid, + luacom_cf, + CLSCTX_LOCAL_SERVER, + REGCLS_SINGLEUSE, + &cookie); + + CHK_COM_CODE(hr); + } + } + catch(class tLuaCOMException& e) + { + // releases pointers + COM_RELEASE(luacom_cf); + + luacom_APIerror(L, e.getMessage()); + + return 0; + } + + COM_RELEASE(luacom_cf); + + lua_pushnumber(L, cookie); + + return 1; +} + + +/* + * luacom_RevokeObject + * + * Revokes a previously registered class factory + * + * Parameters: + * + * 1. Cookie + * + * Return values + * + * 1. non-nil if succeeded + * + */ + +static int luacom_RevokeObject(lua_State *L) +{ + // check parameters + const int cookie = (int) luaL_check_number(L, 1); + + // revokes class object + try + { + HRESULT hr = CoRevokeClassObject(cookie); + CHK_COM_CODE(hr); + } + catch(class tLuaCOMException& e) + { + luacom_APIerror(L, e.getMessage()); + + return 0; + } + + luaCompat_pushBool(L, true); + + return 1; +} + + +/* + * luacom_RegisterObject + * + * Registers a COM Object in the system registry + * + * Parameters: + * + * 1. registration table or userdata + * + * Return values + * + * 1. non-nil if successful + * + */ + + +static int luacom_RegisterObject(lua_State *L) +{ + if(lua_type(L, 1) != LUA_TTABLE && lua_type(L,1) != LUA_TUSERDATA) + { + luaL_argerror(L, 1, "Registration info must be a table or userdata"); + } + + ITypeLib *typelib = NULL; + ITypeInfo* coclassinfo = NULL; + HRESULT hr = S_OK; + const int bufsize = 1000; + + try + { + + lua_pushstring(L, "Control"); + lua_gettable(L, 1); + bool control = luaCompat_toCBool(L, -1); + + // gets the registration information from the registration table + lua_pushstring(L, "VersionIndependentProgID"); + lua_gettable(L, 1); + const char* VersionIndependentProgID = lua_tostring(L, -1); + + // gets the registration information from the registration table + lua_pushstring(L, "ProgID"); + lua_gettable(L, 1); + const char* ProgID = lua_tostring(L, -1); + + lua_pushstring(L, "TypeLib"); + lua_gettable(L, 1); + const char* typelib_path = lua_tostring(L, -1); + + lua_pushstring(L, "CoClass"); + lua_gettable(L, 1); + const char* CoClass = lua_tostring(L, -1); + + lua_pushstring(L, "ComponentName"); + lua_gettable(L, 1); + const char* ComponentName= lua_tostring(L, -1); + + lua_pushstring(L, "Arguments"); + lua_gettable(L, 1); + const char* arguments = lua_tostring(L, -1); + + lua_pushstring(L, "ScriptFile"); + lua_gettable(L, 1); + const char* scriptFile = lua_tostring(L, -1); + + CHK_LCOM_ERR(ProgID && typelib_path && CoClass, + "Incomplete registration table."); + + // Loads and registers the typelib + + { + wchar_t wcTypelib_path[bufsize]; + + mbstowcs(wcTypelib_path, typelib_path, strlen(typelib_path)+1); + + hr = LoadTypeLibEx(wcTypelib_path, REGKIND_REGISTER, &typelib); + } + CHK_COM_CODE(hr); + + + // Gets the type library version and LIBID + + char version[30]; + char libId[bufsize]; + + { + TLIBATTR *plibattr = NULL; + + typelib->GetLibAttr(&plibattr); + + // gets version + sprintf(version, "%d.%d", plibattr->wMajorVerNum, plibattr->wMinorVerNum); + + // gets libid + wchar_t *wcLibId = NULL; + + hr = StringFromCLSID(plibattr->guid, &wcLibId); + CHK_COM_CODE(hr); + + wcstombs(libId, wcLibId, wcslen(wcLibId)+1); + CoTaskMemFree(wcLibId); + + typelib->ReleaseTLibAttr(plibattr); + } + + // gets the CoClass TypeInfo to get the CLSID + coclassinfo = tCOMUtil::GetCoClassTypeInfo(typelib, CoClass); + CHK_LCOM_ERR(coclassinfo, "Could not get coclass typeinfo."); + + + // gets the CLSID + + char clsid[bufsize]; + + { + TYPEATTR* ptypeattr = NULL; + wchar_t* wcClsid= NULL; + + coclassinfo->GetTypeAttr(&ptypeattr); + + hr = StringFromCLSID(ptypeattr->guid, &wcClsid); + CHK_COM_CODE(hr); + + wcstombs(clsid, wcClsid,wcslen(wcClsid)+1); + + coclassinfo->ReleaseTypeAttr(ptypeattr); + CoTaskMemFree(wcClsid); + } + + + //// Now we have all the information needed to perform the registration + + // registers ProgID + char ID[bufsize]; + char CLSID[bufsize]; + char ModulePath[bufsize]; + + // Be safe with null strings in these stack-allocated strings. + ID[0] = 0; + CLSID[0] = 0; + ModulePath[0] = 0; + + GetModuleFileName( + NULL, + ModulePath, + sizeof(ModulePath)); + + if(scriptFile) + { + strcat(ModulePath, " "); + strcat(ModulePath, scriptFile); + } + + if(arguments) + { + strcat(ModulePath, " "); + strcat(ModulePath, arguments); + } + + // Create some base key strings. + strcpy(CLSID, "CLSID\\"); + strcat(CLSID, clsid); + + // Create ProgID keys. + tCOMUtil::SetRegKeyValue( + ProgID, + NULL, + ComponentName); + + tCOMUtil::SetRegKeyValue( + ProgID, + "CLSID", + clsid); + + // Create VersionIndependentProgID keys. + tCOMUtil::SetRegKeyValue( + VersionIndependentProgID, + NULL, + ComponentName); + + tCOMUtil::SetRegKeyValue( + VersionIndependentProgID, + "CurVer", + ProgID); + + tCOMUtil::SetRegKeyValue( + VersionIndependentProgID, + "CLSID", + clsid); + + // Create entries under CLSID. + tCOMUtil::SetRegKeyValue( + CLSID, + NULL, + ComponentName); + + tCOMUtil::SetRegKeyValue( + CLSID, + "ProgID", + ProgID); + + tCOMUtil::SetRegKeyValue( + CLSID, + "VersionIndependentProgID", + VersionIndependentProgID); + + tCOMUtil::SetRegKeyValue( + CLSID, + "LocalServer32", + ModulePath); + +#if 0 // NJG + if(scriptFile) { + tCOMUtil::SetRegKeyValue( + CLSID, + "InprocServer32", + LUACOM_DLL); + tCOMUtil::SetRegKeyValue( + CLSID, + "ScriptFile", + scriptFile); + } + +#endif + + if(control) { + tCOMUtil::SetRegKeyValue( + CLSID, + "Implemented Categories\\{0DE86A53-2BAA-11CF-A229-00AA003D7352}", + NULL); + tCOMUtil::SetRegKeyValue( + CLSID, + "Implemented Categories\\{0DE86A57-2BAA-11CF-A229-00AA003D7352}", + NULL); + tCOMUtil::SetRegKeyValue( + CLSID, + "Implemented Categories\\{40FC6ED4-2438-11CF-A3DB-080036F12502}", + NULL); + tCOMUtil::SetRegKeyValue( + CLSID, + "Implemented Categories\\{40FC6ED5-2438-11CF-A3DB-080036F12502}", + NULL); + tCOMUtil::SetRegKeyValue( + CLSID, + "Implemented Categories\\{7DD95801-9882-11CF-9FA9-00AA006C42C4}", + NULL); + tCOMUtil::SetRegKeyValue( + CLSID, + "Implemented Categories\\{7DD95802-9882-11CF-9FA9-00AA006C42C4}", + NULL); + } + + tCOMUtil::SetRegKeyValue( + CLSID, + "Version", + version); + + tCOMUtil::SetRegKeyValue( + CLSID, + "TypeLib", + libId); + + tCOMUtil::SetRegKeyValue( + CLSID, + "Programmable", + NULL); + } + catch(class tLuaCOMException& e) + { + COM_RELEASE(coclassinfo); + COM_RELEASE(typelib); + + luacom_APIerror(L, e.getMessage()); + + return 0; + } + + COM_RELEASE(coclassinfo); + COM_RELEASE(typelib); + + // signals success + luaCompat_pushBool(L, true); + + return 1; +} + +/* + * luacom_UnRegisterObject + * + * Unregisters a COM Object in the system registry + * + * Parameters: + * + * 1. registration table or userdata + * + * Return values + * + * 1. non-nil if successful + * + */ + + +static int luacom_UnRegisterObject(lua_State *L) +{ + if(lua_type(L, 1) != LUA_TTABLE && lua_type(L,1) != LUA_TUSERDATA) + { + luaL_argerror(L, 1, "Registration info must be a table or userdata"); + } + + ITypeLib *typelib = NULL; + ITypeInfo* coclassinfo = NULL; + HRESULT hr = S_OK; + const int bufsize = 1000; + + try + { + + // gets the registration information from the registration table + lua_pushstring(L, "VersionIndependentProgID"); + lua_gettable(L, 1); + const char* VersionIndependentProgID = lua_tostring(L, -1); + + // gets the registration information from the registration table + lua_pushstring(L, "ProgID"); + lua_gettable(L, 1); + const char* ProgID = lua_tostring(L, -1); + + lua_pushstring(L, "TypeLib"); + lua_gettable(L, 1); + const char* typelib_path = lua_tostring(L, -1); + + lua_pushstring(L, "CoClass"); + lua_gettable(L, 1); + const char* CoClass = lua_tostring(L, -1); + + CHK_LCOM_ERR(ProgID && typelib_path && CoClass, + "Incomplete registration table."); + + // Loads the typelib + + { + wchar_t wcTypelib_path[bufsize]; + + mbstowcs(wcTypelib_path, typelib_path, strlen(typelib_path)+1); + + hr = LoadTypeLibEx(wcTypelib_path, REGKIND_NONE, &typelib); + } + CHK_COM_CODE(hr); + + + // Unregisters the typelib + + { + TLIBATTR *plibattr = NULL; + + typelib->GetLibAttr(&plibattr); + + UnRegisterTypeLib(plibattr->guid, plibattr->wMajorVerNum, plibattr->wMinorVerNum, + plibattr->lcid, plibattr->syskind); + + typelib->ReleaseTLibAttr(plibattr); + } + + // gets the CoClass TypeInfo to get the CLSID + coclassinfo = tCOMUtil::GetCoClassTypeInfo(typelib, CoClass); + CHK_LCOM_ERR(coclassinfo, "Could not get coclass typeinfo."); + + + // gets the CLSID + + char clsid[bufsize]; + + { + TYPEATTR* ptypeattr = NULL; + wchar_t* wcClsid= NULL; + + coclassinfo->GetTypeAttr(&ptypeattr); + + hr = StringFromCLSID(ptypeattr->guid, &wcClsid); + CHK_COM_CODE(hr); + + wcstombs(clsid, wcClsid,wcslen(wcClsid)+1); + + coclassinfo->ReleaseTypeAttr(ptypeattr); + CoTaskMemFree(wcClsid); + } + + + //// Now we have all the information needed to perform the unregistration + + // unregisters ProgID + char CLSID[bufsize]; + + // Be safe with null strings in these stack-allocated strings. + CLSID[0] = 0; + + // Create some base key strings. + strcpy(CLSID, "CLSID\\"); + strcat(CLSID, clsid); + + // Delete ProgID keys. + tCOMUtil::DelRegKey( + ProgID, + NULL); + + // Delete VersionIndependentProgID keys. + tCOMUtil::DelRegKey( + VersionIndependentProgID, + NULL); + + // Delete entries under CLSID. + tCOMUtil::DelRegKey( + CLSID, + NULL); + + } + catch(class tLuaCOMException& e) + { + COM_RELEASE(coclassinfo); + COM_RELEASE(typelib); + + luacom_APIerror(L, e.getMessage()); + + return 0; + } + + COM_RELEASE(coclassinfo); + COM_RELEASE(typelib); + + // signals success + luaCompat_pushBool(L, true); + + return 1; +} + + +/* + * luacom_GetIUnknown + * + * Returns the a IUnknown interface for a + * LuaCOM object + * + * Parameters: + * + * 1. LuaCOM object + * + * Return values + * + * 1. IUnknown pointer (a userdata) + * + */ + + +static int luacom_GetIUnknown(lua_State *L) +{ + // check parameters + tLuaCOM* luacom = (tLuaCOM *) LuaBeans::check_tag(L, 1); + + IDispatch* pdisp = luacom->GetIDispatch(); + IUnknown* punk = NULL; + + pdisp->QueryInterface(IID_IUnknown, (void **) &punk); + + // checks whether there is a usertag for this IUnknown + // If exists, simply uses it + + // gets IUnknown tag + luaCompat_pushTypeByName(L, MODULENAME, LCOM_IUNKNOWN_TYPENAME); + + // sets object type + int newref = luaCompat_newTypedObject(L, punk); + + if(!newref) + { + // there was already a userdata for that pointer, + // so we have to decrement the reference count, + // as the garbage collector will be called just + // once for any userdata + punk->Release(); + } + + return 1; +} + + +static int luacom_GetTypeInfo(lua_State *L) +{ + // check parameters + tLuaCOM* obj = (tLuaCOM *) LuaBeans::check_tag(L, 1); + + if(obj->hasTypeInfo()) + { + tLuaTypeInfo::pushNew(L, obj->GetTypeInfo()); + return 1; + } + else + return 0; +} + + +static int luacom_DumpTypeInfo(lua_State *L) +{ + // check parameters + tLuaCOM* obj = (tLuaCOM *) LuaBeans::check_tag(L, 1); + + if(obj->hasTypeInfo()) + { + try + { + tCOMUtil::DumpTypeInfo(obj->GetTypeInfo()); + } + catch(class tLuaCOMException& e) + { + luacom_APIerror(L, e.getMessage()); + + return 0; + } + } + + return 0; +} + + + +// Starts logging +static int luacom_StartLog(lua_State* L) +{ + const char *filename = luaL_check_lstr(L, 1, NULL); + + bool result = tUtil::OpenLogFile(filename); + + luaCompat_pushBool(L, result); + + return 1; +} + +// Ends logging +static int luacom_EndLog(lua_State* L) +{ + UNUSED(L); + + tUtil::CloseLogFile(); + + return 0; +} + + + +// Gets the IEnumVariant interface for +// an LuaCOM object +static int luacom_GetEnumerator(lua_State *L) +{ + // check parameters + tLuaCOM* luacom = (tLuaCOM *) LuaBeans::check_tag(L, 1); + int retvals = 0; + + try + { + retvals = + luacom->call(L, DISPID_NEWENUM, INVOKE_PROPERTYGET, NULL, tLuaObjList()); + + CHECKPOSCOND(retvals != 0); + + } + catch(class tLuaCOMException& e) + { + luacom_APIerror(L, e.getMessage()); + + return 0; + } + + return retvals; +} + + + +/* + * luacom_LoadTypeLibrary (Lua2C) + * + */ + +static int luacom_LoadTypeLibrary(lua_State *L) +{ + const char* typelib_name = luaL_check_lstr(L, -1, NULL); + + ITypeLib* typelib = NULL; + + try + { + // tries to get the typelib by filename + typelib = tCOMUtil::LoadTypeLibByName(typelib_name); + + if(typelib == NULL) + { + // tries to get by ProgID + CLSID clsid = IID_NULL; + HRESULT hr = S_OK; + + hr = tCOMUtil::ProgID2CLSID(&clsid, typelib_name); + + if(SUCCEEDED(hr)) + typelib = tCOMUtil::LoadTypeLibFromCLSID(clsid); + } + + CHK_LCOM_ERR(typelib, "Could not load type library."); + } + catch(class tLuaCOMException& e) + { + COM_RELEASE(typelib); + + luacom_APIerror(L, e.getMessage()); + + return 0; + } + + tLuaTLB::pushNew(L, typelib); + + COM_RELEASE(typelib); + + return 1; +} + +/* + * Creates a luacom object using an + * IUnknown pointer + */ + +int luacom_CreateLuaCOM(lua_State* L) +{ + // checks whether to object on the stack is of this type + if(!luaCompat_isOfType(L, MODULENAME, LCOM_IUNKNOWN_TYPENAME)) + { + luacom_APIerror(L, "IUnknown typed object expected."); + return 0; + } + + IUnknown* punk = NULL; + IDispatch* pdisp = NULL; + tLuaCOM* lcom = NULL; + + try + { + punk = (IUnknown *) luaCompat_getTypedObject(L, -1); + CHECKPOSCOND(punk); + + HRESULT hr = punk->QueryInterface(IID_IDispatch, (void **) &pdisp); + CHK_COM_CODE(hr); + + lcom = tLuaCOM::CreateLuaCOM(L, pdisp); + } + catch(class tLuaCOMException& e) + { + COM_RELEASE(pdisp); + + luacom_APIerror(L, e.getMessage()); + + return 0; + } + + COM_RELEASE(pdisp); + + LuaBeans::push(L, lcom); + + return 1; +} + +int luacom_StartMessageLoop(lua_State *L) +{ + MSG msg; + if(lua_gettop(L) > 0) { + const char *err; + if(luaCompat_call(L, lua_gettop(L)-1, 0, &err)) { + luacom_APIerror(L, err); + return 0; + } + } + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + if(lua_gettop(L) > 0) { + const char *err; + if(luaCompat_call(L, lua_gettop(L)-1, 0, &err)) { + luacom_APIerror(L, err); + return 0; + } + } + } + return 0; +} + +/* + * Detects automation in a pure Lua server + * + */ + +int luacom_LuaDetectAutomation(lua_State* L) +{ + lua_getglobal(L,"arg"); + if(lua_istable(L,-1)) + { + // Running out-of-process + lua_pushnumber(L,1); + lua_gettable(L,-2); + const char* cmdSwitch = lua_tostring(L,-1); + lua_pop(L,2); + if(cmdSwitch != NULL) { + const char* errMsg; + if(_stricmp("/Register",cmdSwitch) == 0) { + lua_pushstring(L,"Register"); + lua_gettable(L,-2); + lua_pushvalue(L,-2); + if(luaCompat_call(L,1,0,&errMsg)) { + lua_pushnil(L); + lua_pushstring(L,errMsg); + return 2; + } else { + return 1; + } + } else if(_stricmp("/UnRegister",cmdSwitch) == 0) { + lua_pushstring(L,"UnRegister"); + lua_gettable(L,-2); + lua_pushvalue(L,-2); + if(luaCompat_call(L,1,0,&errMsg)) { + lua_pushnil(L); + lua_pushstring(L,errMsg); + return 2; + } else { + return 1; + } + } else if(_stricmp("/Automation",cmdSwitch) == 0) { + lua_pushstring(L,"StartAutomation"); + lua_gettable(L,-2); + lua_pushvalue(L,-2); + if(luaCompat_call(L,1,0,&errMsg)) { + lua_pushnil(L); + lua_pushstring(L,errMsg); + return 2; + } else { + lua_settop(L, 0); + luacom_StartMessageLoop(L); + return 0; + } + } + lua_pushnil(L); + lua_pushstring(L,"no valid command-line switch"); + return 2; + } else { + lua_pushnil(L); + lua_pushstring(L,"no valid command-line switch"); + return 2; + } + } + else + { + // Running in-process + lua_pop(L,1); + return 1; + } +} + +/* + * Transforms a pointer into + * an IUnknown typed object + * + */ + +int luacom_ImportIUnknown(lua_State* L) +{ + IUnknown* punk = (IUnknown*) luaCompat_getPointer(L, -1); + + if(!punk) + { + luacom_APIerror(L, "Pointer expected."); + return 0; + } + + punk->AddRef(); + + luaCompat_pushTypeByName(L, MODULENAME, LCOM_IUNKNOWN_TYPENAME); + int newref = luaCompat_newTypedObject(L, (void*) punk); + + if(!newref) + { + // there was already a userdata for that pointer, + // so we have to decrement the reference count, + // as the garbage collector will be called just + // once for any userdata + punk->Release(); + } + + + return 1; +} + + + +// Returns current directory +int luacom_GetCurrentDirectory(lua_State* L) +{ + static char buffer[1025]; + + DWORD size = GetCurrentDirectory(1024, buffer); + + if(!size || size > 1023) + return 0; + + lua_pushstring(L, buffer); + + return 1; +} + + + +////////////////////////////////////// +// // +// TAG METHODS DO USERTAG IUNKNOWN // +// // +////////////////////////////////////// + +/* + * tag method que gerencia garbage collection + */ + +static int IUnknown_tag_gc(lua_State *L) +{ + IUnknown* punk = (IUnknown*) luaCompat_getTypedObject(L, -1); + + if(punk != NULL) + punk->Release(); + + return 0; +} + +/* + * Checks for IUnknown equality + */ + +static int IUnknown_eq(lua_State *L) +{ + LUASTACK_SET(L); + + IUnknown* punk1 = (IUnknown*) luaCompat_getTypedObject(L, -1); + IUnknown* punk2 = (IUnknown*) luaCompat_getTypedObject(L, -2); + + luaCompat_pushBool(L, punk1 == punk2); + + LUASTACK_CLEAN(L, 1); + + return 1; +} + + + +//////////////////////////////////// +// // +// TAG METHODS DO OBJETO LUACOM // +// // +//////////////////////////////////// + +/* + * tag method que gerencia garbage collection + */ + +static int tagmeth_gc(lua_State *L) +{ + tLuaCOM* lcom = (tLuaCOM*) luaCompat_getTypedObject(L, -1); + + assert(lcom); + + if(lcom != NULL) { + lcom->Unlock(); + } + + return 0; +} + +/* + * tag method que gerencia atribuicoes a campos + * do objeto luacom + */ + +static int tagmeth_settable(lua_State *L) +{ + DISPID dispid; + HRESULT hr = S_OK; + FUNCDESC* pfuncdesc = NULL; + const char* field_name = NULL; + bool set = false; + + /* indexes to the parameters coming from lua */ + const int table_param = 1; + const int index_param = 2; + const int value_param = 3; + + try + { + tLuaCOM* lcom = (tLuaCOM*) LuaBeans::from_lua(L, table_param); + CHECK(lcom, INTERNAL_ERROR); + + field_name = lua_tostring(L, index_param); + + if(!field_name) + return 0; + + if(lua_type(L, value_param) == LUA_TFUNCTION) + { + // Here we have a redefinition of the field to a lua + // function + lua_rawset(L, table_param); + + return 0; + } + + // Here we have two possible situations: the object + // has type info or the object does not have + + if(lcom->hasTypeInfo()) + { + FuncInfo funcinfo; + bool found = lcom->getFUNCDESC(field_name, funcinfo); + + if(found && !funcinfo.propput) + { + // Redefinition of a read only field using a value (not a function) + // is not allowed. We do this to avoid confusion, as the user might + // inadvertently set the value of a read-only field and LuaCOM would + // silently store it in the table, "fooling" the client about the + // real value the field in the COM object. If the user really wishes + // to redefine the field, he should use a lua function instead + + luacom_error(L, "LuaCOM error: trying to set a read-only field in a COM object."); + + return 0; + } + else if(found) + { + + lcom->call(L, funcinfo.propput->memid, + INVOKE_PROPERTYPUT, + funcinfo.propput, + tLuaObjList(value_param, 1) + ); + + set = true; + } + + } + + if(!set && lcom->getDISPID(field_name, &dispid)) + { + lcom->call(L, dispid, + INVOKE_PROPERTYPUT, + NULL, + tLuaObjList(value_param, 1) + ); + set = true; + } + + if(!set) + { + lua_rawset(L, table_param); + + return 0; + } + } + catch(class tLuaCOMException& e) + { + luacom_error(L, e.getMessage()); + + return 0; + } + + return 0; +} + + +/* + * Closure que gerencia chamadas de metodos + * + */ +static int callhook(lua_State *L) +{ + tLuaCOM* lcom = NULL; + HRESULT hr = S_OK; + DISPID dispid = -1; + FUNCDESC *pfuncdesc = NULL; + long invkind = INVOKE_FUNC; + + int num_return_values = -1; + +try + { + // upvalues + const int luacom_obj_param = luaCompat_upvalueIndex(L, 1, 4); + const int dispid_param = luaCompat_upvalueIndex(L, 2, 4); + const int invkind_param = luaCompat_upvalueIndex(L, 3, 4); + const int funcdesc_param = luaCompat_upvalueIndex(L, 4, 4); + + // self param + const int self_param = 1; + const int first_param = 2; + + // number of lua parameters, excluding upvalues and + // the self param + const int num_params = luaCompat_getNumParams(L, 4) - 1; + + CHECKPARAM_MSG(num_params >= 0, "self parameter not found."); + + // retrieves parameters from lua stack + lcom = (tLuaCOM *) lua_touserdata(L, luacom_obj_param); + dispid = (DISPID) lua_tonumber(L, dispid_param); + invkind = (long) lua_tonumber(L, invkind_param); + pfuncdesc = (FUNCDESC*) lua_touserdata(L, funcdesc_param); + + CHECK(lcom, INTERNAL_ERROR); + + // sets the parameter list excluding the 'self' param + tLuaObjList& params = tLuaObjList(first_param, num_params); + + num_return_values = lcom->call(L, dispid, invkind, pfuncdesc, params); + + return num_return_values; + } + catch(class tLuaCOMException& e) + { + luacom_error(L, e.getMessage()); + + return 0; + } +} + +static bool checkPrefix(const char* pName, const char** ppStripped_name, bool* propget) +{ + if(strncmp(pName, GET_PREFIX, strlen(GET_PREFIX)) == 0) + { + *ppStripped_name = pName+strlen(GET_PREFIX); + *propget = true; + return true; + } + else if(strncmp(pName, PUT_PREFIX, strlen(PUT_PREFIX)) == 0) + { + *ppStripped_name = pName+strlen(PUT_PREFIX); + *propget = false; + return true; + } + else + return false; +} + + + +static int untyped_tagmeth_index(lua_State *L, + tLuaCOM* lcom, + const char *field_name) +{ + DISPID dispid; + HRESULT hr = S_OK; + INVOKEKIND invkind = INVOKE_FUNC; + + // tries to get the DISPID + { + // positions for parameters received from Lua + const int table_param = lua_gettop(L)-1; + const int index_param = lua_gettop(L); + + bool found = lcom->getDISPID(field_name, &dispid); + + const char *stripped_name = NULL; + bool is_propget = false; + + if (!found && checkPrefix(field_name, &stripped_name, &is_propget)) + { + + // checks for field redefinition + { + lua_pushstring(L, stripped_name); + lua_rawget(L, table_param); + + if(lua_type(L, -1) == LUA_TFUNCTION) + { + // field has been redefined. Leaves function on top + // of stack and returns + return 1; + } + else // no redefinition. Removes the value and continues + lua_remove(L, -1); + } + + // the user specified a property get. Tries to + // get the DISPID again, skipping the prefix + + found = lcom->getDISPID(stripped_name, &dispid); + + if(found) + { + if(is_propget) + invkind = INVOKE_PROPERTYGET; + else + invkind = INVOKE_PROPERTYPUT; + } + } + + if(!found) + return 0; + } + + // Decides which INVOKEKIND should be used + { + + switch(invkind) + { + case INVOKE_PROPERTYGET: + { + // pushes closure + luaCompat_pushPointer(L, (void *) lcom); + lua_pushnumber(L, dispid); + lua_pushnumber(L, INVOKE_PROPERTYGET); + lua_pushnumber(L, 0); // no funcdesc + + lua_pushcclosure(L, callhook, 4); + return 1; + } + + case INVOKE_PROPERTYPUT: + { + // pushes closure + luaCompat_pushPointer(L, (void *) lcom); + lua_pushnumber(L, dispid); + lua_pushnumber(L, INVOKE_PROPERTYPUT); + lua_pushnumber(L, 0); // no funcdesc + + lua_pushcclosure(L, callhook, 4); + return 1; + } + + default: + { + // pushes closure + luaCompat_pushPointer(L, (void *) lcom); + lua_pushnumber(L, dispid); + lua_pushnumber(L, INVOKE_PROPERTYGET | INVOKE_FUNC); + lua_pushnumber(L, 0); // no funcdesc + + lua_pushcclosure(L, callhook, 4); + return 1; + } + } + } +} + + + +static int typed_tagmeth_index(lua_State *L, + tLuaCOM* lcom, + const char *field_name) +{ + HRESULT hr = S_OK; + bool is_propget = false; + bool is_propput = false; + FuncInfo funcinfo; + + // positions for parameters received from Lua + const int table_param = lua_gettop(L)-1; + const int index_param = lua_gettop(L); + + + // Now tries to get the FUNCDESC + { + // First, assumes the user supplied the right name + // of the method + + bool found = lcom->getFUNCDESC(field_name, funcinfo); + const char *stripped_name = NULL; + + // if name not found, check for prefixes and for field + // redefinition + + if(!found && checkPrefix(field_name, &stripped_name, &is_propget)) + { + // it seems the user supplied a prefix. Check that + is_propput = !is_propget; + + // checks for field redefinition + { + lua_pushstring(L, stripped_name); + lua_rawget(L, table_param); + + if(lua_type(L, -1) == LUA_TFUNCTION) + { + // field has been redefined. Leaves function on top + // of stack and returns + return 1; + } + else // no redefinition. Removes the value and continues + lua_remove(L, -1); + } + + + // Now tries to get the right FUNCDESC, using the name + // without the prefix + + if(is_propget) + { + // the user specified a property get. Tries to + // get the FUNCDESC again, skipping the prefix + found = lcom->getFUNCDESC(stripped_name, funcinfo); + } + else // there are only two prefixes... + { + found = lcom->getFUNCDESC(stripped_name, funcinfo); + } + } + else // check for a constant + { + if(lcom->getConstant(L, field_name)) + { + // as constants don't change, stores the value + // in the table + lua_pushvalue(L, -2); // index (the name of the constant + lua_pushvalue(L, -2); // value of the constant + + lua_settable(L, -5); // stores in the table the value + + return 1; + } + } + + if(!found) + return 0; + } + + + // Tries to decide which invokekind should be used + { + // First, tests whether should be a property get + + if(funcinfo.propget && !is_propput) + { + // if it has no params and the user did not specify + // a propertyput, make the call. If it's not, tests + // whether might be a propertyget with params + + if(funcinfo.propget->cParams == 0 && !is_propget) + { + return lcom->call(L, funcinfo.propget->memid, + INVOKE_PROPERTYGET, + funcinfo.propget, + tLuaObjList() + ); + } + else if(funcinfo.propget->cParams > 0 || is_propget) + { + // pushes closure + luaCompat_pushPointer(L, (void *) lcom); + lua_pushnumber(L, funcinfo.propget->memid); + lua_pushnumber(L, INVOKE_PROPERTYGET); + luaCompat_pushPointer(L, (void *) funcinfo.propget); + + lua_pushcclosure(L, callhook, 4); + return 1; + } + } + + if(funcinfo.propput && !is_propget) + { + if(funcinfo.propput->cParams > 0) + { + // property put with parameters + // pushes closure + luaCompat_pushPointer(L, (void *) lcom); + lua_pushnumber(L, funcinfo.propput->memid); + lua_pushnumber(L, funcinfo.propput->invkind); + luaCompat_pushPointer(L, (void *) funcinfo.propput); + + lua_pushcclosure(L, callhook, 4); + return 1; + } + } + + if(funcinfo.func && !is_propget && !is_propput) + { + // pushes closure + luaCompat_pushPointer(L, (void *) lcom); + lua_pushnumber(L, funcinfo.func->memid); + lua_pushnumber(L, INVOKE_FUNC); + luaCompat_pushPointer(L, (void *) funcinfo.func); + + lua_pushcclosure(L, callhook, 4); + return 1; + } + + // no match: nothing found + return 0; + } +} + + + +/* + * tag method que gerencia leituras de campos + * do objeto luacom + * + * In: table, index + */ + +static int tagmeth_index(lua_State *L) +{ + // used variables + tLuaCOM* lcom = NULL; + LuaBeans *lbeans = NULL; + int retval = 0; + const char *field_name = NULL; + bool isnumber = false; + + // indexes for the parameters in the Lua stack + const int table_param = 1; + const int index_param = 2; + + try + { + // retrieves LuaCOM object + lcom = (tLuaCOM*) LuaBeans::from_lua(L, table_param); + CHECK(lcom, INTERNAL_ERROR); + + // retrieves the field name + field_name = lua_tostring(L, index_param); + + if(!field_name) + return 0; + + tUtil::log_verbose("tagmeth_index", "looking for name '%s'", field_name); + + // checks for some predefined attributes + if(strcmp(field_name, LCOM_IUNKNOWN_ATTRIBUTE) == 0) + { + luaCompat_pushPointer(L, (IUnknown*) lcom->GetIDispatch()); + return 1; + } + + // Further processing will be done by + // different functions, depending on + // the presence of type information + retval = 0; + + if(lcom->hasTypeInfo() && !isnumber) + retval = typed_tagmeth_index(L, lcom, field_name); + + // tries the version without type information + if(retval == 0 && !isnumber) + retval = untyped_tagmeth_index(L, lcom, field_name); + } + catch(class tLuaCOMException& e) + { + switch(e.code) + { + case tLuaCOMException::INTERNAL_ERROR: + case tLuaCOMException::PARAMETER_OUT_OF_RANGE: + case tLuaCOMException::UNSUPPORTED_FEATURE: + default: + luacom_error(L, e.getMessage()); + + return 0; + + break; + } + + } + + if(retval == 0) + { + // BUG: numeric indices trigger this event + // even if they have a value. Just to + // avoid trouble, we do rawget here + + lua_rawget(L, table_param); + + retval = 1; + } + + return retval; +} + +static bool luacom_runningInprocess(lua_State* L) { + lua_getregistry(L); + lua_pushstring(L,"inproc"); + lua_gettable(L,-2); + bool inproc = lua_toboolean(L,-1); + lua_pop(L,2); + return inproc; +} + + +// +// call_event +// +// Triggered when someone tries to use a LuaCOM object +// as a function. Calls the default method of the LuaCOM +// object in question. +// + +static int call_event(lua_State *L) +{ + // used variables + tLuaCOM* lcom = NULL; + LuaBeans *lbeans = NULL; + int retval = 0; + + // indexes for the parameters in the Lua stack + const int luacom_object_param = 1; + const int first_user_param = 2; + const int num_user_params = lua_gettop(L) - 1; + + try + { + // retrieves LuaCOM object + lcom = (tLuaCOM*) LuaBeans::from_lua(L, luacom_object_param); + CHECK(lcom, INTERNAL_ERROR); + + retval = lcom->call(L, DISPID_VALUE, + INVOKE_PROPERTYGET | INVOKE_FUNC, + NULL, + tLuaObjList(first_user_param, num_user_params) + ); + } + catch(class tLuaCOMException& e) + { + luacom_error(L, e.getMessage()); + + return 0; + } + + return retval; +} + + +static int luacom_RoundTrip(lua_State *L) { + VARIANTARG v; + + tLuaCOMTypeHandler *handler = new tLuaCOMTypeHandler(NULL); + handler->lua2com(L, 1, v); + handler->com2lua(L, v); + delete handler; + return 1; +} + +///////////////////////////////////////////// +// // +// TABELA DAS FUNCOES EXPORTADAS PARA LUA // +// // +///////////////////////////////////////////// + +static struct luaL_reg functions_tb []= +{ + {"CreateObject",luacom_CreateObject}, + {"GetObject",luacom_GetObject}, + {"CLSIDfromProgID",luacom_CLSIDfromProgID}, + {"ImplInterface",luacom_ImplInterface}, + {"ImplInterfaceFromTypelib",luacom_ImplInterfaceFromTypelib}, + {"addConnection", luacom_addConnection}, + {"releaseConnection", luacom_releaseConnection}, + {"ProgIDfromCLSID",luacom_ProgIDfromCLSID}, + {"isMember",luacom_isMember}, + {"Connect",luacom_Connect}, + {"ShowHelp",luacom_ShowHelp}, + {"NewObject", luacom_NewObject}, + {"NewControl", luacom_NewControl}, + {"ExposeObject", luacom_ExposeObject}, + {"RevokeObject", luacom_RevokeObject}, + {"RegisterObject", luacom_RegisterObject}, + {"UnRegisterObject", luacom_UnRegisterObject}, + {"GetIUnknown", luacom_GetIUnknown}, + {"StartLog", luacom_StartLog}, + {"EndLog", luacom_EndLog}, + {"DumpTypeInfo", luacom_DumpTypeInfo}, + {"GetTypeInfo", luacom_GetTypeInfo}, + {"GetEnumerator", luacom_GetEnumerator}, + {"LoadTypeLibrary", luacom_LoadTypeLibrary}, + {"CreateLuaCOM", luacom_CreateLuaCOM}, + {"ImportIUnknown", luacom_ImportIUnknown}, + {"GetCurrentDirectory", luacom_GetCurrentDirectory}, + {"DetectAutomation", luacom_LuaDetectAutomation}, + {"StartMessageLoop", luacom_StartMessageLoop}, + {"RoundTrip", luacom_RoundTrip}, + {NULL, NULL} +}; + + +///////////////////////////////////// +// // +// FUNCOES EXPORTADAS PARA C/C++ // +// // +///////////////////////////////////// + +/* + * luacom_IDispatch2LuaCOM + * Recebe um ponteiro void* que deve ser + * um ponteiro para uma implementacao de uma + * interface IDispatch. E' criado um objeto + * LuaCOM cuja implementacao e' dada por essa + * interface. O objeto criado e' colocado na + * pilha de Lua + */ + +LUACOM_API int luacom_IDispatch2LuaCOM(lua_State *L, void *pdisp_arg) +{ + if(pdisp_arg == NULL) + { + lua_pushnil(L); + return 1; + } + + tLuaCOM* lcom = NULL; + + try + { + lcom = tLuaCOM::CreateLuaCOM(L, (IDispatch*)pdisp_arg); + } + catch(class tLuaCOMException& e) + { + UNUSED(e); + lua_pushnil(L); + return 1; + } + + LuaBeans::push(L, lcom); + + return 1; +} + +/* + * Inicializacao da biblioteca + */ + +LUACOM_API void luacom_open(lua_State *L) +{ + if(L == NULL) + return; + + LUASTACK_SET(L); + + // creates LuaCOM library table + luaCompat_openlib(L, LIBNAME, functions_tb); + + // prepares to store configuration table in + // library table + + lua_pushstring(L, CONFIGTABLE_NAME); + + // creates and registers configuration table + luaCompat_moduleCreate(L, MODULENAME); + + // adds a reference of the configuration table + // to the library one + lua_settable(L, -3); + lua_pop(L, 1); + + LuaBeans::createBeans(L, MODULENAME, LCOM_LUACOM_TYPENAME); + + { + LuaBeans::Events obj_events, pointer_events; + + obj_events.noindex = tagmeth_index; + obj_events.settable = tagmeth_settable; + obj_events.call = call_event; + pointer_events.gc = tagmeth_gc; + + LuaBeans::registerObjectEvents(L, obj_events); + LuaBeans::registerPointerEvents(L, pointer_events); + } + + // Creates a lua tag for IUnknown pointes + luaCompat_newLuaType(L, MODULENAME, LCOM_IUNKNOWN_TYPENAME); + + // Creates a lua tag for Connection Point tables + // and sets tag method + luaCompat_newLuaType(L, MODULENAME, LCOM_CONNPOINT_TYPENAME); + + luaCompat_pushTypeByName(L, MODULENAME, LCOM_CONNPOINT_TYPENAME); + lua_pushcfunction(L, tLuaCOMConnPoint::tagmeth_index); + + luaCompat_handleNoIndexEvent(L); + + lua_pop(L, 1); + + // Registers enumerator type + tLuaCOMEnumerator::registerLuaType(L, MODULENAME); + + // Registers type library types + tLuaTLB::Init(L); + + // Sets a tag method for garbage collection + luaCompat_pushTypeByName(L, MODULENAME, LCOM_IUNKNOWN_TYPENAME); + lua_pushcfunction(L, IUnknown_tag_gc); + luaCompat_handleGCEvent(L); + + lua_pushcfunction(L, IUnknown_eq); + luaCompat_handleEqEvent(L); + + lua_pop(L, 1); + + // sets default behaviour on errors + luaCompat_pushBool(L, 1); + luaCompat_moduleSet(L, MODULENAME, LUACOM_SHOULD_ABORT); + + luaCompat_pushBool(L, 0); + luaCompat_moduleSet(L, MODULENAME, LUACOM_SHOULD_ABORT_API); + + + idxDispatch = (void*)&luacom_runningInprocess; + + LUASTACK_CLEAN(L, 0); +} + +/* + * Fechamento da biblioteca + */ + +LUACOM_API void luacom_close(lua_State *L) +{ +} + + +/* + * Helper for implementing automation servers with LuaCOM + */ + +LUACOM_API int luacom_detectAutomation(lua_State *L, int argc, char *argv[]) +{ + int automation_result = LUACOM_NOAUTOMATION; + int lua_result = 0; + + int top = lua_gettop(L); + + // expects a table with the callback functions + + luaL_checktype (L, -1, LUA_TTABLE); + + // processes command line, looking for automation switches and + // calling the appropriate callback functions + + while(argc--) + { + if(!strcmp(argv[argc], "/Automation")) + { + lua_pushstring(L, "StartAutomation"); + lua_gettable(L, -2); + lua_result = luaCompat_call(L, 0, 0, NULL); + + if(!lua_result) + automation_result = LUACOM_AUTOMATION; + else + automation_result = LUACOM_AUTOMATION_ERROR; + + break; + } + else if(!strcmp(argv[argc], "/Register")) + { + lua_pushstring(L, "Register"); + lua_gettable(L, -2); + lua_result = luaCompat_call(L, 0, 0, NULL); + + if(!lua_result) + automation_result = LUACOM_REGISTER; + else + automation_result = LUACOM_AUTOMATION_ERROR; + + break; + } + } + + // cleans stack + lua_settop(L, top); + + return automation_result; +} diff --git a/luacom/luacom.h b/luacom/luacom.h new file mode 100644 index 00000000..d74ec53f --- /dev/null +++ b/luacom/luacom.h @@ -0,0 +1,37 @@ +#ifndef LUACOM_H +#define LUACOM_H + +#define LUACOM_VERSION "LuaCOM 1.3b 2005-01-06" +#define LUACOM_COPYRIGHT "Copyright (C) 1998-2005 Tecgraf, PUC-Rio" +#define LUACOM_AUTHORS "V. Almendra & R. Cerqueira & F. Mascarenhas" + +#ifndef LUACOM_API +#define LUACOM_API +#endif + +enum +{ + LUACOM_AUTOMATION, + LUACOM_NOAUTOMATION, + LUACOM_REGISTER, + LUACOM_UNREGISTER, + LUACOM_AUTOMATION_ERROR +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + +LUACOM_API void luacom_open(lua_State *L); +LUACOM_API void luacom_close(lua_State *L); + +LUACOM_API int luacom_IDispatch2LuaCOM(lua_State *L, void *pdisp_arg); + +LUACOM_API int luacom_detectAutomation(lua_State *L, int argc, char *argv[]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/luacom/luacom5.lua b/luacom/luacom5.lua new file mode 100644 index 00000000..0c662c85 --- /dev/null +++ b/luacom/luacom5.lua @@ -0,0 +1,1001 @@ +-- +-- Enhanced functionality for the LuaCOM library +-- + + +-- startup code: presumes LuaCOM has already been initialized +-- and lies in the luacom table + +assert(luacom) +luacomE = luacom + +-- tests for other dependencies +assert(table) +assert(string) +assert(io) + + +-- +-- ExportConstants +-- +-- Exports all the constants defined in the type library +-- to the global environment +-- + +function luacomE.ExportConstants(obj, const_table) + + if luacomE.GetType(obj) == "LuaCOM" then + obj = luacom.GetTypeInfo(obj) + end + + if luacomE.GetType(obj) == "ITypeInfo" then + obj = obj:GetTypeLib() + end + + assert(luacomE.GetType(obj) == "ITypeLib") + + if const_table == nil then + const_table = _G + end + + obj:ExportConstants(const_table) +end + + + +-- +-- Proxies for luacom.CreateObject +-- + +function luacomE.CreateLocalObject(ID) + return luacom.CreateObject(ID, "local_server") +end + +function luacomE.CreateInprocObject(ID) + return luacom.CreateObject(ID, "inproc_server") +end + +-- +-- luacomE.pairs +-- +-- Returns an iterator for a COM enumerator +-- + +function luacomE.pairs(luacom_obj) + + assert(luacom_obj) + + local enumerator = luacom.GetEnumerator(luacom_obj) + + if enumerator == nil then + error("Could not get an enumerator") + return + end + + local function iterator(state, index) + local value = state:Next() + + if value == nil then + return nil + else + return index+1, value + end + + end + + return iterator, enumerator, 0 +end + + +-- +-- GetType +-- +-- Returns the type of the object (if it is managed by LuaCOM) +-- + +function luacomE.GetType(obj) + local typetable = getmetatable(obj) + + if typetable ~= nil then + return typetable.type + else + return nil + end + +end + + +------------------------------- +-- Type library related code -- +------------------------------- + +-- Copies fields of a table to another + +function luacomE._copyFields(dest, src, fields) + local function copyField(i,field) + local src_field, dest_field + if type(field) == "table" then + src_field = field[2] + dest_field = field[1] + else + src_field = field + dest_field = field + end + + if src[src_field] ~= "" then + dest[dest_field] = src[src_field] + end + end + + table.foreach(fields, copyField) +end + +-- FillTypeInfo +-- +-- Creates a table filled with the +-- type information contained in a typeinfo + +function luacomE.FillTypeInfo(rawTypeInfo) + + if rawTypeInfo.FilledTypeInfo then + return rawTypeInfo.FilledTypeInfo + end + + local doc, attr + local typeinfo = {} + + rawTypeInfo.FilledTypeInfo = typeinfo + + -- Basic information + doc = rawTypeInfo:GetDocumentation() + typeinfo.name = doc.name + typeinfo.description = doc.helpstring + + -- Now the attributes + attr = rawTypeInfo:GetTypeAttr() + + typeinfo.type = attr.typekind + typeinfo.guid = attr.GUID + + -- copies flags + table.foreach(attr.flags, function(i,v) typeinfo[i] = v end) + + -- function to fill the different types of elements + local function fillMethods(methods, num_methods) + local i, index, method, rawmethod + + index = 1 + for i = 0, num_methods - 1 do + method = {} + rawmethod = rawTypeInfo:GetFuncDesc(i) + + if rawmethod ~= nil then + method.rawMethod = rawmethod + + fields = {"name", "description", + "helpfile", "helpcontext", + {"dispid", "memid"}, {"typeinv", "invkind"}, + {"num_params", "Params"}, "parameters", "type" + } + + luacomE._copyFields(method, rawmethod, fields) + + local prototype + if method.type then + prototype = method.type.." "..method.name + prototype = prototype.."(" + end + + -- builds prototype + if method.parameters then + -- builds parameter list + local first_param = true + + local function add_param(i, param) + + if first_param then + first_param = false + else + prototype = prototype..", " + first_param = false + end + + if param.type then + prototype = prototype..param.type.." " + end + + prototype = prototype..param.name + end + + table.foreachi(method.parameters, add_param) + + end + + if prototype then + prototype = prototype..")" + method.prototype = prototype + end + + methods[index] = method + index = index+1 + end + + end + end + + local function fillEnum(values, num_values) + local i, rawConstant + + local fields = {"name", "value"} + + for i = 0, num_values - 1 do + rawConstant = rawTypeInfo:GetVarDesc(i) + constant = {} + constant.rawConstant = rawConstant + luacomE._copyFields(constant, rawConstant, fields) + + values[i+1] = constant + end + end + + + local function fillCoClass(interfaces, num_interfaces) + local i, interface, rawinterface, typeflags + + for i = 0, num_interfaces - 1 do + rawinterface = rawTypeInfo:GetImplType(i) + interface = {} + interface.dispinterface = luacomE.FillTypeInfo(rawinterface) + + -- copies impltypeflags + typeflags = rawTypeInfo:GetImplTypeFlags(i) + table.foreach(typeflags, function(i,v) interface[i] = v end) + + interfaces[i+1] = interface + end + end + + + -- Creates tables to hold components of the typeinfo + + if attr.typekind == "dispinterface" then + typeinfo.methods = {} + fillMethods(typeinfo.methods, attr.Funcs) + elseif attr.typekind == "coclass" then + typeinfo.interfaces = {} + fillCoClass(typeinfo.interfaces, attr.ImplTypes) + elseif attr.typekind == "enumeration" then + typeinfo.values = {} + fillEnum(typeinfo.values, attr.Vars) + end + + return typeinfo + +end + +-- +-- FillTypeLib +-- +-- Loads a type library and +-- creates a table that rearranges +-- the information contained in the +-- table library to ease its navigation +-- + +function luacomE.FillTypeLib(rawtlb) + + if rawtlb._luacom_isfilled then + return rawtlb + end + + -- Stores type library information + local tlb = {} + tlb._luacom_isfilled = true + + tlb.rawtlb = rawtlb + + local doc = rawtlb:GetDocumentation() + + tlb.name = doc.name + tlb.description = doc.helpstring + + -- stores typeinfos + + local typeinfo, rawtypeinfo, attr + + for i = 0, rawtlb:GetTypeInfoCount() - 1 do + + rawTypeInfo = rawtlb:GetTypeInfo(i) + typeinfo = luacomE.FillTypeInfo(rawTypeInfo) + tlb[i+1] = typeinfo + + end + + return tlb +end + + +-- +-- DumpTypeLib +-- Creates a html page describing a type library, +-- + +function luacomE.DumpTypeLib(obj, htmlfile) + + local tlb, rawtlb + + if type(obj) == "string" then + rawtlb = luacom.LoadTypeLibrary(obj) + elseif luacomE.GetType(obj) == "ITypeLib" then + rawtlb = obj + elseif luacomE.GetType(obj) == "LuaCOM" then + obj = luacom.GetTypeInfo(obj) + rawtlb = obj:GetTypeLib() + elseif luacomE.GetType(obj) == "ITypeInfo" then + rawtlb = obj:GetTypeLib() + end + + if rawtlb == nil then + error("Type library not found.") + end + + tlb = luacomE.FillTypeLib(rawtlb) + rawtlb = nil + + + if htmlfile == nil then + htmlfile = tlb.name..".html" + elseif string.sub(htmlfile, -1) == "\\" then + htmlfile = htmlfile..tlb.name..".html" + end + + local filehandle = io.open(htmlfile, "w") + + if filehandle == nil then + error("Could not create "..htmlfile..": file exists") + end + + io.output(filehandle) + + -- writes html header + io.write("\n") + io.write("") + + -- writes title + io.write("") + + if tlb.description then + io.write(tlb.description) + else + io.write(tlb.name) + end + + io.write("\n") + + io.write("

") + + if tlb.description then + io.write(tlb.description) + else + io.write(tlb.name) + end + + io.write(" Type Library") + + io.write("

\n") + io.write("
\n") + + -- + -- First, makes an index for the entire type library + -- + + io.write("

Summary

\n") + + -- Output function + local function write_typeinfo(i, typeinfo) + io.write("
  • ") + io.write("") + + if typeinfo.type ~= "dispinterface" or typeinfo.dispatchable then + io.write(""..typeinfo.name.."") + else + io.write(typeinfo.name) + end + + io.write("") + io.write("
  • ") + + if typeinfo.description and typeinfo.description ~= "" then + io.write(" - "..typeinfo.description) + end + + io.write("\n") + end + + -- filter function + local function filter_typeinfo(type) + local function filter(i,typeinfo) + + if typeinfo.type == type then + map_function(i, typeinfo) + end + end + + table.foreachi(tlb, filter) + end + + map_function = write_typeinfo + + io.write("

    Components

    \n") + filter_typeinfo("coclass") + + io.write("

    Enumerations

    \n") + filter_typeinfo("enumeration") + + io.write("

    Interfaces

    \n") + filter_typeinfo("dispinterface") + + -- + -- Now, describe each element + -- + + io.write("
    \n") + io.write("

    Detailed description

    \n") + + -- describes coclasses + + io.write("

    Components Classes

    \n") + + local function describe_coclass(i, typeinfo) + assert(typeinfo.type == "coclass") + + if typeinfo.restricted or typeinfo.hidden then + return + end + + io.write("

    ") + io.write("") + io.write(typeinfo.name) + + io.write("

    \n") + + if typeinfo.description then + io.write(typeinfo.description.."

    ") + end + + io.write("

    "..typeinfo.guid.."

    ") + + local i, default, source + + -- locates the default interface and the source interface + for i=1, table.getn(typeinfo.interfaces) do + + if typeinfo.interfaces[i].source and source == nil then + source = typeinfo.interfaces[i].dispinterface + elseif typeinfo.interfaces[i].source + and typeinfo.interfaces[i].default then + source = typeinfo.interfaces[i].dispinterface + end + + if not typeinfo.interfaces[i].source and default == nil then + default = typeinfo.interfaces[i].dispinterface + elseif typeinfo.interfaces[i].default + and not typeinfo.interfaces[i].source then + default = typeinfo.interfaces[i].dispinterface + end + + end + + if default then + if default.dispatchable then + io.write(""..default.name.."") + else + io.write(default.name) + end + + io.write(" is the default interface for this component.
    ") + end + + if source then + if source.dispatchable then + io.write(""..source.name.."") + else + io.write(source.name) + end + + io.write(" is the default set of events for this component.
    ") + end + + if typeinfo.appobject then + io.write("This is the Application object.
    ") + end + + if typeinfo.control then + io.write("This component is an OLE control.
    ") + end + + if typeinfo.cancreate then + io.write("Instances of this component can be created.
    ") + end + + end + + map_function = describe_coclass + + filter_typeinfo("coclass") + + + + -- describes enumerations + + io.write("


    Enumerations

    \n") + + local function describe_enum(i, typeinfo) + assert(typeinfo.type == "enumeration") + + io.write("

    ") + io.write("") + io.write(typeinfo.name) + + io.write("

    \n") + + if typeinfo.description and typeinfo.description ~= nil then + io.write(typeinfo.description.."

    ") + end + + local function describe_constant(i, constant) + io.write("

  • ") + io.write(constant.name.." = "..tostring(constant.value)) + io.write("
  • \n") + end + + io.write("
      \n") + table.foreachi(typeinfo.values, describe_constant) + io.write("
    \n") + end + + map_function = describe_enum + + filter_typeinfo("enumeration") + + + -- describes interfaces + + io.write("

    Interfaces

    \n") + + local function describe_interface(i, typeinfo) + assert(typeinfo.type == "dispinterface") + + io.write("

    ") + io.write("") + io.write(typeinfo.name) + io.write("

    \n") + io.write("
    "..typeinfo.guid.."

    ") + + local function describe_method_use(method) + io.write("LuaCOM examples:

    ") + + local function param_lister() + local first_param = true + local function add_param(i, param) + if param["in"] or (not param.out) then + local name + if param.default then + local default = tostring(param.default) + if default == "" then default = "?" end + name = param.name .. "=" .. default + else + name = param.name + end + if param.opt then name = "[" .. name .. "]" end + if first_param then + io.write(name) + first_param = false + else + io.write(", " .. name) + end + end + end + return add_param + end + + local function retval_lister(first_retval) + local has_retval = false + return function(i, param) + if param.out then + if first_retval then + io.write(param.name) + first_retval = false + else + io.write(", " .. param.name) + end + has_retval = true + end + end, function() return has_retval end + end + + if method.typeinv == "propget" then + if method.num_params == 0 then + io.write("com_obj." .. method.name .. "
    ") + io.write("com_obj:get" .. method.name .. "()") + else + io.write("com_obj:get" .. method.name .. "(") + table.foreachi(method.parameters, param_lister()) + io.write(")") + end + elseif method.typeinv == "propput" then + if method.num_params == 1 then + io.write("com_obj." .. method.name .. " = " .. method.parameters[1].name .. "
    ") + io.write("com_obj:set" .. method.name .. "(" .. method.parameters[1].name .. ")
    ") + else + io.write("com_obj:set" .. method.name .. "(") + table.foreachi(method.parameters, param_lister()) + io.write(")") + end + else + if method.type ~= "void" then + io.write("retval") + table.foreachi(method.parameters, retval_lister(false)) + io.write(" = ") + else + local lister, checker = retval_lister(true) + table.foreachi(method.parameters, lister) + if checker() then io.write(" = ") end + end + io.write("com_obj:" .. method.name .. "(") + table.foreachi(method.parameters, param_lister()) + io.write(")
    ") + end + end + + local function describe_method(i, method) + if method.rawMethod == nil then + return + end + + io.write("

  • ") + io.write(method.name) + + if method.prototype then + io.write("
    "..method.prototype.."
    \n") + else + io.write("
    ") + end + + if method.description then + io.write(method.description.."
    \n") + end + + describe_method_use(method) + + io.write("

    ") + + io.write("

  • \n") + end + + io.write("
      \n") + table.foreachi(typeinfo.methods, describe_method) + io.write("
    \n") + end + + map_function = describe_interface + + filter_typeinfo("dispinterface") + + io.write("") + + io.output():close() + + return htmlfile + +end + + + +-- +-- shows TypeLib dump to the user +-- + +function luacomE.ViewTypeLib(obj) + + local filename = os.getenv("TEMP") + + if filename == nil then + filename = os.getenv("TMP") + end + + if filename == nil then + filename = luacom.GetCurrentDirectory() + end + + if string.sub(filename, -1) ~= "\\" then + filename = filename.."\\" + end + + filename = luacomE.DumpTypeLib(obj, filename) + + local browser = luacom.CreateObject("InternetExplorer.Application") + + browser.Visible = true + browser:Navigate2(filename) + + return filename +end + +local interface_proto = { + constants = {}, + typedefs = {}, + properties = {}, + methods = {} +} + +--[[function interface_proto:AddConstant(type, name, value) + table.insert(self.constants, { type = type, name = name, value = value }) +end]]-- + +--[[function interface_proto:AddTypedef(type, typedef) + table.insert(self.typedefs, { type = type, typedef = typedef }) +end]]-- + +function interface_proto:AddMethod(methodinfo) + table.insert(self.methods, methodinfo) +end + +function interface_proto:AddProperty(propertyinfo) + table.insert(self.properties, propertyinfo) +end + +function interface_proto:Write(file) + local start_id = 0 + + local function attribute_writer(line_break) + local first_attribute = true + return function(name, value) + if not first_attribute then + if line_break then + file:write(",\n ") + else + file:write(", ") + end + else + if line_break then file:write(" ") end + end + first_attribute = false + if(type(name) == "number") then + file:write(value) + else + file:write(name .. "(" .. value .. ")") + end + end + end + + local function constant_writer(i, constant) + file:write("\n" .. " const " .. constant.type .. " " .. constant.name .. " = " .. + constant.value .. ";\n") + end + + local function typedef_writer(i, typedef) + file:write("\n" .. " typedef " .. typedef.type .. " " .. typedef.typedef .. ";\n") + end + + local function param_writer() + local first_param = true + return function(i, param) + if not first_param then file:write(",\n ") end + first_param = false + if param.attributes then + file:write("[") + table.foreach(param.attributes, attribute_writer(false)) + file:write("] ") + end + file:write(param.type .. " " .. param.name) + end + end + + local function property_writer(i, property) + if not property.attributes then + property.attributes = { id = tostring(start_id + i) } + end + file:write("\n [\n") + if property.attributes.id == nil then + property.attributes.id = tostring(start_id + i) + end + table.foreach(property.attributes, attribute_writer(true)) + file:write("\n ]\n ") + file:write(property.type .. " " .. property.name .. ";\n") + end + + local function method_writer(i, method) + if not method.attributes then + method.attributes = { id = tostring(start_id + i) } + end + file:write("\n [\n") + if method.attributes.id == nil then + method.attributes.id = tostring(start_id + i) + end + table.foreach(method.attributes, attribute_writer(true)) + file:write("\n ]\n ") + if method.type then + file:write(method.type) + else + file:write("void") + end + file:write(" " .. method.name .. "(") + if method.parameters then + file:write("\n ") + table.foreachi(method.parameters, param_writer()) + file:write("\n );\n") + else + file:write("void" .. ");\n") + end + end + + if self.attributes then + file:write("[\n ") + table.foreach(self.attributes, attribute_writer(true)) + file:write("\n]\n") + end + file:write("dispinterface " .. self.name .. "\n{") + if self.interface ~= nil then + file:write(" interface " .. self.interface) + else +-- table.foreachi(self.constants, constant_writer) +-- file:write("\n") +-- table.foreachi(self.typedefs, typedef_writer) + file:write("\n properties:\n") + table.foreachi(self.properties, property_writer) + start_id = table.getn(self.properties) + file:write("\n methods:\n") + table.foreachi(self.methods, method_writer) + end + file:write("\n};\n\n") +end + +local coclass_proto = { + interfaces = {} +} + +function coclass_proto:AddInterface(attributes) + table.insert(self.interfaces, attributes) +end + +function coclass_proto:Write(file) + local function attribute_writer(line_break) + local first_attribute = true + return function(name, value) + if not first_attribute then + if line_break then + file:write(",\n ") + else + file:write(", ") + end + end + first_attribute = false + if(type(name) == "number") then + file:write(value) + else + file:write(name .. "(" .. value .. ")") + end + end + end + + local function interface_writer(i, interface) + local name = interface.name + interface.name = nil + file:write("[") + table.foreach(interface, attribute_writer(false)) + file:write("] ") + file:write("dispinterface " .. name .. ";\n") + interface.name = name + end + + if self.attributes then + file:write("[\n ") + table.foreach(self.attributes, attribute_writer(true)) + file:write("\n]\n") + end + file:write("coclass " .. self.name .. "\n{\n") + table.foreachi(self.interfaces, interface_writer) + file:write("};\n\n") +end + +local library_proto = { + interfaces = {}, + coclasses = {}, + imports = {}, + typedefs = {}, + AddTypedef = interface_proto.AddTypedef +} + +function library_proto:AddInterface(attributes) + local name = attributes.name + attributes.name = nil + local interface = attributes.interface + attributes.interface = nil + local newinterface = { name = name, attributes = attributes, interface = interface, __index = interface_proto } + setmetatable(newinterface, newinterface) + table.insert(self.interfaces, newinterface) + if interface ~= nil then + return nil + else + return newinterface + end +end + +function library_proto:AddCoclass(attributes) + local name = attributes.name + attributes.name = nil + local newcoclass = { name = name, attributes = attributes, __index = coclass_proto } + setmetatable(newcoclass, newcoclass) + table.insert(self.coclasses, newcoclass) + return newcoclass +end + +function library_proto:AddImport(library) + table.insert(self.imports, library) +end + +function library_proto:WriteODL(filename) + local file = io.open(filename .. ".odl","w+") + + local function attribute_writer(line_break) + local first_attribute = true + return function(name, value) + if not first_attribute then + if line_break then + file:write(",\n ") + else + file:write(", ") + end + end + first_attribute = false + if(type(name) == "number") then + file:write(value) + else + file:write(name .. "(" .. value .. ")") + end + end + end + + local function import_writer(i, import) + file:write(" " .. "importlib(\"" .. import .. "\");\n") + end + + local function typedef_writer(i, typedef) + file:write("\n" .. " typedef " .. typedef.type .. " " .. typedef.typedef .. ";\n") + end + + local function interface_writer(i, interface) + interface:Write(file) + end + + local function coclass_writer(i, coclass) + coclass:Write(file) + end + + if self.attributes then + file:write("[\n ") + table.foreach(self.attributes, attribute_writer(true)) + file:write("\n]\n") + end + file:write("library " .. self.name .. "\n{\n") + table.foreachi(self.imports, import_writer) + table.foreachi(self.typedefs, typedef_writer) + table.foreachi(self.interfaces, interface_writer) + table.foreachi(self.coclasses, coclass_writer) + file:write("};\n\n") + file:close() +end + +function library_proto:WriteTLB(filename) + self:WriteODL(filename) + os.execute("midl " .. filename .. ".odl") +end + +function luacomE.NewLibrary(attributes) + local name = attributes.name + attributes.name = nil + local newlibrary = { name = name, attributes = attributes, __index = library_proto } + setmetatable(newlibrary, newlibrary) + return newlibrary +end diff --git a/luacom/luacom_internal.h b/luacom/luacom_internal.h new file mode 100644 index 00000000..069983a6 --- /dev/null +++ b/luacom/luacom_internal.h @@ -0,0 +1,55 @@ +/* + * luacom_internal.h + * + * Global definitions for the LuaCOM library + */ + +// Here we define the module name we'll use in Lua +// to be used in the registry + +#ifndef __LUACOM_INTERNAL_H +#define __LUACOM_INTERNAL_H + +#include "luabeans.h" + +#define MODULENAME "__LuaCOM__" + + +// This is the name of the configuration table inside +// the library table + +#define CONFIGTABLE_NAME "config" + + +// Here is the libname, that is, the name used to access +// luacom methods + +#define LIBNAME "luacom" + + +// keys in the configuration table used by luacom +// internally + +#define LCOM_LUACOM_TYPENAME "LuaCOM" +#define LCOM_IUNKNOWN_TYPENAME "IUnknown" +#define LCOM_CONNPOINT_TYPENAME "IConnectionPoint" + + +// names of the configuration keys + +#define LUACOM_SHOULD_ABORT "abort_on_error" +#define LUACOM_SHOULD_ABORT_API "abort_on_API_error" +#define LUACOM_LAST_ERROR "last_error" + + +#define LCOM_IUNKNOWN_ATTRIBUTE "IUnknown" + + +void luacom_error(lua_State* L, const char* message); + +LuaBeans *getLuaBeans(lua_State *L); + +extern HINSTANCE g_hInstance; +extern HWND g_hwndParking; + +#endif // __LUACOM_INTERNAL_H \ No newline at end of file diff --git a/luacom/tCOMUtil.cpp b/luacom/tCOMUtil.cpp new file mode 100644 index 00000000..e94fea76 --- /dev/null +++ b/luacom/tCOMUtil.cpp @@ -0,0 +1,1004 @@ +// tCOMUtil.cpp: implementation of the tCOMUtil class. +// +////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include "tCOMUtil.h" +#include "tLuaCOMException.h" +#include "tUtil.h" + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +tCOMUtil::tCOMUtil() +{ + +} + +tCOMUtil::~tCOMUtil() +{ + +} + +ITypeInfo *tCOMUtil::GetCoClassTypeInfo(CLSID clsid) +{ + ITypeLib* typelib = tCOMUtil::LoadTypeLibFromCLSID(clsid); + + if(typelib == NULL) + return NULL; + + return tCOMUtil::GetCoClassTypeInfo(typelib, clsid); +} + +ITypeInfo *tCOMUtil::GetCoClassTypeInfo(IUnknown* punk) +{ + HRESULT hr = S_OK; + IProvideClassInfo *pIProvideClassInfo = NULL; + ITypeInfo* coclassinfo = NULL; + + hr = punk->QueryInterface(IID_IProvideClassInfo, + (void **) &pIProvideClassInfo); + + if (FAILED(hr)) + return NULL; + + hr = pIProvideClassInfo->GetClassInfo(&coclassinfo); + pIProvideClassInfo->Release(); + + if(SUCCEEDED(hr)) + return coclassinfo; + else + return NULL; +} + +ITypeInfo *tCOMUtil::GetCoClassTypeInfo(IDispatch* pdisp, CLSID clsid) +{ + CHECKPARAM(pdisp); + + ITypeInfo* typeinfo = NULL; + ITypeLib* typelib = NULL; + HRESULT hr = S_OK; + + { + unsigned int typeinfocount = 0; + + hr = pdisp->GetTypeInfoCount(&typeinfocount); + + if(FAILED(hr) || typeinfocount == 0) + return NULL; + } + + hr = pdisp->GetTypeInfo(0, 0, &typeinfo); + + if(FAILED(hr)) + return NULL; + + { + unsigned int dumb_index = -1; + hr = typeinfo->GetContainingTypeLib(&typelib, &dumb_index); + COM_RELEASE(typeinfo); + } + + if(FAILED(hr)) + return NULL; + + ITypeInfo* coclasstypeinfo = tCOMUtil::GetCoClassTypeInfo(typelib, clsid); + typelib->Release(); + + return coclasstypeinfo; +} + +ITypeInfo *tCOMUtil::GetCoClassTypeInfo(ITypeLib *typelib, + const char *coclassname) +{ + wchar_t* wcCoClass = (wchar_t*) + malloc( (strlen(coclassname) + 1) * sizeof(wchar_t)); + + mbstowcs(wcCoClass, coclassname, strlen(coclassname)+1); + + const short max_typeinfos = 1000; + + MEMBERID dumb[max_typeinfos]; + ITypeInfo *typeinfos[max_typeinfos]; + unsigned short number = max_typeinfos; + + HRESULT hr = typelib->FindName(wcCoClass, 0, + typeinfos, dumb, &number); + + free(wcCoClass); + wcCoClass = NULL; + + // a interface especificada nao existe nesta TypeLib + if(FAILED(hr) || number == 0) + return NULL; + + // tries to find the coclass + + unsigned int i = 0; + TYPEATTR *typeattr = NULL; + ITypeInfo *found = NULL; + + for(i = 0; i < number; i++) + { + hr = typeinfos[i]->GetTypeAttr(&typeattr); + + TYPEKIND typekind = typeattr->typekind; + typeinfos[i]->ReleaseTypeAttr(typeattr); + + if(!found && typekind == TKIND_COCLASS) + found = typeinfos[i]; + else + typeinfos[i]->Release(); + } + + return found; +} + + + +ITypeInfo *tCOMUtil::GetDefaultInterfaceTypeInfo(ITypeInfo* pCoClassinfo, + bool source) + +{ + ITypeInfo* typeinfo = NULL; + + // if the component does not have a dispinterface typeinfo + // for events, we stay with an interface typeinfo + ITypeInfo* interface_typeinfo = NULL; + + TYPEATTR* pTA = NULL; + HRESULT hr = S_OK; + + if (SUCCEEDED(pCoClassinfo->GetTypeAttr(&pTA))) + { + UINT i = 0; + int iFlags = 0; + + for (i=0; i < pTA->cImplTypes; i++) + { + //Get the implementation type for this interface + hr = pCoClassinfo->GetImplTypeFlags(i, &iFlags); + + if (FAILED(hr)) + continue; + + if (iFlags & IMPLTYPEFLAG_FDEFAULT || pTA->cImplTypes == 1) + { + if(source == false && !(iFlags & IMPLTYPEFLAG_FSOURCE) + || source == true && (iFlags & IMPLTYPEFLAG_FSOURCE)) + { + HREFTYPE hRefType=NULL; + + /* + * This is the interface we want. Get a handle to + * the type description from which we can then get + * the ITypeInfo. + */ + pCoClassinfo->GetRefTypeOfImplType(i, &hRefType); + hr = pCoClassinfo->GetRefTypeInfo(hRefType, &typeinfo); + + // gets typeattr info + TYPEATTR *ptypeattr = NULL; + GUID guid; + TYPEKIND typekind; + + hr = typeinfo->GetTypeAttr(&ptypeattr); + + if(FAILED(hr)) + { + COM_RELEASE(typeinfo); + break; + } + + guid = ptypeattr->guid; + typekind = ptypeattr->typekind; + + typeinfo->ReleaseTypeAttr(ptypeattr); + + if(typekind == TKIND_DISPATCH) + { + // found! + COM_RELEASE(interface_typeinfo); + break; + } + else // hold this pointer. If we do not find + // anything better, we stay with this typeinfo + { + COM_RELEASE(interface_typeinfo); + interface_typeinfo = typeinfo; + typeinfo = NULL; + } + } + } + } + + pCoClassinfo->ReleaseTypeAttr(pTA); + } + + if(!typeinfo) + return interface_typeinfo; + else + return typeinfo; +} + + + +ITypeInfo *tCOMUtil::GetDispatchTypeInfo(IDispatch* pdisp) +{ + ITypeInfo* typeinfo = NULL; + + HRESULT hr = pdisp->GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, &typeinfo); + + if(FAILED(hr)) + return NULL; + + TYPEATTR *ptypeattr = NULL; + + typeinfo->GetTypeAttr(&ptypeattr); + + TYPEKIND typekind = ptypeattr->typekind; + + if(typekind == TKIND_DISPATCH) + { + typeinfo->ReleaseTypeAttr(ptypeattr); + return typeinfo; + } + + // tries to find another description of the same + // interface in the typelib with TKIND_DISPATCH + + ITypeLib *ptypelib = NULL; + unsigned int dumb = 0; + IID iid = ptypeattr->guid; + + hr = typeinfo->GetContainingTypeLib(&ptypelib, &dumb); + + typeinfo->ReleaseTypeAttr(ptypeattr); + + // if there's no containing type lib, we have to + // trust this one is the right type info + if(FAILED(hr)) + return typeinfo; + + // obtem a typeinfo do iid fornecido + // caso haja uma implementacao dispinterface, + // esta' e' que sera' retornada (segundo + // documentacao do ActiveX + + ITypeInfo* typeinfo_guid = NULL; + + hr = ptypelib->GetTypeInfoOfGuid(iid, &typeinfo_guid); + + COM_RELEASE(ptypelib); + + if(FAILED(hr)) + return typeinfo; + + // verifica se e' dispinterface + TYPEATTR *ptypeattr_iface = NULL; + + hr = typeinfo_guid->GetTypeAttr(&ptypeattr_iface); + TYPEKIND typekind_iface = ptypeattr_iface->typekind; + typeinfo_guid->ReleaseTypeAttr(ptypeattr_iface); + + if(typekind_iface == TKIND_DISPATCH) + { + // releases original type information + COM_RELEASE(typeinfo); + + return typeinfo_guid; + } + else + { + COM_RELEASE(typeinfo_guid); + + // returns original type info + return typeinfo; + } +} + + +ITypeInfo *tCOMUtil::GetInterfaceTypeInfo(ITypeLib* typelib, + const char *interface_name) +{ + wchar_t* wcInterface = (wchar_t*) + malloc( (strlen(interface_name) + 1) * sizeof(wchar_t)); + mbstowcs(wcInterface, interface_name, strlen(interface_name)+1); + + const int max_typeinfos = 30; + + MEMBERID dumb[max_typeinfos]; + ITypeInfo *typeinfos[max_typeinfos]; + unsigned int number = 30; + + HRESULT hr = typelib->FindName(wcInterface, 0, + typeinfos, dumb, (unsigned short *) &number); + + free(wcInterface); + wcInterface = NULL; + + // a interface especificada nao existe nesta TypeLib + if(FAILED(hr) || number == 0) + return NULL; + + // Procura por uma implementacao IDispatch + + unsigned int i = 0; + TYPEATTR *typeattr = NULL; + ITypeInfo *found = NULL; + + for(i = 0; i < number; i++) + { + hr = typeinfos[i]->GetTypeAttr(&typeattr); + + TYPEKIND typekind = typeattr->typekind; + typeinfos[i]->ReleaseTypeAttr(typeattr); + + if(!found && typekind == TKIND_DISPATCH) + found = typeinfos[i]; + else + typeinfos[i]->Release(); + } + + return found; +} + + +/* + * Carrega uma Typelib associada a um ProgID + */ + +ITypeLib* tCOMUtil::LoadTypeLibFromProgID(const char* ProgID, + unsigned short major_version) +{ + CLSID clsid = IID_NULL; + HRESULT hr = tCOMUtil::ProgID2CLSID(&clsid, ProgID); + + if(FAILED(hr)) + return NULL; + + bool version_found = false; + int version = -1; + + if(major_version <= 0) + { + if(sscanf(ProgID, "%*s.%*s.%d", &major_version) == 1) + version_found = true; + } + + // tries to get some version information to help finding + // the right type library + if(version_found) + return tCOMUtil::LoadTypeLibFromCLSID(clsid, major_version); + else + return tCOMUtil::LoadTypeLibFromCLSID(clsid); + +} + +/* + * LoadTypeLibByName + * Carrega uma typelib a partir de um arquivo TLB + */ + +ITypeLib *tCOMUtil::LoadTypeLibByName(const char *pcFilename) +{ + HRESULT hr; + ITypeLib *ptlib = NULL; + wchar_t *wcFilename = new wchar_t[strlen(pcFilename)+1]; + + mbstowcs(wcFilename, pcFilename, strlen(pcFilename)+1); + + hr = LoadTypeLibEx(wcFilename, REGKIND_NONE, &ptlib); + + delete[] wcFilename; + wcFilename = NULL; + + if(FAILED(hr)) + return NULL; + + return ptlib; +} + + + +ITypeLib* tCOMUtil::LoadTypeLibFromCLSID(CLSID clsid, + unsigned short major_version) +{ + wchar_t* wcClsid = NULL; + + HRESULT hr = StringFromCLSID(clsid, &wcClsid); + + if (FAILED(hr)) + return NULL; + + /* converte CLSID para string normal */ + char* pcClsid = (char*) malloc( (wcslen(wcClsid) + 1) * sizeof(char)); + wcstombs(pcClsid, wcClsid,wcslen(wcClsid)+1); + + CoTaskMemFree(wcClsid); + + DWORD size = 38*3; /*{F37C8063-4AD5-101B-B826-00DD01103DE1}*/ + BYTE *bLibID = (BYTE *) malloc(size); + BYTE bVersion[100]; // This must hold something like "5.2" + HKEY iid_key, obj_key, typelib_key, version_key; + + /* extrai do registry type library (GUID e versao) */ + LONG res = 0; + bool version_info_found = true; + + try + { + res = RegOpenKeyEx(HKEY_CLASSES_ROOT,"CLSID", 0, KEY_READ, &iid_key); + WINCHECK(res == ERROR_SUCCESS); + + res = RegOpenKeyEx(iid_key, pcClsid, 0, KEY_READ, &obj_key); + RegCloseKey(iid_key); + free(pcClsid); + pcClsid = NULL; + + WINCHECK(res == ERROR_SUCCESS); + + res = RegOpenKeyEx(obj_key, "TypeLib",0, KEY_READ, &typelib_key); + if(res != ERROR_SUCCESS) + { + RegCloseKey(obj_key); + LUACOM_EXCEPTION(WINDOWS_ERROR); + } + + res = RegOpenKeyEx(obj_key, "version",0, KEY_READ, &version_key); + RegCloseKey(obj_key); + if(res != ERROR_SUCCESS) + version_info_found = false; + + RegQueryValueEx(typelib_key, NULL, NULL, NULL, bLibID, &size); + RegCloseKey(typelib_key); + + RegQueryValueEx(version_key, NULL, NULL, NULL, bVersion, &size); + RegCloseKey(version_key); + } + catch(class tLuaCOMException& e) + { + UNUSED(e); + + if(pcClsid) + free(pcClsid); + + return NULL; + } + + // converts libID to multibyte string + wchar_t* wcTypelib= (wchar_t*) + malloc( (strlen((char *) bLibID) + 1) * sizeof(wchar_t)); + mbstowcs(wcTypelib, (char *) bLibID, strlen((char *) bLibID)+1); + + // extracts version information + + int version_major = 0, version_minor = 0; + + int found = 0; + + if(version_info_found) + { + found = sscanf( + (const char *) bVersion, + "%d.%d", + &version_major, &version_minor); + } + + if(major_version > 0 && + ( + (!version_info_found) || + (version_info_found && found == 0) + ) + ) + { + version_major = major_version; + version_minor = 0; + } + else if(!version_info_found) + { + // tries to load the first type library found in + // the registry + bool result = tCOMUtil::GetDefaultTypeLibVersion( + (const char*) bLibID, + &version_major, + &version_minor); + + if(!result) + return NULL; + } + + free(bLibID); + + GUID libid = IID_NULL; + CLSIDFromString(wcTypelib, &libid); + free(wcTypelib); + + ITypeLib* typelib = NULL; + + hr = LoadRegTypeLib(libid, version_major, version_minor, 0, &typelib); + + if(FAILED(hr)) + return NULL; + + return typelib; +} + +ITypeInfo* tCOMUtil::GetCoClassTypeInfo(ITypeLib *typelib, CLSID clsid) +{ + ITypeInfo* coclassinfo = NULL; + + HRESULT hr = typelib->GetTypeInfoOfGuid(clsid, &coclassinfo); + + if(FAILED(hr)) + return NULL; + + return coclassinfo; +} + +HRESULT tCOMUtil::ProgID2CLSID(CLSID *pClsid, const char *ProgID) +{ + CHECKPARAM(pClsid); + + // tests whether we already have a CLSID + + wchar_t* wcProgId = NULL; + HRESULT hr = S_OK; + + if(ProgID[0] == '{') + { + wcProgId = (wchar_t*) malloc( (strlen(ProgID) + 1) * sizeof(wchar_t)); + mbstowcs(wcProgId, ProgID, strlen(ProgID)+1); + + hr = CLSIDFromString(wcProgId, pClsid); + + free(wcProgId); + wcProgId = NULL; + + return hr; + } + + /* converte ProgID para OLESTR */ + wcProgId = (wchar_t*) malloc( (strlen(ProgID) + 1) * sizeof(wchar_t)); + mbstowcs(wcProgId, ProgID, strlen(ProgID)+1); + + hr = CLSIDFromProgID(wcProgId, pClsid); + + free(wcProgId); + wcProgId = NULL; + + return hr; +} + +CLSID tCOMUtil::GetCLSID(ITypeInfo *coclassinfo) +{ + TYPEATTR* ptypeattr = NULL; + + HRESULT hr = coclassinfo->GetTypeAttr(&ptypeattr); + + if(FAILED(hr)) + return IID_NULL; + + CLSID clsid = ptypeattr->guid; + + coclassinfo->ReleaseTypeAttr(ptypeattr); + + return clsid; +} + +bool tCOMUtil::GetDefaultTypeLibVersion(const char* libid, + int *version_major, + int *version_minor) +{ + LONG res = 0; + HKEY typelib_key, this_typelib_key; + + res = RegOpenKeyEx(HKEY_CLASSES_ROOT,"TypeLib", 0, KEY_READ, &typelib_key); + RegCloseKey(HKEY_CLASSES_ROOT); + + if(res != ERROR_SUCCESS) + return false; + + res = RegOpenKeyEx(typelib_key, libid, 0, KEY_READ, &this_typelib_key); + RegCloseKey(typelib_key); + + if(res != ERROR_SUCCESS) + return false; + + const int bufsize = 1000; + char version_info[bufsize]; + DWORD size = bufsize; + + res = RegEnumKeyEx(this_typelib_key, 0, version_info, &size, + NULL, NULL, NULL, NULL); + RegCloseKey(this_typelib_key); + + if(res != ERROR_SUCCESS) + return false; + + sscanf(version_info, "%d.%d", version_major, version_minor); + + return true; +} + +bool tCOMUtil::GetRegKeyValue(const char* key, char** pValue) { + LONG ec = 0; + long cbValue; + + ec = RegQueryValue(HKEY_CLASSES_ROOT,key,NULL,&cbValue); + + if(ERROR_SUCCESS == ec) { + *pValue = new char[cbValue+1]; + ec = RegQueryValue(HKEY_CLASSES_ROOT,key,*pValue,&cbValue); + if(ERROR_SUCCESS == ec) + return true; + } + + return false; +} + +bool tCOMUtil::SetRegKeyValue(const char *key, + const char *subkey, + const char *value) +{ + + bool ok = false; + LONG ec = 0; + HKEY hKey; + + const int bufsize = 10000; + char Key[bufsize]; + + strncpy(Key, key, bufsize - 1); + + if (NULL != subkey) + { + strcat(Key, "\\"); + strcat(Key, subkey); + } + + ec = RegCreateKeyEx( + HKEY_CLASSES_ROOT, + Key, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, + NULL, + &hKey, + NULL); + + if (ERROR_SUCCESS == ec) + { + if (NULL != value) + { + ec = RegSetValueEx( + hKey, + NULL, + 0, + REG_SZ, + (BYTE *)value, + strlen(value)+1); + } + if (ERROR_SUCCESS == ec) + ok = TRUE; + + RegCloseKey(hKey); + } + + return ok; +} + +bool tCOMUtil::DelRegKey(const char *key, + const char *subkey) +{ + + bool ok = false; + LONG ec = 0; + + const int bufsize = 10000; + char Key[bufsize]; + + strncpy(Key, key, bufsize - 1); + + if (NULL != subkey) + { + strcat(Key, "\\"); + strcat(Key, subkey); + } + + ec = SHDeleteKey(HKEY_CLASSES_ROOT, Key); + + if (ERROR_SUCCESS == ec) + { + return true; + } + + return false; +} + +void tCOMUtil::DumpTypeInfo(ITypeInfo *typeinfo) +{ + HRESULT hr = S_OK; + TYPEATTR* pta = NULL; + + CHECKPARAM(typeinfo); + + hr = typeinfo->GetTypeAttr(&pta); + CHK_COM_CODE(hr); + + // prints IID + LPOLESTR lpsz = NULL; + + hr = StringFromIID(pta->guid, &lpsz); + + if(FAILED(hr)) + { + hr = StringFromCLSID(pta->guid, &lpsz); + } + + if(SUCCEEDED(hr)) + { + wprintf(L"\nInterface: %s\n\n", lpsz); + + CoTaskMemFree(lpsz); + } + + int i = 0; + FUNCDESC *pfd = NULL; + + for(i = 0; i < pta->cFuncs; i++) + { + typeinfo->GetFuncDesc(i, &pfd); + + BSTR names[1]; + unsigned int dumb; + + typeinfo->GetNames(pfd->memid, names, 1, &dumb); + + printf("%.3d: %-30s\tid=0x%p\t%d param(s)\n", i, + tUtil::bstr2string(names[0]), pfd->memid, pfd->cParams); + + typeinfo->ReleaseFuncDesc(pfd); + SysFreeString(names[0]); + } + + typeinfo->ReleaseTypeAttr(pta); +} + + +const char* tCOMUtil::getPrintableInvokeKind(const INVOKEKIND invkind) +{ + switch(invkind) + { + case INVOKE_PROPERTYGET: + return "propget"; + + case INVOKE_PROPERTYPUT: + return "propput"; + + case INVOKE_PROPERTYPUTREF: + return "propputref"; + + case INVOKE_FUNC: + return "func"; + } + + return NULL; +} + +const char* tCOMUtil::getPrintableTypeDesc(const TYPEDESC& tdesc) +{ + static char buffer[200]; + buffer[0] = '\0'; + + switch(tdesc.vt & ~(VT_ARRAY | VT_BYREF)) + { + case VT_VOID: + strcat(buffer, "void"); + break; + + case VT_I2: + strcat(buffer, "short"); + break; + + case VT_I4: + strcat(buffer, "long"); + break; + + case VT_R4: + strcat(buffer, "float"); + break; + + case VT_R8: + strcat(buffer, "double"); + break; + + case VT_CY: + strcat(buffer, "CY"); + break; + + case VT_DATE: + strcat(buffer, "DATE"); + break; + + case VT_BSTR: + strcat(buffer, "BSTR"); + break; + + case VT_DISPATCH: + strcat(buffer, "IDispatch*"); + break; + + case VT_BOOL: + strcat(buffer, "VARIANT_BOOL"); + break; + + case VT_VARIANT: + strcat(buffer, "VARIANT"); + break; + + case VT_UNKNOWN: + strcat(buffer, "IUnknown*"); + break; + + case VT_DECIMAL: + strcat(buffer, "Decimal"); + break; + + case VT_UI1: + strcat(buffer, "unsigned char"); + break; + + case VT_INT: + strcat(buffer, "int"); + break; + + case VT_HRESULT: + strcat(buffer, "void"); + break; + } + + if(tdesc.vt & VT_BYREF) + strcat(buffer, "*"); + + if(tdesc.vt & VT_ARRAY) + strcat(buffer, "[]"); + + return buffer; +} + +const char* tCOMUtil::getPrintableTypeKind(const TYPEKIND tkind) +{ + switch(tkind) + { + case TKIND_COCLASS: + return "coclass"; + break; + + case TKIND_ENUM: + return "enumeration"; + break; + + case TKIND_RECORD: + return "record"; + break; + + case TKIND_MODULE: + return "module"; + break; + + case TKIND_INTERFACE: + return "interface"; + break; + + case TKIND_DISPATCH: + return "dispinterface"; + break; + + case TKIND_ALIAS: + return "alias"; + break; + + case TKIND_UNION: + return "union"; + break; + + default: + return ""; + break; + } +} + + +HRESULT tCOMUtil::GUID2String(GUID& Guid, char** ppGuid) +{ + wchar_t* wcGuid = NULL; + + HRESULT hr = StringFromCLSID(Guid, &wcGuid); + + if (FAILED(hr)) + return hr; + + *ppGuid = new char[wcslen(wcGuid) + 1]; + wcstombs(*ppGuid, wcGuid, wcslen(wcGuid)+1); + + CoTaskMemFree(wcGuid); + + return S_OK; +} + +CLSID tCOMUtil::FindCLSID(ITypeInfo* interface_typeinfo) +{ + ITypeLib* ptypelib = NULL; + ITypeInfo* ptypeinfo = NULL; + long count = 0; + IID iid = IID_NULL; + TYPEATTR* ptypeattr = NULL; + TYPEKIND tkind; + bool found = false; + CLSID clsid = IID_NULL; + + // gets IID + interface_typeinfo->GetTypeAttr(&ptypeattr); + + iid = ptypeattr->guid; + interface_typeinfo->ReleaseTypeAttr(ptypeattr); + ptypeattr = NULL; + + // Gets type library + interface_typeinfo->GetContainingTypeLib(&ptypelib, NULL); + + // iterates looking for IID inside some coclass + count = ptypelib->GetTypeInfoCount(); + + while(count-- && !found) + { + ptypelib->GetTypeInfoType(count, &tkind); + + if(tkind != TKIND_COCLASS) + continue; + + // look inside + ptypelib->GetTypeInfo(count, &ptypeinfo); + + // gets counts and clsid + ptypeinfo->GetTypeAttr(&ptypeattr); + long ifaces_count = ptypeattr->cImplTypes; + clsid = ptypeattr->guid; + + ptypeinfo->ReleaseTypeAttr(ptypeattr); + ptypeattr = NULL; + + HREFTYPE RefType; + ITypeInfo* piface_typeinfo = NULL; + + while(ifaces_count-- && !found) + { + ptypeinfo->GetRefTypeOfImplType(ifaces_count, &RefType); + ptypeinfo->GetRefTypeInfo(RefType, &piface_typeinfo); + piface_typeinfo->GetTypeAttr(&ptypeattr); + + if(IsEqualIID(ptypeattr->guid, iid)) + { + found = true; + } + + piface_typeinfo->ReleaseTypeAttr(ptypeattr); + ptypeattr = NULL; + + COM_RELEASE(piface_typeinfo); + } + + COM_RELEASE(ptypeinfo); + } + + COM_RELEASE(ptypelib); + + return clsid; +} \ No newline at end of file diff --git a/luacom/tCOMUtil.h b/luacom/tCOMUtil.h new file mode 100644 index 00000000..6593c782 --- /dev/null +++ b/luacom/tCOMUtil.h @@ -0,0 +1,69 @@ +// tCOMUtil.h: interface for the tCOMUtil class. +// +////////////////////////////////////////////////////////////////////// + +#ifndef __TCOMUTIL_H +#define __TCOMUTIL_H + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include +#include + +class tCOMUtil +{ +public: + static HRESULT GUID2String(GUID& Guid, char** ppGuid); + static const char* getPrintableTypeKind(const TYPEKIND tkind); + static const char* getPrintableInvokeKind(const INVOKEKIND invkind); + static const char* getPrintableTypeDesc(const TYPEDESC& tdesc); + static void DumpTypeInfo(ITypeInfo* typeinfo); + static bool tCOMUtil::GetRegKeyValue(const char* key, char** pValue); + static bool SetRegKeyValue(const char* key, const char* subkey, const char* value); + static bool DelRegKey(const char *key, const char *subkey); + static CLSID GetCLSID(ITypeInfo* coclassinfo); + static HRESULT ProgID2CLSID(CLSID* pClsid, const char* ProgID); + static ITypeLib* LoadTypeLibFromCLSID( + CLSID clsid, + unsigned short major_version=0); + + static ITypeLib* LoadTypeLibFromProgID( + const char* ProgID, + unsigned short major_version=0); + + static ITypeLib* LoadTypeLibByName(const char *pcFilename); + + static CLSID FindCLSID(ITypeInfo* interface_typeinfo); + + static ITypeInfo* GetCoClassTypeInfo(ITypeLib* typelib, CLSID clsid); + static ITypeInfo* GetCoClassTypeInfo(CLSID clsid); + static ITypeInfo* GetCoClassTypeInfo(IUnknown* punk); + static ITypeInfo* GetCoClassTypeInfo(IDispatch* pdisp, CLSID clsid); + static ITypeInfo* GetCoClassTypeInfo(ITypeLib *typelib, + const char *coclassname); + static ITypeInfo* GetDefaultInterfaceTypeInfo(ITypeInfo* pCoClassinfo, + bool source); + static ITypeInfo* GetInterfaceTypeInfo(ITypeLib* typelib, + const char *interface_name); + static ITypeInfo* GetDispatchTypeInfo(IDispatch* pdisp); + + tCOMUtil(); + virtual ~tCOMUtil(); + +protected: + static bool GetDefaultTypeLibVersion( + const char* libid, + int* version_major, + int* version_minor); +}; + +//#define COM_PRINTREF(x) printf("%p: %d\n", (x), (x)->AddRef()-1); (x)->Release(); +#define COM_PRINTREF(x) + +#define COM_RELEASE(x) {if(x){(x)->Release(); (x) = NULL;}} + + + +#endif // __TCOMUTIL_H diff --git a/luacom/tLuaCOM.cpp b/luacom/tLuaCOM.cpp new file mode 100644 index 00000000..78b916f6 --- /dev/null +++ b/luacom/tLuaCOM.cpp @@ -0,0 +1,788 @@ +/* + * tLuaCOM.cpp + * + * Implementacao da classe tLuaCOM + * + * Renato Cerqueira + * Vinicius Almendra + */ + +// RCS Info +static char *rcsid = "$Id: tLuaCOM.cpp,v 1.39 2005/01/06 18:41:55 fqueiroz Exp $"; +static char *rcsname = "$Name: $"; + +#include "tLuaCOM.h" +#include "tLuaDispatch.h" +#include "LuaAux.h" +#include "tUtil.h" +#include "tLuaCOMException.h" +#include "tCOMUtil.h" + +#include "LuaCompat.h" + +long tLuaCOM::NEXT_ID = 0; + +tLuaCOM::tLuaCOM(lua_State* L, + IDispatch *pdisp_arg, + ITypeInfo *ptinfo_arg, + CLSID coclass + ) +{ + HRESULT hr = S_OK; + + // initialization + plib_tcomp = NULL; + ptcomp = NULL; + clsid = IID_NULL; + lock_count = 0; + conn_point = NULL; + + pdisp = pdisp_arg; + pdisp->AddRef(); + + ptinfo = ptinfo_arg; + + if(ptinfo) + { + // gets ITypeComp interface. If it's not + // available, frees typeinfo, as we only + // use ITypeComp + + hr = ptinfo->GetTypeComp(&ptcomp); + + if(SUCCEEDED(hr)) + { + ptinfo->AddRef(); + + // tries to get typecomp for type library + // (useful to bind to constants) + + ITypeLib* ptlib = NULL; + unsigned int dumb = 0; + + hr = ptinfo->GetContainingTypeLib(&ptlib, &dumb); + + if(SUCCEEDED(hr)) + { + //ptlib->GetTypeComp(&plib_tcomp); + COM_RELEASE(ptlib); + COM_RELEASE(plib_tcomp); + } + } + else + COM_RELEASE(ptinfo); // BUG!!! + } + + typehandler = new tLuaCOMTypeHandler(ptinfo_arg); + + // cleans FuncInfo array + int i; + for(i = 0; i < MAX_FUNCINFOS; i++) + pFuncInfo[i].name = NULL; + + ID = tLuaCOM::NEXT_ID++; + +#ifdef VERBOSE + { + char msg[100]; + lua_Debug ar; + + if(lua_getstack(L, 1, &ar)) + { + lua_getinfo(L, "lnS", &ar); + + sprintf(msg, "%.4d:created:LUAINFO=(%s,%d,%s,%s)", ID, ar.short_src, + ar.currentline, ar.name, ar.what); + } + else if(lua_getstack(L, 0, &ar)) + { + lua_getinfo(L, "lnS", &ar); + sprintf(msg, "%.4d:created:LUAINFO=(%s,%d,%s,%s)", ID, ar.short_src, + ar.currentline, ar.name, ar.what); + } + else + { + sprintf(msg, "%.4d:created:LUAINFO=(not available)", ID); + } + + tUtil::log_verbose("tLuaCOM",msg); + } +#endif +} + +tLuaCOM::~tLuaCOM() +{ + releaseConnections(); + + // frees funcinfos + { + long counter = 0; + + while(pFuncInfo[counter].name != NULL && + counter < MAX_FUNCINFOS) + { + free(pFuncInfo[counter].name); + pFuncInfo[counter].name = NULL; + + ReleaseFuncDesc(pFuncInfo[counter].propget); + ReleaseFuncDesc(pFuncInfo[counter].propput); + ReleaseFuncDesc(pFuncInfo[counter].func); + + counter++; + } + } + + delete typehandler; + typehandler = NULL; + + COM_RELEASE(ptcomp); + COM_RELEASE(plib_tcomp); + COM_RELEASE(ptinfo); + COM_RELEASE(pdisp); + + tUtil::log_verbose("tLuaCOM", "%.4d:destroyed", ID); +} + +bool tLuaCOM::getFUNCDESC(const char *name, FuncInfo& funcinfo) +{ + // First, tries to see we have the FUNCDESC's cached + + long counter = 0; + + for(counter = 0; counter < MAX_FUNCINFOS; counter++) + { + // when .name is NULL, there is no further information + if(pFuncInfo[counter].name == NULL) + break; + + if(strcmp(name, pFuncInfo[counter].name) == 0) + break; + } + + // checks whether funcinfo was found + if(counter < MAX_FUNCINFOS && pFuncInfo[counter].name != NULL) + { + funcinfo = pFuncInfo[counter]; + return true; + } + + // did not find, so gets type information through + // ITypeComp + + HRESULT hr = S_OK; + BINDPTR bindptr; + DESCKIND desckind; + BSTR wName; + ITypeInfo *info = NULL; + + unsigned int dumb = 0; + + wName = tUtil::string2bstr(name); + + unsigned long lhashval = LHashValOfName(LOCALE_SYSTEM_DEFAULT, wName); + + hr = ptcomp->Bind(wName, lhashval, INVOKE_PROPERTYGET, + &info, &desckind, &bindptr); + + if(FAILED(hr) || desckind == DESCKIND_NONE) + funcinfo.propget = NULL; + else + { + funcinfo.propget = bindptr.lpfuncdesc; + info->Release(); + } + + hr = ptcomp->Bind(wName, lhashval, INVOKE_FUNC, + &info, &desckind, &bindptr); + + if(FAILED(hr) || desckind == DESCKIND_NONE) + funcinfo.func = NULL; + else + { + funcinfo.func = bindptr.lpfuncdesc; + info->Release(); + } + + + hr = ptcomp->Bind(wName, lhashval, INVOKE_PROPERTYPUT, + &info, &desckind, &bindptr); + + if(FAILED(hr) || desckind == DESCKIND_NONE) + funcinfo.propput = NULL; + else + { + funcinfo.propput = bindptr.lpfuncdesc; + info->Release(); + } + + // if there is not propertyput, then tries propputref + + if(funcinfo.propput == NULL) + { + hr = ptcomp->Bind(wName, lhashval, INVOKE_PROPERTYPUTREF, + &info, &desckind, &bindptr); + + if(FAILED(hr) || desckind == DESCKIND_NONE) + funcinfo.propput = NULL; + else + { + funcinfo.propput = bindptr.lpfuncdesc; + info->Release(); + } + } + + SysFreeString(wName); + + // If no type information found, returns NULL + if(!funcinfo.propget && !funcinfo.propput && !funcinfo.func) + return false; + else if(counter < MAX_FUNCINFOS) + { + CHECKPRECOND(pFuncInfo[counter].name == NULL); + + pFuncInfo[counter].name = tUtil::strdup(name); + + pFuncInfo[counter].propget = funcinfo.propget; + pFuncInfo[counter].propput = funcinfo.propput; + pFuncInfo[counter].func = funcinfo.func; + + return true; + } + else + return true; +} + + +// +// Tries to find a constant in the type library and +// pushes its value to Lua +// +bool tLuaCOM::getConstant(lua_State* L, const char* name) +{ + if(plib_tcomp == NULL) + return false; + + HRESULT hr = S_OK; + BINDPTR bindptr; + DESCKIND desckind; + BSTR wName; + ITypeInfo *info = NULL; + bool result = false; + + unsigned int dumb = 0; + + wName = tUtil::string2bstr(name); + + unsigned long lhashval = LHashValOfName(LOCALE_SYSTEM_DEFAULT, wName); + + hr = plib_tcomp->Bind(wName, lhashval, INVOKE_PROPERTYGET, + &info, &desckind, &bindptr); + + SysFreeString(wName); + + if(SUCCEEDED(hr) + && desckind == DESCKIND_VARDESC + && bindptr.lpvardesc->varkind == VAR_CONST) + { + typehandler->com2lua(L, *bindptr.lpvardesc->lpvarValue); + result = true; + } + else + result = false; + + COM_RELEASE(info); + + return result; +} + +bool tLuaCOM::getDISPID(const char* name, DISPID* dispid) +{ + HRESULT hr; + wchar_t* w_name = (wchar_t*) malloc( (strlen(name) + 1) * sizeof(wchar_t)); + mbstowcs(w_name,name,strlen(name)+1); + + hr = pdisp->GetIDsOfNames(IID_NULL, &w_name, 1, + LOCALE_SYSTEM_DEFAULT,dispid); + free(w_name); + + return SUCCEEDED(hr); +} + +int tLuaCOM::call(lua_State* L, + DISPID dispid, + int invkind, + FUNCDESC *pfuncdesc, + tLuaObjList& params) +{ + tUtil::log_verbose("tLuaCOM.call", "about to call DISPID 0x%.8x", dispid); + + HRESULT hr = 0; + unsigned int i = 0; + UINT ArgErr = 0; + + // number of return values (required to interface with Lua) + int num_retvals = 0; + + DISPPARAMS dispparams; + VARIANTARG result; + EXCEPINFO excepinfo; + + VariantInit(&result); + + // fills DISPPARAMS structure, converting lua arguments + // to COM parameters + typehandler->fillDispParams(L, dispparams, pfuncdesc, params, invkind); + + hr = pdisp->Invoke( + dispid, + IID_NULL, + LOCALE_SYSTEM_DEFAULT, + invkind, + &dispparams, + &result, + &excepinfo, + &ArgErr); + + //hr = S_OK; + + if(SUCCEEDED(hr)) + { + try + { + // pushes first return value (if any) + // if there is no type information, assumes that + // all functions have return value + if((pfuncdesc && pfuncdesc->elemdescFunc.tdesc.vt != VT_VOID) || + !pfuncdesc) + { + // To ease programming, methods of untyped objects + // always return values to Lua. If the COM method does + // not return nothing, then LuaCOM pushes nil. + // (This avoids confusion with out params) + + typehandler->com2lua(L, result); + num_retvals++; + } + + // pushes out values + if(invkind & INVOKE_FUNC) + num_retvals += typehandler->pushOutValues(L, dispparams); + } + catch(class tLuaCOMException& e) + { + UNUSED(e); + + typehandler->releaseVariants(&dispparams); + VariantClear(&result); + + throw; + } + + typehandler->releaseVariants(&dispparams); + VariantClear(&result); + + return num_retvals; + } + else // Houve erro + { + // Limpa parametros + typehandler->releaseVariants(&dispparams); + + if(hr == DISP_E_EXCEPTION) // excecoes + { + if(excepinfo.bstrDescription != NULL) + COM_EXCEPTION(tUtil::bstr2string(excepinfo.bstrDescription)); + else if(excepinfo.wCode != 0) + COM_EXCEPTION(tUtil::GetErrorMessage(excepinfo.wCode)); + else if(excepinfo.scode != 0) + COM_EXCEPTION(tUtil::GetErrorMessage(excepinfo.scode)); + else + COM_EXCEPTION("Unknown exception"); + } + else // Erros comuns + COM_ERROR(tUtil::GetErrorMessage(hr)); + } +} + +DWORD tLuaCOM::addConnection(tLuaCOM *server) +{ + if(!server->hasTypeInfo()) + return false; + + HRESULT hr; + IDispatch *pdisp_server = server->GetIDispatch(); + + IConnectionPointContainer *pcpc = NULL; + + IConnectionPoint *connection_point; + + hr = pdisp->QueryInterface + ( + IID_IConnectionPointContainer, (void **) &pcpc + ); + + if(FAILED(hr)) + { + return NULL; + } + + { + IID guid; + + server->GetIID(&guid); + + hr = pcpc->FindConnectionPoint(guid, &connection_point); + } + + pcpc->Release(); + pcpc = NULL; + + if(FAILED(hr)) + { + return NULL; + } + + DWORD connection_point_cookie; + + hr = connection_point->Advise + ( + (IUnknown *) pdisp_server, &connection_point_cookie + ); + + if(FAILED(hr)) + { + connection_point->Release(); + connection_point = NULL; + + return NULL; + } + + if(conn_point!=NULL) + conn_point->Release(); + conn_point = connection_point; + conn_cookie = connection_point_cookie; + + return connection_point_cookie; +} + +void tLuaCOM::releaseConnection() +{ + if(conn_point != NULL) { + conn_point->Unadvise(conn_cookie); + conn_point->Release(); + conn_point = NULL; + } +} + +void tLuaCOM::releaseConnection(tLuaCOM* server, DWORD cookie) +{ + IConnectionPointContainer *pcpc = NULL; + + IConnectionPoint *connection_point; + + HRESULT hr = pdisp->QueryInterface + ( + IID_IConnectionPointContainer, (void **) &pcpc + ); + + if(FAILED(hr)) + { + LUACOM_ERROR("Object does not accept connections!"); + } + + { + IID guid; + + server->GetIID(&guid); + + hr = pcpc->FindConnectionPoint(guid, &connection_point); + } + + pcpc->Release(); + pcpc = NULL; + + if(FAILED(hr)) + { + LUACOM_ERROR("No connection point for this interface!"); + } + + connection_point->Unadvise(cookie); + connection_point->Release(); + connection_point = NULL; +} + +void tLuaCOM::releaseConnections() { + if(conn_point==NULL) + return; + + conn_point->Release(); + IConnectionPointContainer *pcpc; + + HRESULT hr = pdisp->QueryInterface(IID_IConnectionPointContainer, (void **) &pcpc); + + if(FAILED(hr)) + { + return; + } + + IEnumConnectionPoints *pecp; + + hr = pcpc->EnumConnectionPoints(&pecp); + pcpc->Release(); + + if(FAILED(hr)) + { + return; + } + + pecp->Reset(); + + IConnectionPoint *pcp; + ULONG fetched = 0; + + hr = pecp->Next(1, &pcp, &fetched); + while(SUCCEEDED(hr) && fetched) { + IEnumConnections *pec; + hr = pcp->EnumConnections(&pec); + if(SUCCEEDED(hr)) { + pec->Reset(); + CONNECTDATA conn; + ULONG conn_fetched = 0; + hr = pec->Next(1, &conn, &conn_fetched); + while(SUCCEEDED(hr) && conn_fetched) { + pcp->Unadvise(conn.dwCookie); + hr = pec->Next(1, &conn, &conn_fetched); + } + pec->Release(); + } + pcp->Release(); + pecp->Next(1, &pcp, &fetched); + } + + pecp->Release(); +} + +// +// isMember +// +// Informa se existe algum metodo ou propriedade com +// o nome passado como parametro +// + +bool tLuaCOM::isMember(const char * name) +{ + HRESULT hr; + DISPID dumb_dispid; + + wchar_t* w_name = (wchar_t*) malloc( (strlen(name) + 1) * sizeof(wchar_t)); + + assert(w_name); + if(!w_name) + return false; + + mbstowcs(w_name, name, strlen(name)+1); + + hr = pdisp->GetIDsOfNames(IID_NULL, &w_name, 1, + LOCALE_SYSTEM_DEFAULT, &dumb_dispid); + free(w_name); + w_name = NULL; + + if(!FAILED(hr)) + return true; + else + return false; +} + + +void tLuaCOM::getHelpInfo(char **ppHelpFile, unsigned long *pHelpContext) +{ + if(!hasTypeInfo()) + { + *ppHelpFile = NULL; + return; + } + + + ITypeLib *typelib = NULL; + BSTR helpfile; + HRESULT hr = S_OK; + + hr = ptinfo->GetDocumentation(-1, NULL, NULL, pHelpContext, &helpfile); + + if(FAILED(hr) || helpfile == NULL) + { + *ppHelpFile = NULL; + return; + } + + // Se nao conseguiu help contextna propria interface, tenta obte-lo + // na type library + if(*pHelpContext == 0) + { + unsigned int dumb_index = 0; + unsigned long typelib_help_context = 0; + BSTR helpfile_typelib; + + hr = ptinfo->GetContainingTypeLib(&typelib, &dumb_index); + + if(!FAILED(hr)) + { + hr = typelib->GetDocumentation(-1, NULL, NULL, + &typelib_help_context, &helpfile_typelib); + + if(!FAILED(hr)) + { + SysFreeString(helpfile); + + helpfile = helpfile_typelib; + *pHelpContext = typelib_help_context; + } + } + } + + int str_size = SysStringLen(helpfile); + *ppHelpFile = (char *) malloc((str_size + 1)*sizeof(wchar_t)); + wcstombs(*ppHelpFile, helpfile, str_size+1); + + SysFreeString(helpfile); +} + + + +// +// CreateLuaCOM +// + + +tLuaCOM * tLuaCOM::CreateLuaCOM(lua_State* L, + IDispatch * pdisp, + const CLSID& coclass, + ITypeInfo* typeinfo, + bool untyped + ) +{ + HRESULT hr = S_OK; + + CHECKPARAM(pdisp && L); + CHECKPARAM(!untyped || !typeinfo); + + if(!untyped) + { + if(!typeinfo) + typeinfo = tCOMUtil::GetDispatchTypeInfo(pdisp); + else + typeinfo->AddRef(); + } + + tLuaCOM *lcom = + new tLuaCOM(L, pdisp, typeinfo, coclass); + + COM_RELEASE(typeinfo); + + // We have one reference (the pointer), so we lock the object + lcom->Lock(); + + return lcom; +} + +ITypeInfo * tLuaCOM::GetDefaultEventsInterface() +{ + CLSID clsid = GetCLSID(); + + if(clsid == IID_NULL) + return NULL; + + ITypeInfo* coclassinfo = tCOMUtil::GetCoClassTypeInfo(pdisp, clsid); + + if(!coclassinfo) + return NULL; + + ITypeInfo *ptinfo = tCOMUtil::GetDefaultInterfaceTypeInfo(coclassinfo, true); + COM_RELEASE(coclassinfo); + + return ptinfo; +} + +void tLuaCOM::ReleaseFuncDesc(FUNCDESC * pfuncdesc) +{ + CHECKPRECOND(ptinfo); + + if(pfuncdesc) + ptinfo->ReleaseFuncDesc(pfuncdesc); +} + +IDispatch * tLuaCOM::GetIDispatch() +{ + return pdisp; +} + +void tLuaCOM::GetIID(IID * piid) +{ + CHECKPRECOND(ptinfo); + + TYPEATTR *ptypeattr; + + ptinfo->GetTypeAttr(&ptypeattr); + *piid = ptypeattr->guid; + ptinfo->ReleaseTypeAttr(ptypeattr); +} + + +CLSID tLuaCOM::GetCLSID() +{ + HRESULT hr = S_OK; + + if(clsid != IID_NULL) + return clsid; + + // tries to find the CLSID using IProvideClassInfo + ITypeInfo* coclassinfo = tCOMUtil::GetCoClassTypeInfo(pdisp); + + if(coclassinfo) + { + clsid = tCOMUtil::GetCLSID(coclassinfo); + COM_RELEASE(coclassinfo); + + if(clsid != IID_NULL) + return clsid; + } + + // Now searches the type library seeking the coclass to which + // this interface belongs + + clsid = tCOMUtil::FindCLSID(ptinfo); + + return clsid; +} + + +ITypeInfo* tLuaCOM::GetTypeInfo() +{ + return ptinfo; +} + +int tLuaCOM::Lock() +{ + return ++lock_count; +} + +int tLuaCOM::Unlock() +{ + if(--lock_count == 0) + { + delete this; + return 0; + } + else + return lock_count; +} + + +bool tLuaCOM::hasTypeInfo(void) +{ + if(ptinfo) + return true; + else + return false; +} + diff --git a/luacom/tLuaCOM.h b/luacom/tLuaCOM.h new file mode 100644 index 00000000..15ee2926 --- /dev/null +++ b/luacom/tLuaCOM.h @@ -0,0 +1,110 @@ +/* + * ttLuaCOM.h + */ + + +#ifndef __LUACOM_H +#define __LUACOM_H + +#include +#include + +extern "C" +{ +#include "..\lua.h" +#include "..\lauxlib.h" +} + +#include "luabeans.h" +#include "tLuaCOMTypeHandler.h" + +#include "tLuaObjList.h" + +enum tWhichInterface {DISP, SOURCE}; + +// Types of FUNCDESC + +#define MAX_FUNCINFOS 150 + +struct FuncInfo +{ + char* name; + + FUNCDESC* propget; + FUNCDESC* propput; + FUNCDESC* func; +}; + + +class tLuaCOM +{ +public: + bool hasTypeInfo(void); + int Lock(void); + int Unlock(void); + ITypeInfo* GetTypeInfo(void); + CLSID GetCLSID(void); + void GetIID(IID *piid); + IDispatch * GetIDispatch(void); + void ReleaseFuncDesc(FUNCDESC *pfuncdesc); + ITypeInfo * GetDefaultEventsInterface(void); + static tLuaCOM * CreateLuaCOM( + lua_State* L, + IDispatch * pdisp, + const CLSID& coclass = IID_NULL, + ITypeInfo* typeinfo=NULL, + bool untyped = false + ); + + void getHelpInfo(char **ppHelpFile, unsigned long *pHelpContext); + bool isMember(const char *name); + + ~tLuaCOM(); + + DWORD addConnection(tLuaCOM *client); + void releaseConnection(tLuaCOM* server, DWORD cookie); + void releaseConnection(); + void releaseConnections(void); + + int call( + lua_State* L, + DISPID dispid, + int invkind, + FUNCDESC *pFuncDesc, + tLuaObjList& params); + + bool getFUNCDESC(const char* name, FuncInfo& funcinfo); + bool getConstant(lua_State* L, const char* name); + bool getDISPID(const char* name, DISPID* dispid); + + static long NEXT_ID; +protected: + ITypeComp* ptcomp; + ITypeComp* plib_tcomp; + long lock_count; + CLSID clsid; + IConnectionPoint *conn_point; + DWORD conn_cookie; + + tLuaCOM( + lua_State* L, + IDispatch *pdisp_arg, + ITypeInfo *ptinfo_arg, + CLSID coclass + ); + + tLuaCOMTypeHandler * typehandler; + + + LPDISPATCH pdisp; + ITypeInfo* ptinfo; + + // struct to hold all type information for a + // member + + FuncInfo pFuncInfo[MAX_FUNCINFOS]; +private: + long ID; +}; + +#endif // __LUACOM_H diff --git a/luacom/tLuaCOMClassFactory.cpp b/luacom/tLuaCOMClassFactory.cpp new file mode 100644 index 00000000..938bcf07 --- /dev/null +++ b/luacom/tLuaCOMClassFactory.cpp @@ -0,0 +1,131 @@ +// tLuaCOMClassFactory.cpp: implementation of the tLuaCOMClassFactory class. +// +////////////////////////////////////////////////////////////////////// + +extern "C" { + #include "..\lua.h" + #include "LuaCompat.h" +} +#include "luacom.h" +#include "tLuaCOMClassFactory.h" +#include "tLuaCOMException.h" +#include "tUtil.h" + + +STDMETHODIMP +tLuaCOMClassFactory::QueryInterface(REFIID iid, void** ppv) +{ + *ppv = NULL; + + if (iid == IID_IUnknown || iid == IID_IClassFactory) + *ppv = this; + else + return E_NOINTERFACE; + + AddRef(); + return NOERROR; +} + + +STDMETHODIMP_(ULONG) +tLuaCOMClassFactory::AddRef(void) +{ + return ++m_cRef; +} + + +STDMETHODIMP_(ULONG) +tLuaCOMClassFactory::Release(void) +{ + if(--m_cRef == 0) + { + delete this; + return 0; + } + + return m_cRef; +} + +/* + * tLuaCOMClassFactory::CreateInstance, LockServer + * + * Purpose: + * Implements IClassFactory::CreateInstance, LockServer + * + */ +STDMETHODIMP +tLuaCOMClassFactory::CreateInstance(IUnknown* punkOuter, + REFIID riid, + void** ppv) +{ + HRESULT hr = E_NOTIMPL; + + *ppv = NULL; + + // This implementation does'nt allow aggregation + if (punkOuter) + return CLASS_E_NOAGGREGATION; + + // This is REGCLS_SINGLEUSE class factory, so CreateInstance will be + // called atmost once. An application objects has a REGCLS_SINGLEUSE class + // factory. The global application object has already been created when + // CreateInstance is called. A REGCLS_MULTIPLEUSE class factory's + // CreateInstance would be called multiple times and would create a new + // object each time. An MDI application would have a REGCLS_MULTIPLEUSE + // class factory for it's document objects. + hr = object->QueryInterface(riid, ppv); + + return hr; +} + +STDMETHODIMP +tLuaCOMClassFactory::LockServer(BOOL fLock) +{ + CoLockObjectExternal(object, fLock, TRUE); + return NOERROR; +} + + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +tLuaCOMClassFactory::tLuaCOMClassFactory(IDispatch* object_arg) +{ + CHECKPARAM(object_arg); + + m_cRef = 0; + + L_inproc = NULL; + object = object_arg; + object->AddRef(); +} + +tLuaCOMClassFactory::tLuaCOMClassFactory(lua_State* L) +{ + CHECKPARAM(L); + + m_cRef = 0; + + L_inproc = L; + lua_getregistry(L); + lua_pushstring(L,"object"); + lua_gettable(L,-2); + object = (IDispatch*)luaCompat_getPointer(L,-1); + object->AddRef(); + lua_pop(L,1); + lua_pushstring(L,"object"); + lua_pushnil(L); + lua_settable(L,-3); + lua_pop(L,1); +} + +tLuaCOMClassFactory::~tLuaCOMClassFactory() +{ + object->Release(); + if(L_inproc!=NULL) { + luacom_close(L_inproc); + lua_close(L_inproc); + } +} diff --git a/luacom/tLuaCOMClassFactory.h b/luacom/tLuaCOMClassFactory.h new file mode 100644 index 00000000..6ca9e0c8 --- /dev/null +++ b/luacom/tLuaCOMClassFactory.h @@ -0,0 +1,43 @@ +// tLuaCOMClassFactory.h: interface for the tLuaCOMClassFactory class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_TLUACOMCLASSFACTORY_H__B2C2D8B2_FE51_4745_8C21_FFC29FE81F86__INCLUDED_) +#define AFX_TLUACOMCLASSFACTORY_H__B2C2D8B2_FE51_4745_8C21_FFC29FE81F86__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "..\lua.h" +#include // IClassFactory + +// +// LuaCOM Classfactory +// + +class tLuaCOMClassFactory : public IClassFactory +{ +public: + // IUnknown methods + STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + + // IClassFactory methods + STDMETHOD(CreateInstance)(IUnknown* punkOuter, REFIID riid, + void** ppv); + STDMETHOD(LockServer)(BOOL fLock); + + tLuaCOMClassFactory(IDispatch* object); + tLuaCOMClassFactory(lua_State* L); + virtual ~tLuaCOMClassFactory(); + +private: + ULONG m_cRef; + lua_State* L_inproc; +protected: + IDispatch* object; +}; + +#endif // !defined(AFX_TLUACOMCLASSFACTORY_H__B2C2D8B2_FE51_4745_8C21_FFC29FE81F86__INCLUDED_) diff --git a/luacom/tLuaCOMConnPoints.cpp b/luacom/tLuaCOMConnPoints.cpp new file mode 100644 index 00000000..88cccfdd --- /dev/null +++ b/luacom/tLuaCOMConnPoints.cpp @@ -0,0 +1,1683 @@ +#include +#include +#include +#include + +#include "tLuaCOM.h" +#include "tLuaCOMConnPoints.h" +#include "tCOMUtil.h" +#include "tLuaCOMException.h" +#include "LuaAux.h" + +#include "luacom_internal.h" + +extern "C" +{ +#include "LuaCompat.h" +} + +#define CONNPOINT_NAME "__LUACOM_CONNPOINT" + + +/*--------------------------------------------------------------------------- + tLuaCOMEnumConnPoints's implementation of its main COM object class + including Constructor, Destructor, QueryInterface, AddRef, Release, + Next, Skip, Reset, and Clone. +---------------------------------------------------------------------------*/ + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnPoints::tLuaCOMEnumConnPoints + + Summary: tLuaCOMEnumConnPoints Constructor. + + Args: IUnknown* pHostObj + Pointer to the host object whose connection points are + being enumerated. + + Modifies: cRefs, pHostObj, iEnumIndex, cConnPts, and paConnPts. + + Returns: void +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +tLuaCOMEnumConnPoints::tLuaCOMEnumConnPoints(IUnknown* pHostObj) +{ + // Zero the COM object's reference count. + cRefs = 0; + + // Assign the Host Object pointer. + pHostObj = pHostObj; + + // Initialize the Connection Point enumerator variables. + iEnumIndex = 0; + cConnPts = 0; + paConnPts = NULL; + + return; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnPoints::~tLuaCOMEnumConnPoints + + Summary: tLuaCOMEnumConnPoints Destructor. + + Args: void + + Modifies: paConnPts. + + Returns: void +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +tLuaCOMEnumConnPoints::~tLuaCOMEnumConnPoints(void) +{ + if (NULL != paConnPts) + { + UINT i; + + // Release all the connection point interface pointers. + for (i=0; iAddRef(); + } + } + else + hr = E_OUTOFMEMORY; + + return (hr); +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnPoints::QueryInterface + + Summary: QueryInterface of the tLuaCOMEnumConnPoints non-delegating + IUnknown implementation. + + Args: REFIID riid, + [in] GUID of the Interface being requested. + void ** ppv) + [out] Address of the caller's pointer variable that will + receive the requested interface pointer. + + Modifies: . + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP tLuaCOMEnumConnPoints::QueryInterface( + REFIID riid, + void ** ppv) +{ + HRESULT hr = E_NOINTERFACE; + + *ppv = NULL; + + // The IEnumConnectionPoints interface is implemented directly in + // this COM object rather than being a nested interface implementation. + if (IID_IUnknown == riid || IID_IEnumConnectionPoints == riid) + *ppv = (LPVOID)this; + + if (NULL != *ppv) + { + // We've handed out a pointer to the interface so obey the COM rules + // and AddRef the reference count. + ((LPUNKNOWN)*ppv)->AddRef(); + hr = NOERROR; + } + + return (hr); +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnPoints::AddRef + + Summary: AddRef of the tLuaCOMEnumConnPoints non-delegating IUnknown + implementation. + + Args: void + + Modifies: cRefs. + + Returns: ULONG + New value of cRefs (COM object's reference count). +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP_(ULONG) tLuaCOMEnumConnPoints::AddRef(void) +{ + cRefs = ++cRefs; + + // Also AddRef the host object to ensure it stays around as long as + // this enumerator. + pHostObj->AddRef(); + + return cRefs; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnPoints::Release + + Summary: Release of the tLuaCOMEnumConnPoints non-delegating IUnknown + implementation. + + Args: void + + Modifies: cRefs. + + Returns: ULONG + New value of cRefs (COM object's reference count). +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP_(ULONG) tLuaCOMEnumConnPoints::Release(void) +{ + // Pass this release along to the Host object being enumerated. + pHostObj->Release(); + + cRefs = --cRefs; + + if (0 == cRefs) + { + // We artificially bump the main ref count to prevent reentrancy via + // the main object destructor. + cRefs++; + delete this; + } + + return cRefs; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnPoints::Next + + Summary: The Next member method of this IEnumConnectionPoints interface + implementation. Called by outside clients of a + tLuaCOMEnumConnPoints object to request that a number of next + connection point interface pointers be deposited into an array + supplied by the caller. + + Args: ULONG cReq + Number of connection points requested for return (starting at + the current Enumerator index). + IConnPoint** paConnPts, + Pointer to a caller's output array that will receive the + enumerated IConnPoint interface pointers. + ULONG* cEnumerated) + Pointer to a ULONG variable that will contain the number of + connection points actually enumerated by this call. + + Modifies: . + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP tLuaCOMEnumConnPoints::Next( + ULONG cReq, + IConnectionPoint** paConnPts, + ULONG* pcEnumerated) +{ + HRESULT hr = NOERROR; + ULONG cRet = 0; + + // Make sure the argument values passed are valid. + if (NULL != paConnPts) + { + if (NULL != paConnPts) + { + if (NULL != *paConnPts && iEnumIndex < cConnPts) + { + if (NULL != pcEnumerated) + *pcEnumerated = 0L; + else + if (1L != cReq) + hr = E_POINTER; + } + else + hr = S_FALSE; + } + else + hr = E_POINTER; + } + else + hr = S_FALSE; + + if (SUCCEEDED(hr)) + { + // Starting at the current Enumerator index, loop to assign the + // requested number of output connection point interface pointers. + for (; iEnumIndex < cConnPts && cReq > 0; + paConnPts++, cRet++, cReq--) + { + // Assign from the inside Enumerator array to the specified receiving + // array. + *paConnPts = paConnPts[iEnumIndex++]; + // After assigning a copy of an IConnPoint pointer, AddRef it. + if (NULL != *paConnPts) + (*paConnPts)->AddRef(); + } + + // Assign the output number of connection points enumerated. + if (NULL != pcEnumerated) + *pcEnumerated = cRet; + } + + return hr; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnPoints::Skip + + Summary: The Skip member method of this IEnumConnectionPoints interface + implementation. Starting at the current Enumerator index, skip + the specified number of connection point items. + + Args: ULONG cSkip + Number of Connection Point items to skip. + + Modifies: . + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP tLuaCOMEnumConnPoints::Skip( + ULONG cSkip) +{ + HRESULT hr = NOERROR; + + // If there really is a connection point array and the requested + // amount of skip does not exceed the number of connection points, + // then bump the index by the requested skip amount. + if (NULL != paConnPts && (iEnumIndex + cSkip) < cConnPts) + iEnumIndex += cSkip; + else + hr = S_FALSE; + + return hr; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnPoints::Reset + + Summary: The Reset member method of the IEnumConnectionPoints interface + implementation. Resets the Enumeration index to the first + connection point item in the array. + + Args: void. + + Modifies: . + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP tLuaCOMEnumConnPoints::Reset( + void) +{ + // Zero the main Enumerator index. + iEnumIndex = 0; + + return NOERROR; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnPoints::Clone + + Summary: The Clone member method of this IEnumConnectionPoints + interface implementation. Creates a new clone of this entire + Connection Point enumerator COM object. + + Args: IEnumConnectionPoints** ppIEnum + Address of the caller's output pointer variable that will + receive the IEnumConnectionPoints interface pointer of the + new enumerator clone. + + Modifies: ... + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP tLuaCOMEnumConnPoints::Clone( + IEnumConnectionPoints** ppIEnum) +{ + HRESULT hr; + tLuaCOMEnumConnPoints* pCOEnum; + + // NULL the output variable first. + *ppIEnum = NULL; + + // Create the Clone Enumerator COM object. + pCOEnum = new tLuaCOMEnumConnPoints(pHostObj); + if (NULL != pCOEnum) + { + // Initialize it with same values as in this existing enumerator. + hr = pCOEnum->Init(cConnPts, paConnPts, iEnumIndex); + if (SUCCEEDED(hr)) + { + // QueryInterface to return the requested interface pointer. + // An AddRef will be conveniently done by the QI. + if (SUCCEEDED(hr)) + hr = pCOEnum->QueryInterface( + IID_IEnumConnectionPoints, + (void **)ppIEnum); + } + } + else + hr = E_OUTOFMEMORY; + + return hr; +} + + +/*--------------------------------------------------------------------------- + tLuaCOMConnPoint's implementation of its main COM object class + including Constructor, Destructor, QueryInterface, AddRef, Release, + GetConnectionInterface, GetConnPointContainer, Advise, Unadvise, + and EnumConnections. +---------------------------------------------------------------------------*/ + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMConnPoint::tLuaCOMConnPoint + + Summary: tLuaCOMConnPoint Constructor. + + Args: IUnknown* pHostObj + Pointer to IUnknown of the connectable object offering this + connection point. + + Modifies: ... + + Returns: void +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +tLuaCOMConnPoint::tLuaCOMConnPoint(lua_State *p_L, + IUnknown* pHostObj) +{ + // stores lua state + L = p_L; + + // Zero the COM object's reference count. + cRefs = 0; + + // Remember an IUnknown pointer to the connectable object that offers + // this connection point. Since this connection point object's lifetime + // is geared to that of the connectable object there is no need to + // AddRef the following copied pointer to the connectable object. + pHostObj = pHostObj; + + // Initialize the Connection Point variables. + dwNextCookie = COOKIE_START_VALUE; + uiMaxIndex = 0; + cConnections = 0; + + // creates a new lua tag associated with this connection point + luaCompat_pushTypeByName(L, MODULENAME, LCOM_CONNPOINT_TYPENAME); + lua_pushcfunction(L, tagmeth_index); + luaCompat_handleNoIndexEvent(L); + + lua_pop(L, 1); + + for(int i = 0; i < ALLOC_CONNECTIONS; i++) + sinks[i] = NULL; + + + return; +} + + +tLuaCOMConnPoint::~tLuaCOMConnPoint(void) +{ + UINT i; + + if (NULL != paConnections) + { + // Release all the connection sink interface pointers. + for (i=0; iRelease(); + + if (NULL != sinks[i]) + { + sinks[i]->Unlock(); + sinks[i] = NULL; + } + } + } + + return; +} + + +HRESULT tLuaCOMConnPoint::Init(REFIID riid, ITypeInfo *typeinfo) +{ + HRESULT hr = NOERROR; + CONNECTDATA* paConns = paConnections; + + // Keep a copy of the reference to the IID of the sink interface + // associated with this connection point. Needed for later + // use by the GetConnectionInterface method. + iidSink = riid; + source_typeinfo = typeinfo; + + // Build the initial dynamic array for connections. +/* paConns = new CONNECTDATA[ALLOC_CONNECTIONS]; + sinks = new tLuaCOM*[ALLOC_CONNECTIONS];*/ + + if (NULL != paConns) + { + // Zero the array. + memset(paConns, 0, ALLOC_CONNECTIONS * sizeof(CONNECTDATA)); + + // Rig this connection point object so that it will use the + // new internal array of connections. + uiMaxIndex = ALLOC_CONNECTIONS; + //paConnections = paConns; + } + else + hr = E_OUTOFMEMORY; + + return (hr); +} + + + +STDMETHODIMP tLuaCOMConnPoint::QueryInterface( + REFIID riid, + void ** ppv) +{ + HRESULT hr = E_NOINTERFACE; + + *ppv = NULL; + + // The IConnPoint interface is implemented directly in this + // COM object rather than being a nested interface implementation. + if (IID_IUnknown == riid || IID_IConnectionPoint == riid) + *ppv = (LPVOID)this; + + if (NULL != *ppv) + { + // We've handed out a pointer to the interface so obey the COM rules + // and AddRef the reference count. + ((LPUNKNOWN)*ppv)->AddRef(); + hr = NOERROR; + } + + return (hr); +} + + +STDMETHODIMP_(ULONG) tLuaCOMConnPoint::AddRef(void) +{ + cRefs = ++cRefs; + + return cRefs; +} + + +STDMETHODIMP_(ULONG) tLuaCOMConnPoint::Release(void) +{ + cRefs = --cRefs; + + if (0 == cRefs) + { + // We artificially bump the main ref count to prevent reentrancy via + // the main object destructor. We relinquish thread ownership of this + // object prior to deleting it--a good practice. + cRefs++; + delete this; + } + + return cRefs; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMConnPoint::GetSlot + + Summary: An internal private utility member method to obtain a free + slot in the dynamic connections array. GetSlot will expand the + dynamic array for more entries if needed. To guarantee thread + safety, this private method should always be called within the + protection of a bracketed OwnThis, UnOwnThis pair. + + Args: UINT* puiFreeSlot + Address of an output variable to receive the free slot index. + + Modifies: uiMaxIndex, paConnections. + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +HRESULT tLuaCOMConnPoint::GetSlot( + UINT* puiFreeSlot) +{ + HRESULT hr = NOERROR; + BOOL bOpen = FALSE; + UINT i; + //CONNECTDATA* paConns; + + // Zero the output variable. + *puiFreeSlot = 0; + + // Loop to find an empty slot. + for (i=0; iQueryInterface( + IID_IConnectionPointContainer, + (void **) ppConnPtCon); + + return hr; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMConnPoint::Advise + + Summary: The Advise member method of this IConnPoint interface + implementation. Called by clients to establish a connection of + their sink to this connection point. Uses the CThreaded + OwnThis mechanism to provide mutually exclusive access by + multiple threads. + + Args: IUnknown* pUnkSink + IUnknown interface pointer of the Sink object in the client. + DWORD* pdwCookie + Pointer to a DWORD in the client that will receive a unique + key used by the client to refer to the connection established + by this Advise call. + + Modifies: ... + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP tLuaCOMConnPoint::Advise( + IUnknown* pUnkSink, + DWORD* pdwCookie) +{ + HRESULT hr = NOERROR; + UINT uiFreeSlot = 0; + IDispatch* pISink = NULL; + + + // Zero the output connection key. + *pdwCookie = 0; + + // Get the specific associated client Sink interface that this + // connection point expects to use for notifications. + hr = pUnkSink->QueryInterface(IID_IDispatch/*iidSink*/, (void **)&pISink); + if (SUCCEEDED(hr)) + { + // Store the specific sink interface in this connection point's + // array of live connections. First find a free slot (expand the + // array if needed). + hr = GetSlot(&uiFreeSlot); + if (SUCCEEDED(hr)) + { + // Assign the new slot with the connection entry. + paConnections[uiFreeSlot].pUnk = pISink; + paConnections[uiFreeSlot].dwCookie = dwNextCookie; + + try + { + // vb supplies a very weird type info, so we + // stay with ours, as it's where vb will look for the + // DISPID's anyway + sinks[uiFreeSlot] = + tLuaCOM::CreateLuaCOM(L, pISink, IID_NULL, source_typeinfo); + } + catch(class tLuaCOMException& e) + { + UNUSED(e); + return CONNECT_E_CANNOTCONNECT; + } + + // Assign the output Cookie value. + *pdwCookie = dwNextCookie; + + // Increment the Cookie counter. + dwNextCookie++; + + // Increment the number of live connections. + cConnections++; + } + } + else if (hr == E_NOINTERFACE) + { + // The sink does not support iidSink. + hr = CONNECT_E_CANNOTCONNECT; + } + + return hr; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMConnPoint::Unadvise + + Summary: The Unadvise member method of this IConnPoint interface + implementation. Called by clients to disconnect a connection + of their sink to this connection point. The connection is + identified by the dwCookie argument (obtained by a previous + Advise call). Uses the CThreaded OwnThis mechanism to provide + mutually exclusive access by multiple threads. + + Args: DWORD dwCookie + Connection key that was obtained by a previous Advise call. + + Modifies: . + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP tLuaCOMConnPoint::Unadvise( + DWORD dwCookie) +{ + HRESULT hr = NOERROR; + UINT uiSlot; + + if (0 != dwCookie) + { + hr = FindSlot(dwCookie, &uiSlot); + if (SUCCEEDED(hr)) + { + // Release the sink interface. + COM_RELEASE(paConnections[uiSlot].pUnk); + sinks[uiSlot]->Unlock(); + sinks[uiSlot] = NULL; + + // Mark the array entry as empty. + paConnections[uiSlot].dwCookie = 0; + + // Decrement the number of live connections. + cConnections--; + } + + } + else + hr = E_INVALIDARG; + + return hr; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMConnPoint::EnumConnections + + Summary: The EnumConnections member method of this IConnPoint + interface implementation. Called to obtain an IEnumConnections + enumerator interface that can be used to enumerate the + connections of this connection point. Uses the CThreaded + OwnThis mechanism to ensure mutually exclusive access by + multiple threads. + + Args: IEnumConnections** ppIEnum + Address of the caller's output pointer variable that will + receive the enumerator IEnumConnections interface pointer. + + Modifies: ... + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP tLuaCOMConnPoint::EnumConnections( + IEnumConnections** ppIEnum) +{ + HRESULT hr = OLE_E_NOCONNECTION; + CONNECTDATA* paConns; + tLuaCOMEnumConnections* pCOEnum; + UINT i,j; + + // Zero the output enumerator interface pointer. + *ppIEnum = NULL; + + if (0 != cConnections) + { + // Create an array of CONNECTDATA structures. + paConns = new CONNECTDATA[(UINT)cConnections]; + if (NULL != paConns) + { + for (i=0, j=0; iInit(cConnections, paConns, 0); + + // QueryInterface to return the requested interface pointer. + // An AddRef will be conveniently done by the QI. + if (SUCCEEDED(hr)) + hr = pCOEnum->QueryInterface( + IID_IEnumConnections, + (void **)ppIEnum); + } + else + hr = E_OUTOFMEMORY; + + // We're done with the locally constructed array copy--delete it. + delete [] paConns; + } + else + hr = E_OUTOFMEMORY; + } + + return hr; +} + + +/*--------------------------------------------------------------------------- + tLuaCOMEnumConnections's implementation of its main COM object class + including Constructor, Destructor, QueryInterface, AddRef, Release, + Next, Skip, Reset, and Clone. +---------------------------------------------------------------------------*/ + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnections::tLuaCOMEnumConnections + + Summary: tLuaCOMEnumConnections Constructor. + + Args: IUnknown* pHostObj + Pointer to IUnknown interface of the host Connection Point + COM object whose connections are being enumerated. + + Modifies: cRefs, pHostObj, iEnumIndex, cConnections, + and paConnections. + + Returns: void +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +tLuaCOMEnumConnections::tLuaCOMEnumConnections( + IUnknown* pHostObj) +{ + // Zero the COM object's reference count. + cRefs = 0; + + // Assign the Host Object pointer. + pHostObj = pHostObj; + + // Initialize the Connection Point enumerator variables. + iEnumIndex = 0; + cConnections = 0; + paConnections = NULL; + + return; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnections::~tLuaCOMEnumConnections + + Summary: tLuaCOMEnumConnections Destructor. + + Args: void + + Modifies: paConnections. + + Returns: void +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +tLuaCOMEnumConnections::~tLuaCOMEnumConnections(void) +{ + if (NULL != paConnections) + { + UINT i; + + // Release all the connected sink interface pointers. + for (i=0; iRelease(); + + // Delete the array of connections. + delete [] paConnections; + } + + return; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnections::Init + + Summary: tLuaCOMEnumConnections Initialization method. Create any + necessary arrays, structures, and objects. + + Args: ULONG cConnections + Number of Connections. + CONNECTDATA* paConnections, + Pointer to array of connections. + ULONG iEnumIndex + The Enumerator index initial value. + + Modifies: cConnections, paConnections, pHostObj, iEnumIndex. + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +HRESULT tLuaCOMEnumConnections::Init( + ULONG cConnections, + CONNECTDATA* paConnections, + ULONG iEnumIndex) +{ + HRESULT hr = NOERROR; + UINT i; + + // Remember the number of live Connections. + cConnections = cConnections; + + // Remember the initial enumerator index. + iEnumIndex = iEnumIndex; + + // Create a copy of the array of connections and keep it inside + // this enumerator COM object. + paConnections = new CONNECTDATA [(UINT) cConnections]; + + // Fill the array copy with the connection data from the connections + // array passed. AddRef for each new sink Interface pointer copy made. + if (NULL != paConnections) + { + for (i=0; iAddRef(); + } + } + else + hr = E_OUTOFMEMORY; + + return (hr); +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnections::QueryInterface + + Summary: QueryInterface of the tLuaCOMEnumConnections non-delegating + IUnknown implementation. + + Args: REFIID riid, + [in] GUID of the Interface being requested. + void ** ppv) + [out] Address of the caller's pointer variable that will + receive the requested interface pointer. + + Modifies: . + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP tLuaCOMEnumConnections::QueryInterface( + REFIID riid, + void ** ppv) +{ + HRESULT hr = E_NOINTERFACE; + + *ppv = NULL; + + // The IEnumConnections interface is implemented directly in + // this COM object rather than being a nested interface implementation. + if (IID_IUnknown == riid || IID_IEnumConnections == riid) + *ppv = (LPVOID)this; + + if (NULL != *ppv) + { + // We've handed out a pointer to the interface so obey the COM rules + // and AddRef the reference count. + ((LPUNKNOWN)*ppv)->AddRef(); + hr = NOERROR; + } + + return (hr); +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnections::AddRef + + Summary: AddRef of the tLuaCOMEnumConnections non-delegating IUnknown + implementation. + + Args: void + + Modifies: cRefs. + + Returns: ULONG + New value of cRefs (COM object's reference count). +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP_(ULONG) tLuaCOMEnumConnections::AddRef(void) +{ + cRefs = ++cRefs; + + // Also AddRef the host object to ensure it stays around as long as + // this enumerator. + pHostObj->AddRef(); + + return cRefs; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnections::Release + + Summary: Release of the tLuaCOMEnumConnections non-delegating IUnknown + implementation. + + Args: void + + Modifies: cRefs. + + Returns: ULONG + New value of cRefs (COM object's reference count). +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP_(ULONG) tLuaCOMEnumConnections::Release(void) +{ + // Pass this release along to the Host object being enumerated. + pHostObj->Release(); + + cRefs = --cRefs; + + if (0 == cRefs) + { + // We artificially bump the main ref count to prevent reentrancy via + // the main object destructor. + cRefs++; + delete this; + } + + return cRefs; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnections::Next + + Summary: The Next member method of this IEnumConnections interface + implementation. Called by outside clients of a + tLuaCOMEnumConnections object to request a number of next + connections be returned in an array supplied by the caller. + + Args: ULONG cReq + Number of connection points requested for return (starting at + the current Enumerator index). + CONNECTDATA* paConnections, + Pointer to a caller's output array that will receive the + enumerated connection data structures. + ULONG* pcEnumerated) + Pointer to a ULONG variable that will contain the number of + connection points actually enumerated by this call. + + Modifies: . + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP tLuaCOMEnumConnections::Next( + ULONG cReq, + CONNECTDATA* paConnections, + ULONG* pcEnumerated) +{ + HRESULT hr = NOERROR; + ULONG cRet = 0; + + // Make sure the argument values passed are valid. + if (NULL != paConnections) + { + if (NULL != paConnections) + { + if (iEnumIndex < cConnections) + { + if (NULL != pcEnumerated) + *pcEnumerated = 0L; + else + if (1L != cReq) + hr = E_POINTER; + } + else + hr = S_FALSE; + } + else + hr = E_POINTER; + } + else + hr = S_FALSE; + + if (SUCCEEDED(hr)) + { + // Starting at the current Enumerator index, loop to assign the + // requested number of output connection data structures. + for (; iEnumIndex < cConnections && cReq > 0; + paConnections++, iEnumIndex++, cRet++, cReq--) + { + // Because we are assigning a copy of a connection's data, AddRef + // its sink interface pointer. + if (NULL != paConnections[iEnumIndex].pUnk) + paConnections[iEnumIndex].pUnk->AddRef(); + + // Assign a connection's data from the inside Enumerator array to + // the specified output receiving array. + *paConnections = paConnections[iEnumIndex]; + } + + // Assign the output number of connections enumerated. + if (NULL != pcEnumerated) + *pcEnumerated = cRet; + } + + return hr; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnections::Skip + + Summary: The Skip member method of this IEnumConnections interface + implementation. Starting at the current Enumerator index, skip + the specified number of connection items. + + Args: ULONG cSkip + Number of Connection items to skip. + + Modifies: . + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP tLuaCOMEnumConnections::Skip( + ULONG cSkip) +{ + HRESULT hr = NOERROR; + + // If there really is a connection array and the requested + // amount of skip does not exceed the number of connections, + // then bump the index by the requested skip amount. + if (NULL != paConnections && (iEnumIndex + cSkip) < cConnections) + iEnumIndex += cSkip; + else + hr = S_FALSE; + + return hr; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnections::Reset + + Summary: The Reset member method of the IEnumConnections interface + implementation. Resets the Enumeration index to the first + connection item in the array. + + Args: void. + + Modifies: . + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP tLuaCOMEnumConnections::Reset( + void) +{ + // Zero the main Enumerator index. + iEnumIndex = 0; + + return NOERROR; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMEnumConnections::Clone + + Summary: The Clone member method of this IEnumConnections interface + implementation. Creates a new clone of this entire Connection + enumerator COM object and returns a pointer to its + IEnumConnections interface. + + Args: IEnumConnections** ppIEnum + Address of the caller's output pointer variable that will + receive the IEnumConnections interface pointer of the + new enumerator clone. + + Modifies: ... + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP tLuaCOMEnumConnections::Clone( + IEnumConnections** ppIEnum) +{ + HRESULT hr; + tLuaCOMEnumConnections* pCOEnum; + + // NULL the output variable first. + *ppIEnum = NULL; + + // Create the Clone Enumerator COM object. + pCOEnum = new tLuaCOMEnumConnections(pHostObj); + if (NULL != pCOEnum) + { + // Initialize it with same values as in this existing enumerator. + hr = pCOEnum->Init(cConnections, paConnections, iEnumIndex); + if (SUCCEEDED(hr)) + { + // QueryInterface to return the requested interface pointer. + // An AddRef will be conveniently done by the QI. + if (SUCCEEDED(hr)) + hr = pCOEnum->QueryInterface( + IID_IEnumConnections, + (void **)ppIEnum); + } + } + else + hr = E_OUTOFMEMORY; + + return hr; +} + + + + + + + + + + + + + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMConnPointContainer + ::tLuaCOMConnPointContainer + + Summary: Constructor for the tLuaCOMConnPointContainer interface + instantiation. + + Args: COBall* pBackObj, + Back pointer to the parent outer object. + IUnknown* pUnkOuter + Pointer to the outer Unknown. For delegation. + + Modifies: pBackObj, pUnkOuter. + + Returns: void +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +tLuaCOMConnPointContainer::tLuaCOMConnPointContainer(lua_State* p_L, + IUnknown* p_pUnkOuter) +{ + HRESULT hr = S_OK; + ITypeInfo *events_typeinfo = NULL; + + CHECKPARAM(p_L); CHECKPARAM(p_pUnkOuter); + + // stores pointers + pUnkOuter = p_pUnkOuter; + L = p_L; + + // creates connection point for source interface + IProvideClassInfo2 *ci2 = NULL; + + hr = pUnkOuter->QueryInterface(IID_IProvideClassInfo2, (void **) &ci2); + CHK_COM_CODE(hr); + + IID iid; + + hr = ci2->GetGUID(GUIDKIND_DEFAULT_SOURCE_DISP_IID, &iid); + CHK_COM_CODE(hr); + + ITypeInfo *coclassinfo = NULL; + + hr = ci2->GetClassInfo(&coclassinfo); + CHK_COM_CODE(hr); + + events_typeinfo = tCOMUtil::GetDefaultInterfaceTypeInfo(coclassinfo, true); + CHK_LCOM_ERR(events_typeinfo, "No default source typeinfo."); + + COM_RELEASE(ci2); + COM_RELEASE(coclassinfo); + + max_connection_points = 1; + connection_points = new tLuaCOMConnPoint*[max_connection_points]; + CHKMALLOC(connection_points); + + connection_points[0] = new tLuaCOMConnPoint(L, p_pUnkOuter); + CHKMALLOC(connection_points[0]); + + connection_points[0]->AddRef(); + + num_connection_points = 1; + + hr = connection_points[0]->Init(iid, events_typeinfo); + CHK_COM_CODE(hr); + + default_connection = connection_points[0]; + + return; +} + + + +tLuaCOMConnPointContainer::~tLuaCOMConnPointContainer(void) +{ + while(num_connection_points--) + { + COM_RELEASE(connection_points[num_connection_points]); + } + + delete[] connection_points; + return; +} + + +STDMETHODIMP tLuaCOMConnPointContainer::QueryInterface( + REFIID riid, + void ** ppv) +{ + // Delegate this call to the outer object's QueryInterface. + return pUnkOuter->QueryInterface(riid, ppv); +} + + + +STDMETHODIMP_(ULONG) tLuaCOMConnPointContainer::AddRef(void) +{ + return pUnkOuter->AddRef(); +} + + +STDMETHODIMP_(ULONG) tLuaCOMConnPointContainer::Release(void) +{ + return pUnkOuter->Release(); +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMConnPointContainer::FindConnectionPoint + + Summary: Given an IID for a connection point sink find and return the + interface pointer for that connection point sink. + + Args: REFIID riid + Reference to an IID + IConnectionPoint** ppConnPt + Pointer to the caller's Connection Point pointer variable. + + Modifies: . + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP tLuaCOMConnPointContainer::FindConnectionPoint( + REFIID riid, + IConnectionPoint** ppConnPt) +{ + HRESULT hr = E_NOINTERFACE; + + // NULL the output variable. + *ppConnPt = NULL; + + //pIConnPt = pBackObj->aConnectionPoints[CONNPOINT_BALLSINK]; + if (NULL != default_connection) + { + IID iid; + default_connection->GetConnectionInterface(&iid); + + if(iid == riid) + { + hr = default_connection->QueryInterface(IID_IConnectionPoint, + (void **)ppConnPt); + } + else + { + hr = CONNECT_E_NOCONNECTION; + } + } + + + return hr; +} + + +/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M + Method: tLuaCOMConnPointContainer::EnumConnectionPoints + + Summary: Return Enumerator for the connectable object's contained + connection points. + + Args: IEnumConnectionPoints** ppIEnum + Pointer to the caller's Enumerator pointer variable. + An output variable that will receive a pointer to the + connection point enumerator COM object. + + Modifies: . + + Returns: HRESULT + Standard result code. NOERROR for success. +M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ +STDMETHODIMP tLuaCOMConnPointContainer::EnumConnectionPoints( + IEnumConnectionPoints** ppIEnum) +{ + HRESULT hr = NOERROR; + IConnectionPoint* aConnPts[MAX_CONNECTION_POINTS]; + tLuaCOMEnumConnPoints* pCOEnum; + + + // Zero the output interface pointer. + *ppIEnum = NULL; + + // Make a copy on the stack of the array of connection point interfaces. + // The copy is used below in the creation of the new Enumerator object. +// for (i=0; iaConnectionPoints[i]; + + // Create a Connection Point enumerator COM object for the connection + // points offered by this COBall object. Pass 'this' to be used to + // hook the lifetime of the host object to the life time of this + // enumerator object. + pCOEnum = new tLuaCOMEnumConnPoints(this); + if (NULL != pCOEnum) + { + // Use the array copy to Init the new Enumerator COM object. + // Set the initial Enumerator index to 0. + hr = pCOEnum->Init(MAX_CONNECTION_POINTS, aConnPts, 0); + if (SUCCEEDED(hr)) + { + // QueryInterface to return the requested interface pointer. + // An AddRef will be conveniently done by the QI. + if (SUCCEEDED(hr)) + hr = pCOEnum->QueryInterface( + IID_IEnumConnectionPoints, + (void **)ppIEnum); + } + } + else + hr = E_OUTOFMEMORY; + + + return hr; +} + + + +tLuaCOMConnPoint* tLuaCOMConnPointContainer::GetDefault() +{ + return default_connection; +} + +void tLuaCOMConnPoint::push() +{ + LUASTACK_SET(L); + + lua_newtable(L); + luaCompat_pushTypeByName(L, MODULENAME, LCOM_CONNPOINT_TYPENAME); + luaCompat_setType(L, -2); + + lua_pushstring(L, CONNPOINT_NAME); + luaCompat_pushPointer(L, this); + + lua_settable(L, -3); + + LUASTACK_CLEAN(L, 1); +} + +int tLuaCOMConnPoint::tagmeth_index(lua_State *L) +{ + // pushes connection point + lua_pushstring(L, CONNPOINT_NAME); + lua_gettable(L, -3); + + // pushes event name + lua_pushvalue(L, 2); + + // pushes closure to call all sinks + lua_pushcclosure(L, call_sinks, 2); + + return 1; +} + + +// lua C function that dispatches events +// to sinks +int tLuaCOMConnPoint::call_sinks(lua_State *L) +{ + /// positions of parameters + + // self param (not used, but needed for ensuring + // consistency + const int self_param = 1; + + // first user param + const int user_first_param = 2; + + // last user param, excluding upvalues + const int user_last_param = luaCompat_getNumParams(L, 2); + + // upvalues + const int connpoint = luaCompat_upvalueIndex(L, 1, 2); + const int event = luaCompat_upvalueIndex(L, 2, 2); + + int num_params = 0; + + if(user_last_param < user_first_param) + num_params = 0; + else + num_params = user_last_param - user_first_param + 1; + + // counter + int i = 0; + + // gets connection point + tLuaCOMConnPoint* cp = + (tLuaCOMConnPoint*) luaCompat_getPointer(L, connpoint); + + // call each sink + for(i = 0; i < (int)cp->cConnections; i++) + { + // pushes function + LuaBeans::push(L, cp->sinks[i]); + cp->sinks[i]->Lock(); + + lua_pushvalue(L, event); + lua_gettable(L, -2); + + // removes table, leaving just function + lua_remove(L, -2); + + // self param (mandatory but unused) + LuaBeans::push(L, cp->sinks[i]); + cp->sinks[i]->Lock(); + + // duplicates parameters (if any) + for(i = user_first_param; i <= user_last_param; i++) + { + lua_pushvalue(L, i); + } + + // calls function (including self param) + // ignoring errors + luaCompat_call(L, num_params+1, 0, NULL); + + // cleans stack + lua_settop(L, user_last_param); + } + + // events do not return nothing + return 0; +} + diff --git a/luacom/tLuaCOMConnPoints.h b/luacom/tLuaCOMConnPoints.h new file mode 100644 index 00000000..13147fac --- /dev/null +++ b/luacom/tLuaCOMConnPoints.h @@ -0,0 +1,284 @@ +#ifndef __LUACOM_CONNECTIONPOINTS_H +#define __LUACOM_CONNECTIONPOINTS_H + +#include "luabeans.h" + +#ifdef __cplusplus + +// An enumeration giving symbol names array indexes of the connection +// points offered by the DllSndBall component in this server. +enum +{ + CONNPOINT_BALLSINK = 0 +}; + +enum +{ + // The maximum number of connection points offered by the DllSndBall + // component in this CONSERVE server. The number of items in the + // connection point enumeration above. + MAX_CONNECTION_POINTS = 1, + + // A constant for the number of connections to add to the allocation + // of the dynamic connection array. + ALLOC_CONNECTIONS = 8, + + // The start value for the connection key (cookie) counter. + COOKIE_START_VALUE = 400 +}; + + +/*O+O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O + ObjectClass: tLuaCOMEnumConnPoints + + Summary: COM object class for enumerating the Connection Points of + offered by a connectable object. + + Interfaces: IUnknown + Standard interface providing COM object features. + IEnumConnectionPoints + Interface for connection point enumeration. + + Aggregation: tLuaCOMEnumConnPoints COM Objects are not aggregatable. +O---O---O---O---O---O---O---O---O---O---O---O---O---O---O---O---O---O---O-O*/ +class tLuaCOMEnumConnPoints : public IEnumConnectionPoints +{ + public: + // Main Object Constructor & Destructor. + tLuaCOMEnumConnPoints(IUnknown* pHostObj); + ~tLuaCOMEnumConnPoints(void); + + // A general method for initializing this newly created object. + // Creates any subordinate arrays, structures, or objects. + HRESULT Init( + ULONG cConnPts, + IConnectionPoint** paConnPts, + ULONG iEnumIndex); + + // IUnknown methods. Main object, non-delegating. + STDMETHODIMP QueryInterface(REFIID, void **); + STDMETHODIMP_(ULONG) AddRef(void); + STDMETHODIMP_(ULONG) Release(void); + + // IEnumConnectionPoints methods. + STDMETHODIMP Next(ULONG, IConnectionPoint**, ULONG*); + STDMETHODIMP Skip(ULONG); + STDMETHODIMP Reset(void); + STDMETHODIMP Clone(IEnumConnectionPoints**); + + private: + // Private data of tLuaCOMEnumConnPoints COM objects. + + // Main Object reference count. + ULONG cRefs; + + // IUnknown pointer to host COM object being enumerated. + IUnknown* pHostObj; + + // Connection Point index variable. + ULONG iEnumIndex; + + // Number of Connection Points being enumerated. + ULONG cConnPts; + + // Allocated array of Connection Point interface pointers. + IConnectionPoint** paConnPts; +}; + +typedef tLuaCOMEnumConnPoints* PtLuaCOMEnumConnPoints; + + +/*O+O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O + ObjectClass: tLuaCOMConnPoint + + Summary: Connection Point COM object class. Implements a native + IConnectionPoint interface. The Advise, Unadvise, and + EnumConnections methods use the CThreaded OwnThis mechanism + to provide thread-safe mutually exclusive access to this + connection point object. + + Interfaces: IUnknown + Standard interface providing COM object features. + IConnectionPoint + Interface for connection point features. + + Aggregation: tLuaCOMConnPoint COM Objects are not aggregatable. +O---O---O---O---O---O---O---O---O---O---O---O---O---O---O---O---O---O---O-O*/ +class tLuaCOMConnPoint : public IConnectionPoint +{ + public: + static int tagmeth_index(lua_State* L); + void push(void); + // Main Object Constructor & Destructor. + tLuaCOMConnPoint(lua_State* L, IUnknown* pHostObj); + ~tLuaCOMConnPoint(void); + + // A general method for initializing this newly created object. + // Creates any subordinate arrays, structures, or objects. + HRESULT Init(REFIID riid, ITypeInfo *typeinfo); + + // IUnknown methods. Main object, non-delegating. + STDMETHODIMP QueryInterface(REFIID, void **); + STDMETHODIMP_(ULONG) AddRef(void); + STDMETHODIMP_(ULONG) Release(void); + + // IConnectionPoint methods. + STDMETHODIMP GetConnectionInterface(IID*); + STDMETHODIMP GetConnectionPointContainer(IConnectionPointContainer**); + STDMETHODIMP Advise(IUnknown*, DWORD*); + STDMETHODIMP Unadvise(DWORD); + STDMETHODIMP EnumConnections(IEnumConnections**); + + private: + // Private utility methods of tLuaCOMConnPoint. + HRESULT GetSlot(UINT* puiFreeSlot); + HRESULT FindSlot(DWORD dwCookie, UINT* puiSlot); + + // Private data of tLuaCOMConnPoint COM objects. + + // Main Object reference count. + ULONG cRefs; + + // IUnknown pointer to host COM object offering this connection point. + IUnknown* pHostObj; + + // The IID of the sink interface associated with this connection point. + IID iidSink; + + // The current connection cookie (key) counter. + DWORD dwNextCookie; + + // The current number of live sink connections to this connection point. + UINT cConnections; + + // The current maximum index into the dynamic connection array. + UINT uiMaxIndex; + + // The dynamic array of sink connections to this connection point. + CONNECTDATA paConnections[ALLOC_CONNECTIONS]; + + // holds LuaCOM objects for each sink + tLuaCOM* sinks[ALLOC_CONNECTIONS]; +protected: + static int call_sinks(lua_State *L); + ITypeInfo* source_typeinfo; + lua_State* L; +}; + +typedef tLuaCOMConnPoint* PtLuaCOMConnPoint; + + +/*O+O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O+++O + ObjectClass: tLuaCOMEnumConnections + + Summary: COM object class for enumerating the connections of + a connection point of a connectable object. + + Interfaces: IUnknown + Standard interface providing COM object features. + IEnumConnections + Interface for connection enumeration features. + + Aggregation: tLuaCOMEnumConnections COM Objects are not aggregatable. +O---O---O---O---O---O---O---O---O---O---O---O---O---O---O---O---O---O---O-O*/ +class tLuaCOMEnumConnections : public IEnumConnections +{ + public: + // Main Object Constructor & Destructor. + tLuaCOMEnumConnections(IUnknown* pHostObj); + ~tLuaCOMEnumConnections(void); + + // A general method for initializing this newly created object. + // Creates any subordinate arrays, structures, or objects. + HRESULT Init( + ULONG cConnections, + CONNECTDATA* paConnections, + ULONG iEnumIndex); + + // IUnknown methods. Main object, non-delegating. + STDMETHODIMP QueryInterface(REFIID, void **); + STDMETHODIMP_(ULONG) AddRef(void); + STDMETHODIMP_(ULONG) Release(void); + + // IEnumConnections methods. + STDMETHODIMP Next(ULONG, CONNECTDATA*, ULONG*); + STDMETHODIMP Skip(ULONG); + STDMETHODIMP Reset(void); + STDMETHODIMP Clone(IEnumConnections**); + + private: + // Private data of tLuaCOMEnumConnections COM objects. + + // Main Object reference count. + ULONG cRefs; + + // IUnknown pointer to host connection point COM object being + // enumerated. + IUnknown* pHostObj; + + // Connection index variable. + ULONG iEnumIndex; + + // Number of Connections being enumerated. + ULONG cConnections; + + // Allocated array of live Connections only. + CONNECTDATA* paConnections; +}; + +typedef tLuaCOMEnumConnections* PtLuaCOMEnumConnections; + + + +class tLuaCOMConnPointContainer : public IConnectionPointContainer +{ + public: + tLuaCOMConnPoint* GetDefault(void); + tLuaCOMConnPointContainer(lua_State *p_L, IUnknown* p_pUnkOuter); + + // Interface Implementation Constructor & Destructor. + ~tLuaCOMConnPointContainer(void); + + // IUnknown methods. + STDMETHODIMP QueryInterface(REFIID, void **); + STDMETHODIMP_(ULONG) AddRef(void); + STDMETHODIMP_(ULONG) Release(void); + + // IConnectionPointContainer methods. + STDMETHODIMP FindConnectionPoint(REFIID, IConnectionPoint**); + STDMETHODIMP EnumConnectionPoints(IEnumConnectionPoints**); + + private: + // Data private to this interface implementation. + IUnknown* pUnkOuter; // Outer unknown for Delegation. +protected: + long num_connection_points; + long max_connection_points; + tLuaCOMConnPoint* default_connection; + tLuaCOMConnPoint** connection_points; + lua_State* L; +}; + + + +#endif // __cplusplus + + +#endif // CONNECT_H + + + + + + + + + + + + + + + + + diff --git a/luacom/tLuaCOMEnumerator.cpp b/luacom/tLuaCOMEnumerator.cpp new file mode 100644 index 00000000..fe3ec637 --- /dev/null +++ b/luacom/tLuaCOMEnumerator.cpp @@ -0,0 +1,273 @@ +// tLuaCOMEnumerator.cpp: implementation of the tLuaCOMEnumerator class. +// +////////////////////////////////////////////////////////////////////// + +#include "tLuaCOMEnumerator.h" + +#include "tUtil.h" +#include "tCOMUtil.h" +#include "tLuaCOMException.h" + +#include "LuaAux.h" + +#include "luacom_internal.h" + +extern "C" +{ +#include "luacompat.h" +} + + + +// initialization + +const char *tLuaCOMEnumerator::type_name = "__ENUMERATOR_LUACOM_TYPE"; +const char *tLuaCOMEnumerator::pointer_type_name = "__ENUMERATOR_POINTER_LUACOM_TYPE"; +const char *tLuaCOMEnumerator::module_name = NULL; + +#define ENUMERATOR_FIELD "__TLUACOMENUMERATOR__internal" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +tLuaCOMEnumerator::tLuaCOMEnumerator(IEnumVARIANT* pEV_param) +{ + CHECKPRECOND(pEV_param); + + // stores enumerator + pEV = pEV_param; + pEV->AddRef(); + + typehandler = new tLuaCOMTypeHandler(NULL); +} + +tLuaCOMEnumerator::~tLuaCOMEnumerator() +{ + COM_RELEASE(pEV); + delete typehandler; +} + +int tLuaCOMEnumerator::index(lua_State *L) +{ + // pushes connection point + lua_pushstring(L, ENUMERATOR_FIELD); + lua_gettable(L, -3); + + // pushes method name + lua_pushvalue(L, 2); + + // pushes closure to call all sinks + lua_pushcclosure(L, call_method, 2); + + return 1; +} + +void tLuaCOMEnumerator::push(lua_State* L) +{ + LUASTACK_SET(L); + + // creates table + lua_newtable(L); + luaCompat_pushTypeByName(L, + tLuaCOMEnumerator::module_name, + tLuaCOMEnumerator::type_name); + + luaCompat_setType(L, -2); + + lua_pushstring(L, ENUMERATOR_FIELD); + + // pushes typed pointer + luaCompat_pushTypeByName(L, + tLuaCOMEnumerator::module_name, + tLuaCOMEnumerator::pointer_type_name); + + luaCompat_newTypedObject(L, this); + + // stores in the table + lua_settable(L, -3); + + LUASTACK_CLEAN(L, 1); +} + +int tLuaCOMEnumerator::garbagecollect(lua_State *L) +{ + LUASTACK_SET(L); + + // gets the enumerator + tLuaCOMEnumerator* enumerator = + (tLuaCOMEnumerator*) luaCompat_getTypedObject(L, -1); + + delete enumerator; + + LUASTACK_CLEAN(L, 0); + + return 0; +} + +void tLuaCOMEnumerator::registerLuaType(lua_State *L, const char *module) +{ + LUASTACK_SET(L); + + tLuaCOMEnumerator::module_name = module; + + luaCompat_newLuaType(L, + tLuaCOMEnumerator::module_name, + tLuaCOMEnumerator::type_name); + + luaCompat_newLuaType(L, + tLuaCOMEnumerator::module_name, + tLuaCOMEnumerator::pointer_type_name); + + luaCompat_pushTypeByName(L, + tLuaCOMEnumerator::module_name, + tLuaCOMEnumerator::type_name); + + lua_pushcfunction(L, tLuaCOMEnumerator::index); + luaCompat_handleNoIndexEvent(L); + + lua_pop(L, 1); + + luaCompat_pushTypeByName(L, + tLuaCOMEnumerator::module_name, + tLuaCOMEnumerator::pointer_type_name); + + lua_pushcfunction(L, tLuaCOMEnumerator::garbagecollect); + luaCompat_handleGCEvent(L); + + lua_pop(L, 1); + + LUASTACK_CLEAN(L, 0); +} + + +int tLuaCOMEnumerator::call_method(lua_State *L) +{ + /// positions of parameters + + // self param (not used, but explicited to ensure + // consistency) + const int self_param = 1; + + // first user param + const int user_first_param = 2; + + // last user param, excluding upvalues + const int user_last_param = luaCompat_getNumParams(L, 2); + + // upvalues + const int enumerator_param = luaCompat_upvalueIndex(L, 1, 2); + const int method_param = luaCompat_upvalueIndex(L, 2, 2); + + int num_params = 0; + + if(user_last_param < user_first_param) + num_params = 0; + else + num_params = user_last_param - user_first_param + 1; + + // gets the enumerator + tLuaCOMEnumerator* enumerator = + (tLuaCOMEnumerator*) luaCompat_getTypedObject(L, enumerator_param); + + // gets the method name + const char* method_name = lua_tostring(L, method_param); + + // call method + int retval = 0; + + try + { + retval = enumerator->callCOMmethod(L, method_name, user_first_param, num_params); + } + catch(class tLuaCOMException& e) + { + luacom_error(L, e.getMessage()); + + return 0; + } + + return retval; +} + +int tLuaCOMEnumerator::callCOMmethod(lua_State* L, const char *name, int first_param, int num_params) +{ + HRESULT hr = S_OK; + + // Next method + if(strcmp(name, "Next") == 0) + { + VARIANT* pVar = NULL; + unsigned long num_elements = 1, counter = 0, fetched = 0; + + + if(num_params > 0) + { + num_elements = (unsigned long) lua_tonumber(L, first_param); + } + + pVar = new VARIANT[num_elements]; + + for(counter = 0; counter < num_elements; counter++) + VariantInit(&pVar[counter]); + + + hr = pEV->Next(num_elements, pVar, &fetched); + + for(counter = 0; counter < fetched; counter++) + { + typehandler->com2lua(L, pVar[counter]); + typehandler->releaseVariant(&pVar[counter]); + } + + for(counter = 0; counter < num_elements; counter++) + VariantClear(&pVar[counter]); + + delete[] pVar; + + pVar = NULL; + + return fetched; + } + + if(strcmp(name, "Reset") == 0) + { + hr = pEV->Reset(); + CHK_LCOM_ERR(hr == S_OK, "Unable to reset enumeration."); + + return 0; + } + + if(strcmp(name, "Skip") == 0) + { + CHK_LCOM_ERR(num_params > 0, "Not enough parameters."); + + unsigned long num_elements = (unsigned long) lua_tonumber(L, first_param); + + hr = pEV->Skip(num_elements); + + luaCompat_pushBool(L, hr == S_OK); + + return 1; + } + + if(strcmp(name, "Clone") == 0) + { + IEnumVARIANT* p_newEV = NULL; + + hr = pEV->Clone(&p_newEV); + CHK_COM_CODE(hr); + + tLuaCOMEnumerator* enumerator = new tLuaCOMEnumerator(p_newEV); + + COM_RELEASE(p_newEV); + + enumerator->push(L); + + return 1; + } + + + + return 0; +} diff --git a/luacom/tLuaCOMEnumerator.h b/luacom/tLuaCOMEnumerator.h new file mode 100644 index 00000000..fa144430 --- /dev/null +++ b/luacom/tLuaCOMEnumerator.h @@ -0,0 +1,42 @@ +// tLuaCOMEnumerator.h: interface for the tLuaCOMEnumerator class. +// +////////////////////////////////////////////////////////////////////// + +#ifndef _TLUACOMENUMERATOR_H +#define _TLUACOMENUMERATOR_H + +#include +#include + +extern "C" +{ +#include "..\lua.h" +} + +#include "tLuaCOMTypeHandler.h" +#include "luabeans.h" + + +class tLuaCOMEnumerator +{ +public: + static void registerLuaType(lua_State* L, const char* module); + void push(lua_State* L); + tLuaCOMEnumerator(IEnumVARIANT* pEV_param); + virtual ~tLuaCOMEnumerator(); + +protected: + int callCOMmethod(lua_State* L, const char* name, int first_param, int last_param); + static int call_method(lua_State* L); + static int garbagecollect(lua_State* L); + static int index(lua_State* L); + + static const char* type_name; + static const char* module_name; + static const char* pointer_type_name; + IEnumVARIANT* pEV; + + tLuaCOMTypeHandler* typehandler; +}; + +#endif // _TLUACOMENUMERATOR_H diff --git a/luacom/tLuaCOMException.cpp b/luacom/tLuaCOMException.cpp new file mode 100644 index 00000000..6b8a1545 --- /dev/null +++ b/luacom/tLuaCOMException.cpp @@ -0,0 +1,76 @@ +// tLuaCOMException.cpp: implementation of the tLuaCOMException class. +// +////////////////////////////////////////////////////////////////////// + +//#include +#include +#include + +#include "tLuaCOMException.h" +#include "tUtil.h" + +char *tLuaCOMException::messages[] = + { + "Internal Error", + "Parameter(s) out of range", + "Type conversion error", + "COM error", + "COM exception", + "Unsupported feature required", + "Windows error", + "LuaCOM error", + "Memory allocation error" + }; + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +tLuaCOMException::tLuaCOMException(Errors p_code, char *p_file, int p_line, + const char *p_usermessage) +{ + code = p_code; + + file = p_file; + line = p_line; + usermessage = p_usermessage; + + tUtil::log("luacom", getMessage()); +} + +tLuaCOMException::~tLuaCOMException() +{ +} + + + +const char * tLuaCOMException::getMessage() +{ + static char string[5000]; + char error_position[1000]; + + + strncpy(string, messages[code], sizeof(string)-1); + + if(file != NULL) + { + sprintf(error_position, ":(%s,%d)", file, line); + strcat(string, error_position); + } + + strncat(string, ":", sizeof(string) - strlen(string) - 1); + + + if(usermessage != NULL) + { + strncat(string, usermessage, sizeof(string) - strlen(string) - 1); + } + + return string; +} + +const char *tLuaCOMException::GetErrorMessage(DWORD errorcode) +{ + return tUtil::GetErrorMessage(errorcode); +} diff --git a/luacom/tLuaCOMException.h b/luacom/tLuaCOMException.h new file mode 100644 index 00000000..a705df0e --- /dev/null +++ b/luacom/tLuaCOMException.h @@ -0,0 +1,86 @@ +// tLuaCOMException.h: interface for the tLuaCOMException class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_TLUACOMEXCEPTION_H__26509908_AFD8_11D4_B882_0000B45D7541__INCLUDED_) +#define AFX_TLUACOMEXCEPTION_H__26509908_AFD8_11D4_B882_0000B45D7541__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#include + +class tLuaCOMException +{ +public: + void getDebugMessage(void); + const char * getMessage(void); + enum Errors {INTERNAL_ERROR, PARAMETER_OUT_OF_RANGE, + TYPECONV_ERROR, COM_ERROR, COM_EXCEPTION, UNSUPPORTED_FEATURE, + WINDOWS_ERROR, LUACOM_ERROR, MALLOC_ERROR + }; + + static const char *GetErrorMessage(DWORD errorcode); + + tLuaCOMException(Errors p_code, char *p_file, int p_line, const char *usermessage = NULL); + virtual ~tLuaCOMException(); + + Errors code; + char *file; + int line; + const char *usermessage; + +protected: + static char *messages[]; +}; + +#define LUACOM_EXCEPTION(x) throw tLuaCOMException(tLuaCOMException::##x, \ + __FILE__, __LINE__) + +#define LUACOM_EXCEPTION_MSG(x,y) throw tLuaCOMException(tLuaCOMException::##x, \ + __FILE__, __LINE__, y) + + +#define CHECK(x,y) ((x) ? (void) 0 : LUACOM_EXCEPTION(y)) + +#define TYPECONV_ERROR(x) throw tLuaCOMException(tLuaCOMException::TYPECONV_ERROR, \ + __FILE__, __LINE__, x) + +#define COM_ERROR(x) throw tLuaCOMException(tLuaCOMException::COM_ERROR, \ +__FILE__, __LINE__, ((x) == NULL ? "Unknown error" : (x))) + +#define COM_EXCEPTION(x) throw tLuaCOMException(tLuaCOMException::COM_EXCEPTION, \ + __FILE__, __LINE__, x) + +#define CHECKPARAM(x) ((x) ? (void) 0 : LUACOM_EXCEPTION(PARAMETER_OUT_OF_RANGE)) + +#define CHECKPARAM_MSG(x,y) ((x) ? (void) 0 : LUACOM_EXCEPTION_MSG( \ + PARAMETER_OUT_OF_RANGE, y)) + +#define CHECKPRECOND(x) ((x) ? (void) 0 : LUACOM_EXCEPTION(INTERNAL_ERROR)) + +#define CHECKPOSCOND(x) CHECKPRECOND(x) + +#define CHECKFEATURE(x, y) ((x) ? (void) 0 : tLuaCOMException( \ + tLuaCOMException::UNSUPPORTED_FEATURE, __FILE__, __LINE__, y)) + +#define INTERNAL_ERROR() LUACOM_EXCEPTION(INTERNAL_ERROR) + +#define WINCHECK(x) ((x) ? (void) 0 : LUACOM_EXCEPTION(WINDOWS_ERROR)) + +#define LUACOM_ERROR(x) (throw tLuaCOMException( \ + tLuaCOMException::LUACOM_ERROR, __FILE__, __LINE__, x)) + +#define CHK_LCOM_ERR(x, y) ((x) ? (void) 0 : LUACOM_ERROR(y)) + +#define CHK_COM_ERR(x, y) (((x) == S_OK) ? (void) 0 : COM_ERROR(y)) + +#define CHKMALLOC(x) ((x) ? (void) 0 : LUACOM_EXCEPTION(MALLOC_ERROR)) + +#define CHK_COM_CODE(hr) CHK_COM_ERR(hr, tLuaCOMException::GetErrorMessage(hr)) + + + + +#endif // !defined(AFX_TLUACOMEXCEPTION_H__26509908_AFD8_11D4_B882_0000B45D7541__INCLUDED_) diff --git a/luacom/tLuaCOMTypeHandler.cpp b/luacom/tLuaCOMTypeHandler.cpp new file mode 100644 index 00000000..9b6c9714 --- /dev/null +++ b/luacom/tLuaCOMTypeHandler.cpp @@ -0,0 +1,2122 @@ +// tLuaCOMTypeHandler.cpp: implementation of the tLuaCOMTypeHandler class. +// +////////////////////////////////////////////////////////////////////// + +// RCS Info +static char *rcsid = "$Id: tLuaCOMTypeHandler.cpp,v 1.39 2005/01/06 18:42:00 fqueiroz Exp $"; +static char *rcsname = "$Name: $"; + +#pragma warning( disable : 4800 4018 ) // never mind those "bool" warnings + +#include +#include + +extern "C" +{ +#include "..\lua.h" +#include "LuaCompat.h" +} + +#include +#include + +#include "tLuaCOMTypeHandler.h" +#include "tLuaCOM.h" +#include "tLuaVector.h" +#include "tLuaCOMException.h" +#include "tLuaDispatch.h" +#include "tCOMUtil.h" + +#include "tLuaCOMEnumerator.h" + +#include "tUtil.h" +#include "LuaAux.h" +#include "luabeans.h" + +#include "luacom_internal.h" + + +#define LUA_NOOBJECT 0 + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +tLuaCOMTypeHandler::tLuaCOMTypeHandler(ITypeInfo *ptypeinfo) +{ + m_typeinfo = ptypeinfo; + + if(m_typeinfo) + m_typeinfo->AddRef(); +} + +tLuaCOMTypeHandler::~tLuaCOMTypeHandler() +{ + COM_RELEASE(m_typeinfo); +} + +void tLuaCOMTypeHandler::pushTableVarNumber(lua_State *L, VARTYPE vt, double val) { + lua_newtable(L); + lua_pushstring(L, "Type"); + switch(vt) { + case VT_CY: + lua_pushstring(L, "currency"); + break; + case VT_UI1: + lua_pushstring(L, "uint1"); + break; + case VT_UI2: + lua_pushstring(L, "uint2"); + break; + case VT_UI4: + lua_pushstring(L, "uint4"); + break; + case VT_INT: + lua_pushstring(L, "int"); + break; + case VT_UINT: + lua_pushstring(L, "uint"); + break; + case VT_I1: + lua_pushstring(L, "int1"); + break; + case VT_I2: + lua_pushstring(L, "int2"); + break; + case VT_I4: + lua_pushstring(L, "int4"); + break; + case VT_R4: + lua_pushstring(L, "float"); + break; + case VT_R8: + lua_pushstring(L, "double"); + break; + case VT_DECIMAL: + lua_pushstring(L, "decimal"); + break; + default: + lua_pushstring(L, "double"); + } + lua_settable(L, -3); + lua_pushstring(L, "Value"); + lua_pushnumber(L, val); + lua_settable(L, -3); +} + +void tLuaCOMTypeHandler::com2lua(lua_State* L, VARIANTARG varg_orig, bool is_variant) +{ + LUASTACK_SET(L); + + HRESULT hr = S_OK; + + VARIANT varg; + VariantInit(&varg); + + lua_pushstring(L,"luacom"); + luaCompat_getglobal(L); + lua_pushstring(L,"TableVariants"); + lua_gettable(L, -2); + bool table_variants = luaCompat_toCBool(L, -1); + lua_pop(L, 2); + + + // dereferences VARIANTARG (if necessary) + hr = VariantCopyInd(&varg, &varg_orig); + + if(FAILED(hr)) + COM_ERROR(tUtil::GetErrorMessage(hr)); + + // Gives a different treatment to SAFEARRAYs + if(varg.vt & VT_ARRAY) + { + // treats an array of VT_UI1 as an array of char and + // converts it to a string + if(varg.vt == (VT_ARRAY | VT_UI1)) + safearray2string(L, varg); + else + safearray_com2lua(L, varg); + } + else + { + + + // used in some type conversions + VARIANTARG new_varg; + VariantInit(&new_varg); + + try + { + switch (varg.vt) + { + case VT_EMPTY: + if(is_variant && table_variants) { + lua_newtable(L); + lua_pushstring(L, "Type"); + lua_pushstring(L, "empty"); + lua_settable(L, -3); + } + else lua_pushnil(L); + break; + case VT_NULL: // SQL's NULL value. + if(is_variant && table_variants) { + lua_newtable(L); + lua_pushstring(L, "Type"); + lua_pushstring(L, "null"); + lua_settable(L, -3); + } + else lua_pushnil(L); + break; + case VT_CY: + case VT_UI1: + case VT_UI2: + case VT_UI4: + case VT_INT: + case VT_UINT: + case VT_I1: + case VT_I2: + case VT_I4: + case VT_R4: + case VT_DECIMAL: + case VT_R8: + { + new_varg.vt = VT_R8; + HRESULT hr = VariantChangeType(&new_varg, &varg, 0, VT_R8); + CHK_COM_CODE(hr); + + if(is_variant && table_variants) + pushTableVarNumber(L, varg.vt, new_varg.dblVal); + else + lua_pushnumber(L, new_varg.dblVal); + break; + } + + case VT_DATE: + { + lua_pushstring(L,"luacom"); + luaCompat_getglobal(L); + lua_pushstring(L,"DateFormat"); + lua_gettable(L, -2); + const char *dateformat = lua_tostring(L, -1); + lua_pop(L, 2); + if(dateformat == NULL || (strcmp("string",dateformat)==0)) { + HRESULT hr = VariantChangeType(&new_varg, &varg, 0, VT_BSTR); + CHK_COM_CODE(hr); + + lua_pushstring(L, (char *) tUtil::bstr2string(new_varg.bstrVal)); + } else if(strcmp("table",dateformat)==0) { + SYSTEMTIME date; + VariantTimeToSystemTime(varg.date,&date); + lua_newtable(L); + lua_pushstring(L, "Day"); + lua_pushnumber(L, date.wDay); + lua_settable(L, -3); + lua_pushstring(L, "DayOfWeek"); + lua_pushnumber(L, date.wDayOfWeek); + lua_settable(L, -3); + lua_pushstring(L, "Month"); + lua_pushnumber(L, date.wMonth); + lua_settable(L, -3); + lua_pushstring(L, "Year"); + lua_pushnumber(L, date.wYear); + lua_settable(L, -3); + lua_pushstring(L, "Hour"); + lua_pushnumber(L, date.wHour); + lua_settable(L, -3); + lua_pushstring(L, "Minute"); + lua_pushnumber(L, date.wMinute); + lua_settable(L, -3); + lua_pushstring(L, "Second"); + lua_pushnumber(L, date.wSecond); + lua_settable(L, -3); + lua_pushstring(L, "Milliseconds"); + lua_pushnumber(L, date.wMilliseconds); + lua_settable(L, -3); + } + + break; + } + + + case VT_ERROR: + // assumes that a parameter has been omitted + if(is_variant && table_variants) { + lua_newtable(L); + lua_pushstring(L, "Type"); + lua_pushstring(L, "error"); + lua_settable(L, -3); + } else + lua_pushnil(L); + break; + + case VT_BOOL: + if(is_variant && table_variants) { + lua_newtable(L); + lua_pushstring(L, "Type"); + lua_pushstring(L, "bool"); + lua_settable(L, -3); + lua_pushstring(L, "Value"); + luaCompat_pushCBool(L, varg.boolVal); + lua_settable(L, -3); + } else + luaCompat_pushCBool(L, varg.boolVal); + break; + + case VT_BSTR: + { + const char* str = tUtil::bstr2string(varg.bstrVal); + if(is_variant && table_variants) { + lua_newtable(L); + lua_pushstring(L, "Type"); + lua_pushstring(L, "bool"); + lua_settable(L, -3); + lua_pushstring(L, "string"); + lua_pushstring(L, (char *) str); + lua_settable(L, -3); + } else + lua_pushstring(L, (char *) str); + + break; + } + + case VT_DISPATCH: + { + unsigned int ninfo = 0; + IDispatch *pdisp = varg.pdispVal; + + if(pdisp == NULL) + { + lua_pushnil(L); + break; + } + + void *pProxMgr; + ILuaDispatch *pLuaDispatch; + if((pdisp->QueryInterface(IID_IProxyManager, &pProxMgr)==E_NOINTERFACE) && + SUCCEEDED(pdisp->QueryInterface(IID_ILuaDispatch, (void**)&pLuaDispatch)) && + SUCCEEDED(pLuaDispatch->PushIfSameState(L))) + break; + + tLuaCOM* lcom = NULL; + + try + { + lcom = tLuaCOM::CreateLuaCOM(L, pdisp); + } + catch(class tLuaCOMException& e) + { + UNUSED(e); + lua_pushnil(L); + break; + } + + LuaBeans::push(L, lcom); + } + break; + + case VT_UNKNOWN: + { + // first, tries to get an IDispatch. If not possible, + // pushes pointer + IUnknown* punk = varg.punkVal; + IDispatch* pdisp = NULL; + + hr = punk->QueryInterface(IID_IDispatch, (void **) &pdisp); + + if(SUCCEEDED(hr)) + { + void *pProxMgr; + ILuaDispatch *pLuaDispatch; + if((pdisp->QueryInterface(IID_IProxyManager, &pProxMgr)==E_NOINTERFACE) && + SUCCEEDED(pdisp->QueryInterface(IID_ILuaDispatch, (void**)&pLuaDispatch)) && + SUCCEEDED(pLuaDispatch->PushIfSameState(L))) + break; + + tLuaCOM* lcom = NULL; + + try + { + lcom = tLuaCOM::CreateLuaCOM(L, pdisp); + } + catch(class tLuaCOMException& e) + { + UNUSED(e); + COM_RELEASE(pdisp); + lua_pushnil(L); + break; + } + + COM_RELEASE(pdisp); + LuaBeans::push(L, lcom); + + break; + + } + + IEnumVARIANT* pEV = NULL; + + hr = punk->QueryInterface(IID_IEnumVARIANT, (void **) &pEV); + + if(SUCCEEDED(hr)) + { + tLuaCOMEnumerator* enumerator = NULL; + + try + { + enumerator = + new tLuaCOMEnumerator(pEV); + } + catch(class tLuaCOMException& e) + { + UNUSED(e); + + COM_RELEASE(pEV); + throw; + } + + COM_RELEASE(pEV); + + enumerator->push(L); + + break; + } + + + // defaults to pushing and userdata for the IUnknown + varg.punkVal->AddRef(); + pushIUnknown(L, varg.punkVal); + + break; + } + + default: + { + static char msg[100]; + + sprintf(msg, "COM->Lua - Type 0x%.2x not implemented.", varg.vt); + + TYPECONV_ERROR(msg); + + break; + } + } + } + catch(class tLuaCOMException& e) + { + UNUSED(e); + VariantClear(&varg); + throw; + } + + VariantClear(&new_varg); + VariantClear(&varg); + } + + LUASTACK_CLEAN(L, 1); +} + +tLuaCOM *tLuaCOMTypeHandler::convert_table(lua_State *L, stkIndex luaval) +{ + tLuaCOM *lcom; + stkIndex table = lua_gettop(L); + lua_pushvalue(L, luaval); + lua_pushstring(L, "typelib"); + lua_gettable(L, table); + if(!lua_isnil(L, -1)) + { + lua_pushstring(L, "luacom"); + luaCompat_getglobal(L); + lua_pushstring(L, "ImplInterfaceFromTypelib"); + lua_gettable(L, -2); + lua_remove(L, -2); + lua_insert(L, table+1); + lua_pushstring(L, "interface"); + lua_gettable(L, table); + lua_pushstring(L, "coclass"); + lua_gettable(L, table); + if(lua_isnil(L, -1)) { + lua_pop(L, 1); + lua_call(L, 3, 1); + } else { + lua_call(L, 4, 1); + } + } + else + { + lua_pop(L, 1); + lua_pushstring(L, "luacom"); + luaCompat_getglobal(L); + lua_pushstring(L, "ImplInterface"); + lua_gettable(L, -2); + lua_remove(L, -2); + lua_insert(L, table+1); + lua_pushstring(L, "progid"); + lua_gettable(L, table); + lua_pushstring(L, "interface"); + lua_gettable(L, table); + lua_call(L, 3, 1); + } + lcom = from_lua(L, lua_gettop(L)); + lua_settop(L, table-1); + return lcom; +} + +void tLuaCOMTypeHandler::lua2com(lua_State* L, stkIndex luaval, VARIANTARG& varg, VARTYPE type) +{ + CHECKPARAM(luaval > 0); + + VariantClear(&varg); + + switch(lua_type(L, luaval)) + { + case LUA_TNUMBER: + varg.dblVal = lua_tonumber(L, luaval); + varg.vt = VT_R8; + + break; + + + case LUA_TSTRING: + { + const char* str = lua_tostring(L, luaval); + long c_len = strlen(str); + long l_len = lua_strlen(L, luaval); + if (c_len == l_len) + { + varg.vt = VT_BSTR; + varg.bstrVal = tUtil::string2bstr(str); + } + else + { + string2safearray(str, l_len, varg); + } + } + + break; + + + case LUA_TTABLE: + { + // tests whether it's a LuaCOM object + tLuaCOM* lcom = from_lua(L, luaval); + + if(lcom) + { + varg.pdispVal = lcom->GetIDispatch(); + + varg.pdispVal->AddRef(); + varg.vt = VT_DISPATCH; + } + else + { + // tests if it is an already created tLuaDispatch + luaCompat_pushPointer(L, idxDispatch); + lua_rawget(L, luaval); + if(!lua_isnil(L, -1)) { + varg.pdispVal = (IDispatch*)luaCompat_getPointer(L, -1); + varg.pdispVal->AddRef(); + varg.vt = VT_DISPATCH; + } else if(luaCompat_checkTagToCom(L, luaval)) { + lua_remove(L, -2); + tLuaCOM* lcom; + switch(lua_type(L, -1)) { + case LUA_TTABLE: + lcom = convert_table(L, luaval); + break; + case LUA_TFUNCTION: + lua_pushvalue(L, luaval); + lua_pushnumber(L, type); + lua_call(L, 2, 1); + lcom = from_lua(L, lua_gettop(L)); + lua_pop(L, 1); + break; + default: + lua_pop(L,1); + TYPECONV_ERROR("Invalid conversion function."); + } + if(!lcom) TYPECONV_ERROR("Conversion function failed."); + varg.pdispVal = lcom->GetIDispatch(); + varg.pdispVal->AddRef(); + varg.vt = VT_DISPATCH; + } else { + lua_pushstring(L, "Type"); + lua_gettable(L, luaval); + if(!lua_isnil(L, -1)) { // Table describes a variant + const char* vtype = lua_tostring(L, -1); + lua_pushstring(L, "Value"); + lua_gettable(L, luaval); + if(strcmp(vtype, "double") == 0) { + varg.vt = VT_R8; + varg.dblVal = lua_tonumber(L, -1); + } else if(strcmp(vtype, "float") == 0) { + varg.vt = VT_R4; + varg.fltVal = (float)lua_tonumber(L, -1); + } else if(strcmp(vtype, "currency") == 0) { + varg.vt = VT_R8; + varg.dblVal = lua_tonumber(L, -1); + VariantChangeType(&varg, &varg, 0, VT_CY); + } else if(strcmp(vtype, "decimal") == 0) { + varg.vt = VT_R8; + varg.dblVal = lua_tonumber(L, -1); + VariantChangeType(&varg, &varg, 0, VT_DECIMAL); +//NJG } else if(strcmp(vtype, "int8") == 0) { +//NJG varg.vt = VT_I8; +//NJG varg.llVal = (LONGLONG)lua_tonumber(L, -1); +//NJG } else if(strcmp(vtype, "uint8") == 0) { +//NJG varg.vt = VT_UI8; +//NJG varg.ullVal = (ULONGLONG)lua_tonumber(L, -1); + } else if(strcmp(vtype, "int4") == 0) { + varg.vt = VT_I4; + varg.lVal = (int)lua_tonumber(L, -1); + } else if(strcmp(vtype, "uint4") == 0) { + varg.vt = VT_UI4; + varg.ulVal = (unsigned int)lua_tonumber(L, -1); + } else if(strcmp(vtype, "int2") == 0) { + varg.vt = VT_I2; + varg.iVal = (short)lua_tonumber(L, -1); + } else if(strcmp(vtype, "uint2") == 0) { + varg.vt = VT_UI2; + varg.uiVal = (unsigned short)lua_tonumber(L, -1); + } else if(strcmp(vtype, "int1") == 0) { + varg.vt = VT_I1; + varg.cVal = (char)lua_tonumber(L, -1); + } else if(strcmp(vtype, "uint1") == 0) { + varg.vt = VT_UI1; + varg.bVal = (unsigned char)lua_tonumber(L, -1); + } else if(strcmp(vtype, "int") == 0) { + varg.vt = VT_INT; + varg.intVal = (int)lua_tonumber(L, -1); + } else if(strcmp(vtype, "uint") == 0) { + varg.vt = VT_UINT; + varg.uintVal = (unsigned int)lua_tonumber(L, -1); + } else if(strcmp(vtype, "string") == 0) { + varg.vt = VT_BSTR; + varg.bstrVal = tUtil::string2bstr(lua_tostring(L, -1)); + } else if(strcmp(vtype, "null") == 0) { + varg.vt = VT_NULL; + } else if(strcmp(vtype, "error") == 0) { + varg.vt = VT_ERROR; + varg.scode = (SCODE)lua_tonumber(L, -1); + } else if(strcmp(vtype, "bool") == 0) { + varg.vt = VT_BOOL; + varg.boolVal = luaCompat_toCBool(L, -1) ? (short)0xFFFF : (short)0; + } else { + varg.vt = VT_EMPTY; + } + } + else { // maybe a date? + int isdate = NULL; + SYSTEMTIME date; + lua_pushstring(L, "Day"); + lua_gettable(L, luaval); + isdate = isdate || !lua_isnil(L, -1); + date.wDay = (WORD)lua_tonumber(L, -1); + lua_pop(L, 1); + lua_pushstring(L, "DayOfWeek"); + lua_gettable(L, luaval); + isdate = isdate || !lua_isnil(L, -1); + date.wDayOfWeek = (WORD)lua_tonumber(L, -1); + lua_pop(L, 1); + lua_pushstring(L, "Month"); + lua_gettable(L, luaval); + isdate = isdate || !lua_isnil(L, -1); + date.wMonth = (WORD)lua_tonumber(L, -1); + lua_pop(L, 1); + lua_pushstring(L, "Year"); + lua_gettable(L, luaval); + isdate = isdate || !lua_isnil(L, -1); + date.wYear = (WORD)lua_tonumber(L, -1); + lua_pop(L, 1); + lua_pushstring(L, "Hour"); + lua_gettable(L, luaval); + isdate = isdate || !lua_isnil(L, -1); + date.wHour = (WORD)lua_tonumber(L, -1); + lua_pop(L, 1); + lua_pushstring(L, "Minute"); + lua_gettable(L, luaval); + isdate = isdate || !lua_isnil(L, -1); + date.wMinute = (WORD)lua_tonumber(L, -1); + lua_pop(L, 1); + lua_pushstring(L, "Second"); + lua_gettable(L, luaval); + isdate = isdate || !lua_isnil(L, -1); + date.wSecond = (WORD)lua_tonumber(L, -1); + lua_pop(L, 1); + lua_pushstring(L, "Milliseconds"); + lua_gettable(L, luaval); + isdate = isdate || !lua_isnil(L, -1); + date.wMilliseconds = (WORD)lua_tonumber(L, -1); + lua_pop(L, 1); + if(isdate) { + varg.vt = VT_DATE; + SystemTimeToVariantTime(&date, &varg.date); + } else safearray_lua2com(L, luaval, varg, VT_VARIANT); + } + } + } + break; + } + + break; + + case LUA_TBOOLEAN: + varg.vt = VT_BOOL; + varg.boolVal = luaCompat_toCBool(L, luaval); + break; + + + case LUA_TUSERDATA: + if(isIUnknown(L, luaval)) // is an IUnknown? + { + varg.vt = VT_UNKNOWN; + varg.punkVal = (IUnknown *) luaCompat_getTypedObject(L, luaval); + varg.punkVal->AddRef(); + } + + break; + + case LUA_TNIL: + varg.vt = VT_EMPTY; + break; + + case LUA_TNONE: + default: + TYPECONV_ERROR("No lua value to convert."); + break; + } +} + +bool tLuaCOMTypeHandler::setRetval(lua_State* L, + const FUNCDESC * funcdesc, + stkIndex luaval, + VARIANTARG * pvarg_retval) +{ + VARIANT varg; + + VariantInit(&varg); + + if(funcdesc->elemdescFunc.tdesc.vt != VT_VOID) + { + lua2com(L, luaval, varg, funcdesc->elemdescFunc.tdesc.vt); + + initByRefParam(pvarg_retval, VT_VARIANT); + toByRefParam(varg, pvarg_retval); + } + else + return false; + + return true; +} + + +int tLuaCOMTypeHandler::pushOutValues(lua_State* L, const DISPPARAMS& dispparams) +{ + unsigned int i = 0; + int num_pushed_values = 0; + + // Procura valor de retorno dos parametros de saida + for(i = 0; i < dispparams.cArgs; i++) + { + VARIANTARG& varg = dispparams.rgvarg[dispparams.cArgs - i - 1]; + + if(varg.vt & VT_BYREF) + { + com2lua(L, varg); + num_pushed_values++; + } + } + + return num_pushed_values; +} + + +void tLuaCOMTypeHandler::releaseVariants(DISPPARAMS *pDispParams) +{ + unsigned int i = 0; + VARIANTARG* &vargs = pDispParams->rgvarg; + + if (vargs != NULL) + { + for (i = 0; i < pDispParams->cArgs; i ++) + { + releaseVariant(&vargs[i]); + } + + delete [] vargs; + + vargs = NULL; + pDispParams->cArgs = 0; + } + +} + + + +// +// Preenche estrutura DISPPARAMS, inicializando parametros +// + +void tLuaCOMTypeHandler::fillDispParams(lua_State* L, + DISPPARAMS& rDispParams, + FUNCDESC * pfuncdesc, + tLuaObjList& params, + int invkind) +{ + // initializes DISPPARAMS + rDispParams.cArgs = 0; + rDispParams.cNamedArgs = 0; + rDispParams.rgvarg = NULL; + rDispParams.rgdispidNamedArgs = NULL; + + // if we know that this function does not received + // parameters, stop here + if (pfuncdesc && pfuncdesc->cParams == 0) + return; + + static DISPID dispidNamed = DISPID_PROPERTYPUT; + + unsigned short i = 0; + stkIndex val = -1; + + // references to simplify code + unsigned int& r_cArgs = rDispParams.cArgs; + VARIANTARG* &r_rgvarg = rDispParams.rgvarg; + + // propertyput particular case + if(invkind == DISPATCH_PROPERTYPUT || + invkind == DISPATCH_PROPERTYPUTREF) + { + rDispParams.cNamedArgs = 1; + rDispParams.rgdispidNamedArgs = &dispidNamed; + } + + r_cArgs = 0; // starts empty + long lua_args = 0; + long max_idl_params = 0; + + + // first attemp to determine the size + // of DISPPARAMS + unsigned int max_params = 0; + + if(pfuncdesc) + max_params = pfuncdesc->cParams; + else + max_params = params.getNumParams(); + + // if this function can receive a variable + // number of arguments, then the last + // formal parameter is a safearray of these + // arguments and must be treated separately. + // Following the documentation, we should pass + // a safearray containing the remaining parameters. + // As this didn't work with MSHTML.HTMLDocument.WriteLn, + // we choose to do the same as VBScript: pass all + // the remaining parameters separately. + // The code to do this the "documented" way + // is commented some lines of code below. + if(pfuncdesc && pfuncdesc->cParamsOpt == -1) + { + assert(max_params >= 1); + + // The maximum number of parameters now is + // bounded by the size of the parameter list, + // if it is larger than the formal parameter + // list + if(params.getNumParams() > pfuncdesc->cParams) + max_params = params.getNumParams(); + else + max_params = pfuncdesc->cParams; + + // We ignore the last parameter (the safearray + // of variants), as we won't use it + max_idl_params = pfuncdesc->cParams - 1; + } + else + max_idl_params = max_params; + + // creates array of VARIANTs + r_rgvarg = new VARIANTARG[max_params]; + + + bool hasdefault = false; + bool byref = false; + bool array = false; + VARTYPE array_type = VT_EMPTY; + VARTYPE type = VT_EMPTY; + + VARIANT var, defaultValue; + + // itera no array lprgelemdescParam procurando pegar + // os parametros da tabela lua + + VariantInit(&defaultValue); + + try + { + for (i = 0; i < max_params; i++) + { + // default values + byref = true; + hasdefault = false; + array = false; + type = VT_VARIANT; + + VariantInit(&r_rgvarg[r_cArgs]); + + // processing that makes sense when there is type info + // available + if(pfuncdesc && i < max_idl_params) + { + PARAMDESC paramdesc = pfuncdesc->lprgelemdescParam[i].paramdesc; + const TYPEDESC tdesc = + processTYPEDESC(m_typeinfo, pfuncdesc->lprgelemdescParam[i].tdesc); + + // stores type of the expected value + type = tdesc.vt & ~VT_BYREF; + + // tests whether an array is expected, + // storing type of array elements if so. + if(tdesc.vt & VT_ARRAY) + { + array = true; + array_type = type & ~VT_ARRAY; + } + + // ignores out parameters + if(!(paramdesc.wParamFlags & PARAMFLAG_FIN) && + (paramdesc.wParamFlags != PARAMFLAG_NONE) && + !(paramdesc.wParamFlags & PARAMFLAG_FOPT)) + { + // If server expects a safearray, creates an + // empty one to avoid problems + if(array) + { + r_rgvarg[r_cArgs].vt = array_type | VT_ARRAY | VT_BYREF; + r_rgvarg[r_cArgs].pparray = + (SAFEARRAY**) CoTaskMemAlloc(sizeof(SAFEARRAY*)); + *r_rgvarg[r_cArgs].pparray = NULL; + } else { + initByRefParam(&r_rgvarg[r_cArgs], type, false); + } + + r_cArgs++; + continue; + } + else if(paramdesc.wParamFlags & PARAMFLAG_FOUT) + { + // assumes that it is an in/out parameter + byref = true; + } + else if(tdesc.vt & VT_BYREF) // tdesc overrides paramflags + byref = true; + else // in param + byref = false; + + // deals with default values (if any) + if(paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) + { + hasdefault = true; + VariantCopy( + &defaultValue, + ¶mdesc.pparamdescex->varDefaultValue); + } + } + + // gets value from lua + val = params.getparam(lua_args); + + // Converts to VARIANT + VariantInit(&var); + + if(val != 0 && lua_type(L, val) != LUA_TNONE && !lua_isnil(L, val)) + { + if(array) + safearray_lua2com(L, val, var, array_type); + else + lua2com(L, val, var, type); + } + else if(hasdefault) + { + VariantCopy(&var, &defaultValue); + VariantClear(&defaultValue); + } + else if(!byref) // here we filter the optional out params (treated below) + { + // assumes that a parameter is expected but has not been found + + var.vt = VT_ERROR; + var.scode = DISP_E_PARAMNOTFOUND; + } + + if(!byref || var.vt == VT_ERROR) + { + VariantCopy(&r_rgvarg[i], &var); + VariantClear(&var); + } + else // here we also process optional out parameters + { + initByRefParam(&r_rgvarg[i], type, true); + toByRefParam(var, &r_rgvarg[i]); + } + + r_cArgs++; + lua_args++; + } + + /* + // deals with vararg functions following + // vararg documentation + if(pfuncdesc && pfuncdesc->cParamsOpt == -1) + { + safearray_lua2com( + params.getparam(lua_args), + r_rgvarg[r_cArgs], + VT_VARIANT, + true); + + r_cArgs++; + } + */ + } + catch(class tLuaCOMException& e) + { + UNUSED(e); + + delete[] r_rgvarg; + r_rgvarg = NULL; + throw; + } + + // inverts parameters order to match + // what is expected by Automation + if(r_cArgs > 0) + { + VARIANTARG temp; + + for(i = 0; i < r_cArgs/2; i++) + { + temp = r_rgvarg[i]; + r_rgvarg[i] = r_rgvarg[r_cArgs - i - 1]; + r_rgvarg[r_cArgs - i - 1] = temp; + } + } + + return; +} + + +void tLuaCOMTypeHandler::pushLuaArgs(lua_State* L, + DISPPARAMS* pDispParams, + const ELEMDESC* pElemDesc) +{ + unsigned int arg = 0; + VARIANT var; + HRESULT hr = S_OK; + unsigned int ArgErr = 0; + + const unsigned int first_named_param = + pDispParams->cArgs - pDispParams->cNamedArgs; + + VariantInit(&var); + + for(arg = 0; arg < pDispParams->cArgs; arg++) + { + const USHORT& wParamFlags = pElemDesc[arg].paramdesc.wParamFlags; + const TYPEDESC tdesc = processTYPEDESC(m_typeinfo, pElemDesc[arg].tdesc); + + // if parameter is not an out param, convert it to Lua + if(wParamFlags & PARAMFLAG_FIN || wParamFlags == PARAMFLAG_NONE ) + { + + // First we have to find the right index in the + // rgvarg array, as we must deal with positional and + // named parameters + + int index = -1; + + if(arg < first_named_param) // still inside positional parameters + index = pDispParams->cArgs - arg - 1; + else // now we are dealing with named parameters + { + // tries to find a named param for the current position + for(unsigned int i = 0; i < pDispParams->cNamedArgs; i++) + { + if(pDispParams->rgdispidNamedArgs[i] == arg) + { + index = i; + break; + } + } + + if(index == -1) // no corresponding named param found + { + lua_pushnil(L); + continue; + } + } + + VARIANTARG& varg = pDispParams->rgvarg[index]; + + // we assume that empty parameters with paramflags NONE + // are out params + if(varg.vt == VT_EMPTY && wParamFlags == PARAMFLAG_NONE) + continue; + + + if(varg.vt == VT_ERROR || varg.vt == VT_EMPTY) + { + // parameter has been omitted + lua_pushnil(L); + continue; + } + + // removes indirections + hr = VariantCopyInd(&var, &varg); + CHK_COM_CODE(hr); + + // some type checks + if((tdesc.vt & ~(VT_BYREF)) != VT_VARIANT && + V_ISARRAY(&tdesc) != V_ISARRAY(&var)) + CHK_COM_CODE(DISP_E_TYPEMISMATCH); + else if(!V_ISARRAY(&var)) + { + // coerces value to the expected scalar type + Coerce(var, var, (tdesc.vt & ~VT_BYREF)); + } + + com2lua(L, var, (tdesc.vt & ~VT_BYREF) == VT_VARIANT); + VariantClear(&var); + } + } +} + +void tLuaCOMTypeHandler::setOutValues(lua_State* L, + FUNCDESC * pFuncDesc, + DISPPARAMS * pDispParams, + stkIndex outvalue + ) +{ + CHECKPRECOND(outvalue > 0); + + const unsigned int num_args = pDispParams->cArgs; + const unsigned int first_named_param = pDispParams->cArgs - pDispParams->cNamedArgs; + unsigned int arg = 0; + + VARIANT var; + VariantInit(&var); + + // Procura valor de retorno dos parametros de saida + for(arg = 0; arg < num_args; arg++) + { + // checks whether there are more return values to map + // to out parameters + if(lua_type(L, outvalue) == LUA_TNONE) + break; + + // alias + const TYPEDESC tdesc = + processTYPEDESC(m_typeinfo, pFuncDesc->lprgelemdescParam[arg].tdesc); + + // tests whether this parameters is an out parameter + if(V_ISBYREF(&tdesc)) + { + // tries to find the right position in the rgvarg array, + // when using named args + unsigned int index = -1; + + if(arg < first_named_param) // still inside positional parameters + index = pDispParams->cArgs - arg - 1; + else // now we are dealing with named parameters + { + // tries to find a named param for the current position + for(unsigned int i = 0; i < pDispParams->cNamedArgs; i++) + { + if(pDispParams->rgdispidNamedArgs[i] == arg) + { + index = i; + break; + } + } + + if(index == -1) + { + // no corresponding named param found, so we must skip + // this one + outvalue++; + continue; + } + } + + // alias + VARIANTARG& varg_orig = pDispParams->rgvarg[index]; + + // Allocates if pure out value + + USHORT paramFlags = pFuncDesc->lprgelemdescParam[arg].paramdesc.wParamFlags; + if(!(paramFlags & PARAMFLAG_FIN) && + (paramFlags != PARAMFLAG_NONE) && + !(paramFlags & PARAMFLAG_FOPT)) + initByRefParam(&varg_orig, tdesc.vt & ~VT_BYREF); + + // does indirection in the case of VARIANTs + if(varg_orig.vt == (VT_VARIANT | VT_BYREF)) + { + VARIANTARG& varg = *varg_orig.pvarVal; + + if(varg.vt & VT_ARRAY) + safearray_lua2com(L, outvalue, var, varg.vt & ~(VT_BYREF | VT_ARRAY)); + else + lua2com(L, outvalue, var, (varg.vt & ~VT_BYREF)); + + if(varg.vt & VT_BYREF) + toByRefParam(var, &varg); + else + VariantCopy(&varg, &var); + } + else + { + VARIANTARG& varg = varg_orig; + + if(varg.vt == VT_ERROR || varg.vt == VT_EMPTY) + initByRefParam(&varg, tdesc.vt & ~VT_BYREF); + + if(varg.vt & VT_ARRAY) + safearray_lua2com(L, outvalue, var, varg.vt & ~(VT_BYREF | VT_ARRAY)); + else + lua2com(L, outvalue, var, (varg.vt & ~VT_BYREF)); + + toByRefParam(var, &varg); + } + + outvalue++; + } + } +} + +// +// Conversao de Safe Arrays para tabelas lua e vice versa +// + +// funcoes auxiliares + +// funcoes auxiliares de safearray_lua2com + + + + +SAFEARRAYBOUND* tLuaCOMTypeHandler::getRightOrderedBounds( + SAFEARRAYBOUND *bounds, + unsigned long num_dimensions) +{ + SAFEARRAYBOUND* new_bounds = new SAFEARRAYBOUND[num_dimensions]; + + unsigned long i = 0; + + for(i = 0; i < num_dimensions; i++) + new_bounds[i] = bounds[num_dimensions - i - 1]; + + return new_bounds; +} + + +void tLuaCOMTypeHandler::put_in_array(SAFEARRAY* safearray, + VARIANT var, + long* indices, + VARTYPE vt + ) +{ + HRESULT hr = S_OK; + VARIANT var_value; + + // converts to the right type + Coerce(var, var, vt); + + // does a copy to avoid problems + VariantInit(&var_value); + VariantCopy(&var_value, &var); + + switch(vt) + { + case VT_I2: + hr = SafeArrayPutElement(safearray, indices, &var_value.iVal); + break; + + case VT_I4: + hr = SafeArrayPutElement(safearray, indices, &var_value.lVal); + break; + + case VT_R4: + hr = SafeArrayPutElement(safearray, indices, &var_value.fltVal); + break; + + case VT_R8: + hr = SafeArrayPutElement(safearray, indices, &var_value.dblVal); + break; + + case VT_CY: + hr = SafeArrayPutElement(safearray, indices, &var_value.cyVal); + break; + + case VT_DATE: + hr = SafeArrayPutElement(safearray, indices, &var_value.date); + break; + + case VT_BSTR: + // BSTR already a pointer + hr = SafeArrayPutElement(safearray, indices, var_value.bstrVal); + break; + + case VT_DISPATCH: + // IDispatch already is a pointer (no indirection need) + hr = SafeArrayPutElement(safearray, indices, var_value.pdispVal); + VariantClear(&var_value); + break; + + case VT_ERROR: + hr = SafeArrayPutElement(safearray, indices, &var_value.scode); + break; + + case VT_BOOL: + hr = SafeArrayPutElement(safearray, indices, &var_value.boolVal); + break; + + case VT_VARIANT: + hr = SafeArrayPutElement(safearray, indices, &var_value); + break; + + case VT_UNKNOWN: + // see IDispatch + hr = SafeArrayPutElement(safearray, indices, var_value.punkVal); + VariantClear(&var_value); + break; + + case VT_DECIMAL: + hr = SafeArrayPutElement(safearray, indices, &var_value.decVal); + break; + + case VT_UI1: + hr = SafeArrayPutElement(safearray, indices, &var_value.bVal); + break; + + case VT_INT: + hr = SafeArrayPutElement(safearray, indices, &var_value.intVal); + break; + + case VT_ARRAY: + TYPECONV_ERROR("SAFEARRAY of SAFEARRAYS not allowed"); + break; + + case VT_I1: + case VT_UI2: + case VT_UI4: + case VT_UINT: + default: + TYPECONV_ERROR("Type not compatible with automation."); + break; + } + + CHK_COM_CODE(hr); +} + +stkIndex tLuaCOMTypeHandler::get_from_array(lua_State* L, + SAFEARRAY* safearray, + long *indices, + const VARTYPE& vt + ) +{ + VARIANTARG varg; + void *pv = NULL; + + + HRESULT hr = S_OK; + + if(vt == VT_VARIANT) + { + pv = &varg; + } + else + { + VariantInit(&varg); + varg.vt = vt; + + // e' uma union, tanto faz de quem pego o ponteiro + pv = (void *) &varg.dblVal; + } + + hr = SafeArrayGetElement(safearray, indices, pv); + + if(FAILED(hr)) + LUACOM_EXCEPTION(INTERNAL_ERROR); + + com2lua(L, varg); + + return lua_gettop(L); +} + + + +void tLuaCOMTypeHandler::inc_indices(long *indices, + SAFEARRAYBOUND *bounds, + unsigned long dimensions + ) +{ + unsigned long j = 0; + + indices[0]++; + j = 0; + + while( + (indices[j] >= (long) bounds[j].cElements + bounds[j].lLbound) && + (j < (dimensions - 1)) + ) + { + indices[j] = bounds[j].lLbound; + indices[j+1]++; + + j++; + } +} + + +// +// Cuida da conversao de tabelas para safe arrays +// + +void tLuaCOMTypeHandler::safearray_lua2com(lua_State* L, + stkIndex luaval, + VARIANTARG& varg, + VARTYPE vt, + bool from_stack) +{ + LUASTACK_SET(L); + + HRESULT hr = S_OK; + + tLuaVector luavector; + + long stack_bottom = lua_gettop(L); + + if(!from_stack) + { + // when trying to convert a string to a safearray + // uses a specific method + if(lua_type(L, luaval) == LUA_TSTRING) + { + string2safearray( + lua_tostring(L, luaval), + lua_strlen(L, luaval), + varg + ); + return; + } + + // creates a luavector based on the table passed + luavector.InitVectorFromTable(L, luaval); + } + else // trying to create an array from the stack + { + luavector.InitVectorFromStack(L, luaval); + } + + long stack_top = lua_gettop(L); + + // Cria variaveis + unsigned long i = 0; + const unsigned long dimensions = luavector.get_Dimensions(); + SAFEARRAYBOUND *bounds = new SAFEARRAYBOUND[dimensions]; + SAFEARRAY *safearray = NULL; + VARIANTARG var_value; + + VariantInit(&var_value); + + + // inicializa dimensoes + for(i = 0; i < dimensions; i++) + { + bounds[i].lLbound = 1; + bounds[i].cElements = + luavector.get_Nth_Dimension(dimensions - i); + } + + + // cria array + safearray = SafeArrayCreate(vt, dimensions, bounds); + + long *indices = NULL; + + try + { + CHECK(safearray, INTERNAL_ERROR); + + // Inicializa indices + indices = new long[dimensions]; + + for(i = 0; i < dimensions; i++) + indices[i] = bounds[i].lLbound; + + // copia elementos um por um + while(indices[dimensions - 1] < + (long) bounds[dimensions - 1].cElements + bounds[dimensions - 1].lLbound) + { + // obtem valor + luaval = luavector.getindex(indices, dimensions, bounds); + + //converte + lua2com(L, luaval, var_value, vt); + + // coloca no array + put_in_array(safearray, var_value, indices, vt); + + // libera + VariantClear(&var_value); + + // incrementa indices + inc_indices(indices, bounds, dimensions); + } + } + catch(class tLuaCOMException&) + { + delete[] bounds; + delete[] indices; + SafeArrayDestroy(safearray); + + while(stack_top > stack_bottom) + { + lua_remove(L, stack_top); + stack_top--; + } + + throw; + } + + + // preenche variantarg + varg.vt = vt | VT_ARRAY; + varg.parray = safearray; + + + // libera memoria + delete[] bounds; + delete[] indices; + + while(stack_top > stack_bottom) + { + lua_remove(L, stack_top); + stack_top--; + } + + LUASTACK_CLEAN(L, 0); + + return; +} + +void tLuaCOMTypeHandler::string2safearray(const char* str, long len, VARIANTARG& varg) +{ + HRESULT hr = S_OK; + + // cria array + SAFEARRAY *safearray = SafeArrayCreateVector(VT_UI1, 0, len); + CHECK(safearray, INTERNAL_ERROR); + + void * buffer = NULL; + hr = SafeArrayAccessData(safearray,&buffer); + if(FAILED(hr)) + LUACOM_EXCEPTION(INTERNAL_ERROR); + if (buffer != NULL) + memcpy(buffer,str,len); + SafeArrayUnaccessData(safearray); + + // preenche variantarg + varg.vt = VT_UI1 | VT_ARRAY; + varg.parray = safearray; +} + +void tLuaCOMTypeHandler::safearray2string(lua_State* L, VARIANTARG & varg) +{ + CHECKPRECOND(varg.vt & (VT_ARRAY | VT_UI1)); + CHECKPRECOND(varg.parray->cDims == 1); + + HRESULT hr = S_OK; + void * buffer = NULL; + + long size = varg.parray->rgsabound[0].cElements; + + hr = SafeArrayAccessData(varg.parray, &buffer); + CHK_COM_CODE(hr); + + lua_pushlstring(L, (char*) buffer, size); + + SafeArrayUnaccessData(varg.parray); +} + + +long * tLuaCOMTypeHandler::dimensionsFromBounds(SAFEARRAYBOUND* bounds, + long num_bounds + ) +{ + int i = 0; + long *dimensions = new long[num_bounds]; + + for(i = 0; i < num_bounds; i++) + { + dimensions[i] = + bounds[num_bounds - i - 1].cElements; + } + + return dimensions; +} + + + +void tLuaCOMTypeHandler::safearray_com2lua(lua_State* L, VARIANTARG & varg) +{ + + CHECK(varg.vt & VT_ARRAY, PARAMETER_OUT_OF_RANGE); + + bool succeeded = false; + long *indices = NULL; + SAFEARRAYBOUND* bounds = NULL; + + try + { + SAFEARRAY* safearray = varg.parray; + + // pega dimensoes + const int num_dimensions = SafeArrayGetDim(safearray); + + bounds = getRightOrderedBounds + ( + safearray->rgsabound, + num_dimensions + ); + + + // cria objeto LuaVector + tLuaVector luavector; + + { + long *dimensions = dimensionsFromBounds(bounds, num_dimensions); + + try + { + luavector.InitVectorFromDimensions(dimensions, num_dimensions); + } + catch(class tLuaCOMException&) + { + delete[] dimensions; + throw; + } + + delete[] dimensions; + } + + // initializes indices + indices = new long[num_dimensions]; + + int i = 0; + for(i = 0; i < num_dimensions; i++) + indices[i] = bounds[i].lLbound; + + // gets array data type + VARTYPE vt = varg.vt & ~VT_ARRAY; + + // holds index to lua objects + stkIndex luaval = 0; + + // saves current stack position + stkIndex stacktop = lua_gettop(L); + + // allocates enough stack room + luaCompat_needStack(L, luavector.size()*2); + + // copia elementos um por um + while(indices[num_dimensions-1] < + (long) + (bounds[num_dimensions-1].cElements + + bounds[num_dimensions-1].lLbound + ) + ) + { + // pega do array + luaval = get_from_array(L, safearray, indices, vt); + + // seta no luavector + luavector.setindex(L, luaval, indices, num_dimensions, bounds); + + // incrementa indices + inc_indices(indices, bounds, num_dimensions); + } + + // tries to create lua table on the top of stack + succeeded = luavector.CreateTable(L); + + // remove temporary objects + stkIndex clean_until = lua_gettop(L); + + if(succeeded) + clean_until--; // doesn't clean created table! + + while(clean_until > stacktop) + { + lua_remove(L, clean_until); + clean_until--; + } + } + catch(class tLuaCOMException&) + { + delete[] bounds; + delete[] indices; + throw; + } + + delete[] bounds; + delete[] indices; + + return; +} + + +tLuaCOM * tLuaCOMTypeHandler::from_lua(lua_State* L, int index) +{ + return (tLuaCOM *) LuaBeans::from_lua(L, index); +} + +TYPEDESC tLuaCOMTypeHandler::processPTR(ITypeInfo* typeinfo, + const TYPEDESC &tdesc) +{ + CHECKPRECOND(tdesc.vt == VT_PTR); + + TYPEDESC pointed_at; + + // continues indirection + pointed_at.vt = tdesc.lptdesc->vt; + pointed_at.lptdesc = tdesc.lptdesc->lptdesc; + + // removes aliases + pointed_at = processAliases(typeinfo, pointed_at); + + // if the referenced type is userdefined, gets its + // definition + bool userdef = false; + + if(pointed_at.vt == VT_USERDEFINED) + { + userdef = true; + pointed_at = processUSERDEFINED(typeinfo, pointed_at); + } + + if(userdef == true && + (pointed_at.vt == VT_DISPATCH || pointed_at.vt == VT_UNKNOWN)) + { + // does nothing, because it's a VT_USERDEFINED TYPEDESC that + // describes an interface that inherits from IDispatch. + // Pointers (that is, single indirection) to IDispatch + // are always VT_DISPATCH. + } + else if(pointed_at.vt == VT_PTR) + { + // continues indirection + pointed_at = processPTR(typeinfo, pointed_at); + + // We arrive here if the TYPEDESC describes a + // pointer to a pointer. This only happens + // when we are refencing interfaces. Since + // interfaces are always refenced as pointers, + // it looks like a single indirection + + pointed_at.vt |= VT_BYREF; + } + else if(pointed_at.vt == VT_SAFEARRAY) + { + pointed_at = processSAFEARRAY(typeinfo, pointed_at); + pointed_at.vt |= VT_BYREF; + } + else // other types under a VT_PTR are just BYREF + { + pointed_at.vt |= VT_BYREF; + } + + return pointed_at; +} + +TYPEDESC tLuaCOMTypeHandler::processUSERDEFINED(ITypeInfo* typeinfo, + const TYPEDESC &tdesc) +{ + HRESULT hr = S_OK; + ITypeInfo *userdef = NULL; + TYPEATTR *typeattr = NULL; + TYPEDESC newtdesc; + + newtdesc.vt = 0; + + hr = typeinfo->GetRefTypeInfo(tdesc.hreftype, &userdef); + + if(FAILED(hr)) + TYPECONV_ERROR("Could not understand user-defined type"); + + hr = userdef->GetTypeAttr(&typeattr); + + if(FAILED(hr)) + { + userdef->Release(); + TYPECONV_ERROR("Could not understand user-defined type"); + } + + switch(typeattr->typekind) + { + case TKIND_ENUM: + newtdesc.vt = VT_INT; + break; + + case TKIND_DISPATCH: + newtdesc.vt = VT_DISPATCH; + break; + + case TKIND_ALIAS: + // shouldn't arrive here: aliases must be removed via + // processAliases() + INTERNAL_ERROR(); + break; + + case TKIND_INTERFACE: + newtdesc.vt = VT_UNKNOWN; + break; + + case TKIND_UNION: + TYPECONV_ERROR("Union type not supported!"); + break; + + case TKIND_COCLASS: + newtdesc.vt = VT_UNKNOWN; + break; + + case TKIND_RECORD: + TYPECONV_ERROR("Record type not supported!"); + break; + + case TKIND_MODULE: + case TKIND_MAX: + TYPECONV_ERROR("TKIND_MODULE and TKIND_MAX not supported!"); + break; + + default: + TYPECONV_ERROR("Unknown TYPEKIND on VT_USERDEFINED TYPEDESC"); + break; + } + + userdef->ReleaseTypeAttr(typeattr); + userdef->Release(); + + return newtdesc; +} + +// +// Clears a VARIANT, releasing first the memory allocated + +void tLuaCOMTypeHandler::releaseVariant(VARIANTARG *pvarg, bool release_memory) +{ + if(pvarg->vt & VT_BYREF && pvarg->byref != NULL) + { + switch(pvarg->vt & ~VT_BYREF) + { + case VT_BSTR: + SysFreeString(*pvarg->pbstrVal); + break; + + case VT_DISPATCH: + COM_RELEASE(*pvarg->ppdispVal); + break; + + case VT_UNKNOWN: + COM_RELEASE(*pvarg->ppunkVal); + break; + + case VT_VARIANT: + // a variant cannot contain another BYREF + // so we just clear with VariantClear + VariantClear(pvarg->pvarVal); + break; + + } + + if(pvarg->vt & VT_ARRAY && *pvarg->pparray) + SafeArrayDestroy(*pvarg->pparray); + + if(release_memory) + { + CoTaskMemFree(pvarg->byref); + //char *p = (char*)pvarg->byref; + //delete [] p; + VariantClear(pvarg); + //pvarg->byref = NULL; + //pvarg->vt = VT_EMPTY; + } + } + else + VariantClear(pvarg); + +} + + +// Dereferences typedef's in type descriptions + +TYPEDESC tLuaCOMTypeHandler::processAliases(ITypeInfo* typeinfo, + const TYPEDESC &tdesc) +{ + // if it's not a userdefined type, does nothing + if(tdesc.vt != VT_USERDEFINED) + return tdesc; + + HRESULT hr = S_OK; + ITypeInfo *userdef = NULL; + TYPEATTR *typeattr = NULL; + TYPEDESC newtdesc; + + newtdesc.vt = 0; + + hr = typeinfo->GetRefTypeInfo(tdesc.hreftype, &userdef); + + if(FAILED(hr)) + TYPECONV_ERROR("Could not understand user-defined type"); + + hr = userdef->GetTypeAttr(&typeattr); + + if(FAILED(hr)) + { + userdef->Release(); + TYPECONV_ERROR("Could not understand user-defined type"); + } + + if(typeattr->typekind == TKIND_ALIAS) + { + newtdesc = typeattr->tdescAlias; + newtdesc = processAliases(typeinfo, newtdesc); + } + else + newtdesc = tdesc; + + userdef->ReleaseTypeAttr(typeattr); + userdef->Release(); + + return newtdesc; +} + +TYPEDESC tLuaCOMTypeHandler::processTYPEDESC(ITypeInfo* typeinfo, + TYPEDESC tdesc) +{ + // removes aliases + tdesc = processAliases(typeinfo, tdesc); + + bool done = false; + + switch(tdesc.vt) + { + case VT_USERDEFINED: + tdesc = processUSERDEFINED(typeinfo, tdesc); + break; + + case VT_PTR: + tdesc = processPTR(typeinfo, tdesc); + break; + + case VT_SAFEARRAY: + tdesc = processSAFEARRAY(typeinfo, tdesc); + } + + CHECKPOSCOND(tdesc.vt != VT_USERDEFINED && tdesc.vt != VT_PTR); + + return tdesc; +} + + +/* + * IsIUnknown + * + * checks whether the lua value is of tag LuaCOM_IUnknown + */ + +bool tLuaCOMTypeHandler::isIUnknown(lua_State* L, stkIndex value) +{ + lua_pushvalue(L, value); + + bool result = luaCompat_isOfType(L, MODULENAME, LCOM_IUNKNOWN_TYPENAME); + + lua_pop(L, 1); + + return result; +} + + +void tLuaCOMTypeHandler::pushIUnknown(lua_State* L, IUnknown *punk) +{ + luaCompat_pushTypeByName(L, MODULENAME, LCOM_IUNKNOWN_TYPENAME); + luaCompat_newTypedObject(L, punk); +} + + +void tLuaCOMTypeHandler::initByRefParam(VARIANTARG* pvarg, VARTYPE vt, bool alloc_memory) +{ + CHECKPRECOND(!(vt & VT_BYREF)); + VariantClear(pvarg); + + pvarg->vt = vt | VT_BYREF; + + if(alloc_memory) { + const long size = VariantSize(vt); + + pvarg->byref = (void *) CoTaskMemAlloc(size); + + //pvarg->byref = (void *) new char[size]; + + // Initializes the allocated memory + if(vt == VT_VARIANT) + VariantInit(pvarg->pvarVal); + else + memset(pvarg->byref, 0, size); + } else { + pvarg->byref = NULL; + } +} + +void tLuaCOMTypeHandler::toByRefParam(VARIANT &var_source, VARIANTARG* pvarg_dest) +{ + CHECKPARAM(pvarg_dest); + CHECKPRECOND(!(var_source.vt & VT_BYREF)); + + // if a VARIANT ByRef is expected, just copies the value + // to the ByRef VARIANT + if(pvarg_dest->vt == (VT_VARIANT | VT_BYREF)) + { + // we do a hard copy, to avoid increasing the reference count + // objects by the use of VariantCopy + memcpy(pvarg_dest->pvarVal, &var_source, sizeof(VARIANT)); + return; + } + + VARTYPE vt_dest = pvarg_dest->vt & ~VT_BYREF; + + // Tries to convert the value to the type expected in varg_dest + if(!(vt_dest & VT_ARRAY)) + { + HRESULT hr = + VariantChangeType(&var_source, &var_source, 0, vt_dest); + + CHK_COM_CODE(hr); + } + + // Clears the old contents + releaseVariant(pvarg_dest, false); + + pvarg_dest->vt = vt_dest | VT_BYREF; + + // Does a hard copy of the memory contents, + + memcpy(pvarg_dest->byref, &var_source.byref, VariantSize(vt_dest)); +} + +TYPEDESC tLuaCOMTypeHandler::processSAFEARRAY(ITypeInfo* typeinfo, + TYPEDESC &tdesc) +{ + CHECKPRECOND(tdesc.vt == VT_SAFEARRAY); + + TYPEDESC pointed_at; + + // continues indirection + pointed_at = *tdesc.lptdesc; + pointed_at = processTYPEDESC(typeinfo, pointed_at); + + pointed_at.vt |= VT_ARRAY; + + return pointed_at; +} + + +// Returns the memory size of data that can +// be stored in a VARIANT +long tLuaCOMTypeHandler::VariantSize(VARTYPE vt) +{ + if(vt & VT_ARRAY) + { + return sizeof(SAFEARRAY *); + } + + switch(vt) + { + case VT_I2: + return 2; + + case VT_I4: + return 4; + + case VT_R4: + return 4; + + case VT_R8: + return 8; + + case VT_CY: + return sizeof(CURRENCY); + + case VT_DATE: + return sizeof(DATE); + + case VT_BSTR: + return sizeof(BSTR); + + case VT_DISPATCH: + return sizeof(IDispatch*); + + case VT_ERROR: + return sizeof(SCODE); + + case VT_BOOL: + return sizeof(VARIANT_BOOL); + + case VT_VARIANT: + return sizeof(VARIANT); + + case VT_UNKNOWN: + return sizeof(IUnknown*); + + case VT_DECIMAL: + return 16; + + case VT_UI1: + case VT_I1: + return 1; + + case VT_UI2: + return 2; + + case VT_UI4: + return 4; + + case VT_INT: + return sizeof(int); + + case VT_UINT: + return sizeof(unsigned int); + + default: + TYPECONV_ERROR("Unknown type"); + } +} + +// +// Type conversion function +// +void tLuaCOMTypeHandler::Coerce(VARIANTARG &dest, VARIANTARG src, VARTYPE vt) +{ + HRESULT hr = S_OK; + + if(vt == VT_VARIANT) + { + // do nothing. We already have a VARIANT + return; + } + + hr = VariantChangeType(&dest, &src, 0, vt); + CHK_COM_CODE(hr); + +} diff --git a/luacom/tLuaCOMTypeHandler.h b/luacom/tLuaCOMTypeHandler.h new file mode 100644 index 00000000..4562d61f --- /dev/null +++ b/luacom/tLuaCOMTypeHandler.h @@ -0,0 +1,124 @@ + +// tLuaCOMTypeHandler.h: interface for the tLuaCOMTypeHandler class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_TLUACOMTYPEHANDLER_H__2CAF122C_E09B_11D3_BD2F_444553540000__INCLUDED_) +#define AFX_TLUACOMTYPEHANDLER_H__2CAF122C_E09B_11D3_BD2F_444553540000__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#include + +#include "luabeans.h" +#include "tLuaObjList.h" +#include "LuaAux.h" + +class tLuaCOM; + +class tLuaCOMTypeHandler +{ +public: + void setOutValues( + lua_State* L, + FUNCDESC* pFuncDesc, + DISPPARAMS* pDispParams, + stkIndex outvalue); + + void pushLuaArgs( + lua_State* L, + DISPPARAMS* pDispParams, + const ELEMDESC* pElemDesc + ); + + void fillDispParams( + lua_State* L, + DISPPARAMS& rDispParams, + FUNCDESC *pfuncdesc, + tLuaObjList& params, + int invkind + ); + + void releaseVariants(DISPPARAMS *pDispParams); + + void releaseVariant(VARIANTARG *pvarg, bool release_memory=true); + + void pushTableVarNumber(lua_State *L, VARTYPE vt, double val); + + int pushOutValues(lua_State* L, const DISPPARAMS& dispparams); + + bool setRetval( + lua_State* L, + const FUNCDESC *funcdesc, + stkIndex luaval, + VARIANTARG *pvarg); + + void lua2com(lua_State* L, stkIndex luaval, VARIANTARG& varg, VARTYPE type=VT_VARIANT); + + void com2lua(lua_State* L, VARIANTARG varg, bool is_variant = false); + tLuaCOMTypeHandler(ITypeInfo *ptypeinfo); + virtual ~tLuaCOMTypeHandler(); + + static TYPEDESC processTYPEDESC( + ITypeInfo* typeinfo, + TYPEDESC tdesc); + +protected: + long * dimensionsFromBounds(SAFEARRAYBOUND* bounds, long num_bounds); + void put_in_array(SAFEARRAY* safearray, + VARIANT var_value, + long* indices, + VARTYPE vt); + + void inc_indices(long *indices, + SAFEARRAYBOUND *bounds, + unsigned long dimensions); + + SAFEARRAYBOUND* getRightOrderedBounds(SAFEARRAYBOUND *bounds, + unsigned long num_dimensions); + + void Coerce(VARIANTARG& dest, VARIANTARG src, VARTYPE vt); + long VariantSize(VARTYPE vt); + static TYPEDESC processSAFEARRAY(ITypeInfo* typeinfo, TYPEDESC& tdesc); + void toByRefParam(VARIANT& var_source, VARIANTARG * pvarg_dest); + void initByRefParam(VARIANTARG* pvarg, VARTYPE vt, bool alloc_memory = true); + void pushIUnknown(lua_State* L, IUnknown *punk); + bool isIUnknown(lua_State* L, stkIndex value); + static TYPEDESC processAliases( + ITypeInfo* typeinfo, + const TYPEDESC& tdesc); + static TYPEDESC processUSERDEFINED( + ITypeInfo* typeinfo, + const TYPEDESC& tdesc); + static TYPEDESC processPTR( + ITypeInfo* typeinfo, + const TYPEDESC& tdesc); + + tLuaCOM * from_lua(lua_State* L, int index); + tLuaCOM * convert_table(lua_State *L, stkIndex luaval); + stkIndex get_from_array( + lua_State* L, + SAFEARRAY* safearray, + long *indices, + const VARTYPE& vt); + + void safearray_com2lua(lua_State* L, VARIANTARG& varg); + + void safearray_lua2com( + lua_State* L, + stkIndex luaval, + VARIANTARG& varg, VARTYPE vt, + bool from_stack = false + ); + + void string2safearray(const char* str, long len, VARIANTARG& varg); + void safearray2string(lua_State* L, VARIANTARG & varg); + + ITypeInfo * m_typeinfo; +}; + +#define LUACOM_IUNKNOWN_TAGNAME "_LuaCOM_IUnknown_tag" + +#endif // !defined(AFX_TLUACOMTYPEHANDLER_H__2CAF122C_E09B_11D3_BD2F_444553540000__INCLUDED_) diff --git a/luacom/tLuaControl.cpp b/luacom/tLuaControl.cpp new file mode 100644 index 00000000..64e97bd1 --- /dev/null +++ b/luacom/tLuaControl.cpp @@ -0,0 +1,2224 @@ +/* + * tLuaControl.cpp + * + */ + +#include +#include +#include + +extern "C" +{ +#include "..\lua.h" +#include "..\lauxlib.h" +#include "LuaCompat.h" +} + +#include "luacom_internal.h" +#include "tLuaDispatch.h" +#include "tLuaControl.h" + +#pragma warning(disable: 4244 4101) + +const float HIMETRIC_PER_PIXEL(26.4583333333f); + +const OLEVERB verbs[] = { + { OLEIVERB_SHOW, 0, 0, 0}, + { OLEIVERB_HIDE, 0, 0, 0}, + { OLEIVERB_INPLACEACTIVATE, 0, 0, 0}, + { OLEIVERB_PRIMARY, 0, 0, 0}, + { OLEIVERB_UIACTIVATE, 0, 0, 0} +}; + +#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ + const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} + +#define ASSERT(fTest, szMsg) \ + if (!(fTest)) { \ + static char szMsgCode[] = szMsg; \ + static char szAssert[] = #fTest; \ + DisplayAssert(szMsgCode, szAssert, __FILE__, __LINE__); \ + } + +#define FAIL(szMsg) \ + { static char szMsgCode[] = szMsg; \ + DisplayAssert(szMsgCode, "FAIL", __FILE__, __LINE__); } + +// macro that checks a pointer for validity on input +// +#define CHECK_POINTER(val) if (!(val) || IsBadWritePtr((void *)(val), sizeof(void *))) return E_POINTER + +#define RELEASE_OBJECT(ptr) if (ptr) { IUnknown *pUnk = (ptr); (ptr) = NULL; pUnk->Release(); } +#define QUICK_RELEASE(ptr) if (ptr) ((IUnknown *)ptr)->Release(); +#define ADDREF_OBJECT(ptr) if (ptr) (ptr)->AddRef() + +#define RETURN_ON_FAILURE(hr) if (FAILED(hr)) return hr +#define CLEANUP_ON_FAILURE(hr) if (FAILED(hr)) goto CleanUp + +MIDL_DEFINE_GUID(CLSID, CLSID_Teste,0x687362C8,0x00D6,0x4eff,0x92,0x07,0xDD,0xB2,0x2E,0xE2,0x30,0x6D); + +//=--------------------------------------------------------------------------= +// Private Constants +//---------------------------------------------------------------------------= +// +static const char szFormat[] = "%s\nFile %s, Line %d"; +static const char szFormat2[] = "%s\n%s\nFile %s, Line %d"; + +#define _SERVERNAME_ "ActiveX Framework" + +static const char szTitle[] = _SERVERNAME_ " Assertion (Abort = UAE, Retry = INT 3, Ignore = Continue)"; + +//=--------------------------------------------------------------------------= +// Local functions +//=--------------------------------------------------------------------------= +int NEAR _IdMsgBox(LPSTR pszText, LPCSTR pszTitle, UINT mbFlags); + +//=--------------------------------------------------------------------------= +// DisplayAssert +//=--------------------------------------------------------------------------= +// Display an assert message box with the given pszMsg, pszAssert, source +// file name, and line number. The resulting message box has Abort, Retry, +// Ignore buttons with Abort as the default. Abort does a FatalAppExit; +// Retry does an int 3 then returns; Ignore just returns. +// +VOID DisplayAssert +( + LPSTR pszMsg, + LPSTR pszAssert, + LPSTR pszFile, + UINT line +) +{ + char szMsg[250]; + LPSTR lpszText; + + lpszText = pszMsg; // Assume no file & line # info + + // If C file assert, where you've got a file name and a line # + // + if (pszFile) { + + // Then format the assert nicely + // + wsprintf(szMsg, szFormat, (pszMsg&&*pszMsg) ? pszMsg : pszAssert, pszFile, line); + lpszText = szMsg; + } + + // Put up a dialog box + // + switch (_IdMsgBox(lpszText, szTitle, MB_ICONHAND|MB_ABORTRETRYIGNORE|MB_SYSTEMMODAL)) { + case IDABORT: + FatalAppExit(0, lpszText); + return; + + case IDRETRY: + // call the win32 api to break us. + // + DebugBreak(); + return; + } + + return; +} + + +//=---------------------------------------------------------------------------= +// Beefed-up version of WinMessageBox. +//=---------------------------------------------------------------------------= +// +int NEAR _IdMsgBox +( + LPSTR pszText, + LPCSTR pszTitle, + UINT mbFlags +) +{ + HWND hwndActive; + int id; + + hwndActive = GetActiveWindow(); + + id = MessageBox(hwndActive, pszText, pszTitle, mbFlags); + + return id; +} + +void PixelToHimetric(const SIZEL* pixelSize, SIZEL* himetricSize) { + SIZEL ret; + ret.cx = static_cast(pixelSize->cx * HIMETRIC_PER_PIXEL + 0.5); + ret.cy = static_cast(pixelSize->cy * HIMETRIC_PER_PIXEL + 0.5); + *himetricSize = ret; +} + +void HimetricToPixel(const SIZEL* himetricSize, SIZEL* pixelSize) { + SIZEL ret; + ret.cx = static_cast(himetricSize->cx / HIMETRIC_PER_PIXEL + 0.5); + ret.cy = static_cast(himetricSize->cy / HIMETRIC_PER_PIXEL + 0.5); + *pixelSize = ret; +} + +//=--------------------------------------------------------------------------= +// GetParkingWindow +//=--------------------------------------------------------------------------= +// creates the global parking window that we'll use to parent things, or +// returns the already existing one +// +// Output: +// HWND - our parking window +// +// Notes: +// +HWND GetParkingWindow(void) +{ + WNDCLASS wndclass; + + // crit sect this creation for apartment threading support. + // + if (g_hwndParking) + goto CleanUp; + + ZeroMemory(&wndclass, sizeof(wndclass)); + wndclass.lpfnWndProc = DefWindowProc; + wndclass.hInstance = g_hInstance; + wndclass.lpszClassName = "CtlFrameWork_Parking"; + + if (!RegisterClass(&wndclass)) { + FAIL("Couldn't Register Parking Window Class!"); + goto CleanUp; + } + + g_hwndParking = CreateWindow("CtlFrameWork_Parking", NULL, WS_POPUP, 0, 0, 0, 0, NULL, NULL, g_hInstance, NULL); + + ASSERT(g_hwndParking, "Couldn't Create Global parking window!!"); + + + CleanUp: + return g_hwndParking; +} + +tLuaControl::tLuaControl(lua_State* L, ITypeInfo *pTypeinfo, int ref) : tLuaDispatch(L, pTypeinfo, ref) { + // initialize all our variables -- we decided against using a memory-zeroing + // memory allocator, so we sort of have to do this work now ... + // + m_pClientSite = NULL; + m_pControlSite = NULL; + m_pInPlaceSite = NULL; + m_pInPlaceFrame = NULL; + m_pInPlaceUIWindow = NULL; + + // certain hosts don't like 0,0 as your initial size, so we're going to set + // our initial size to 100,50 [so it's at least sort of visible on the screen] + // + lua_getref(L, table_ref); + lua_pushstring(L, "InitialSize"); + lua_gettable(L, -2); + lua_pushvalue(L, -2); + lua_remove(L, -3); + const char * err; + if(!luaCompat_call(L, 1, 2, &err)) { + m_Size.cx = lua_tonumber(L,-2); + m_Size.cy = lua_tonumber(L,-1); + } else { + m_Size.cx = 50; + m_Size.cy = 20; + } + memset(&m_rcLocation, 0, sizeof(m_rcLocation)); + + m_hRgn = NULL; + m_hwnd = NULL; + m_hwndParent = NULL; + + m_pSimpleFrameSite = NULL; + m_pOleAdviseHolder = NULL; + m_pViewAdviseSink = NULL; + m_pDispAmbient = NULL; + + m_fDirty = FALSE; + m_fInPlaceActive = FALSE; + m_fInPlaceVisible = FALSE; + m_fUIActive = FALSE; +} + +tLuaControl::~tLuaControl() { + // if we've still got a window, go and kill it now. + // + if (m_hwnd) { + // so our window proc doesn't crash. + // + DestroyWindow(); + } + + if (m_hRgn != NULL) + { + DeleteObject(m_hRgn); + m_hRgn = NULL; + } + + // clean up all the pointers we're holding around. + // + QUICK_RELEASE(m_pClientSite); + QUICK_RELEASE(m_pControlSite); + QUICK_RELEASE(m_pInPlaceSite); + QUICK_RELEASE(m_pInPlaceFrame); + QUICK_RELEASE(m_pInPlaceUIWindow); + QUICK_RELEASE(m_pSimpleFrameSite); + QUICK_RELEASE(m_pOleAdviseHolder); + QUICK_RELEASE(m_pViewAdviseSink); + QUICK_RELEASE(m_pDispAmbient); +} + +void tLuaControl::DestroyWindow() { + lua_getref(L, table_ref); + lua_pushstring(L, "DestroyWindow"); + lua_gettable(L, -2); + lua_pushvalue(L, -2); + lua_remove(L, -3); + luaCompat_call(L, 1, 0, NULL); +} + +STDMETHODIMP tLuaControl::QueryInterface(REFIID riid, void FAR* FAR* ppv) +{ + if(IsEqualIID(riid, IID_IUnknown) || + IsEqualIID(riid, IID_IDispatch) || + IsEqualIID(riid, interface_iid)) { + *ppv = (IDispatch*)this; + this->AddRef(); + return NOERROR; + } + + if((IsEqualIID(riid, IID_IProvideClassInfo) || + IsEqualIID(riid, IID_IProvideClassInfo2) ) && + classinfo2) + { + *ppv = classinfo2; + classinfo2->AddRef(); + return NOERROR; + } + + if(IsEqualIID(riid, IID_IConnectionPointContainer) && + cpc) + { + *ppv = cpc; + cpc->AddRef(); + return NOERROR; + } + + if(IsEqualIID(riid, IID_ILuaDispatch)) + { + *ppv = (ILuaDispatch*)this; + this->AddRef(); + return NOERROR; + } + + if(IsEqualIID(riid, IID_IOleObject)) + { + *ppv = (IOleObject*)this; + this->AddRef(); + return NOERROR; + } + + if(IsEqualIID(riid, IID_IOleControl)) + { + *ppv = (IOleControl*)this; + this->AddRef(); + return NOERROR; + } + + if(IsEqualIID(riid, IID_IOleInPlaceObject)) + { + *ppv = (IOleInPlaceObject*)this; + this->AddRef(); + return NOERROR; + } + + if(IsEqualIID(riid, IID_IOleInPlaceActiveObject)) + { + *ppv = (IOleInPlaceActiveObject*)this; + this->AddRef(); + return NOERROR; + } + + if(IsEqualIID(riid, IID_IViewObject)) + { + *ppv = (IViewObject2*)this; + this->AddRef(); + return NOERROR; + } + + if(IsEqualIID(riid, IID_IViewObject2)) + { + *ppv = (IViewObject2*)this; + this->AddRef(); + return NOERROR; + } + +/* if(IsEqualIID(riid, IID_IQuickActivate)) + { + *ppv = (IQuickActivate*)this; + this->AddRef(); + return NOERROR; + }*/ + + if(IsEqualIID(riid, IID_IPersistStreamInit)) + { + *ppv = (IPersistStreamInit*)this; + this->AddRef(); + return NOERROR; + } + + if(IsEqualIID(riid, IID_IPersistStorage)) + { + *ppv = (IPersistStorage*)this; + this->AddRef(); + return NOERROR; + } + + *ppv = NULL; + return ResultFromScode(E_NOINTERFACE); +} + +STDMETHODIMP_(unsigned long) tLuaControl::AddRef() +{ + return ++m_refs; +} + + +STDMETHODIMP_(unsigned long) tLuaControl::Release() +{ + assert(m_refs > 0); + if(--m_refs == 0) + { + // destrava tabela LUA + lua_unref(L, table_ref); + + // libera libs + + while(num_methods--) + { + typeinfo->ReleaseFuncDesc(funcinfo[num_methods].funcdesc); + delete funcinfo[num_methods].name; + } + + delete funcinfo; + typeinfo->Release(); + typeinfo = NULL; + + delete typehandler; + + if(cpc) + delete cpc; + + if(classinfo2) + delete classinfo2; + + // destroi objeto + delete this; + return 0; + } + + return m_refs; +} + +//=--------------------------------------------------------------------------= +// COleControl::GetControlInfo (IOleControl) +//=--------------------------------------------------------------------------= +// returns some information on a control, such as an accelerator table, and +// flags. really used for keyboard handling and mnemonics +// +// Parameters: +// CONTROLINFO * - [in] where to put said information +// +// Output: +// HRESULT - S_OK +// +// Notes: +// +STDMETHODIMP tLuaControl::GetControlInfo(CONTROLINFO *pControlInfo) +{ + CHECK_POINTER(pControlInfo); + + // certain hosts have a bug in which it doesn't initialize the cb in the + // CONTROLINFO structure, so we can only assert on that here. + // + ASSERT(pControlInfo->cb == sizeof(CONTROLINFO), "Host doesn't initialize CONTROLINFO structure"); + + // NOTE: control writers should override this routine if they want to + // return accelerator information in their control. + // + pControlInfo->hAccel = NULL; + pControlInfo->cAccel = NULL; + + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::OnMnemonic [IOleControl] +//=--------------------------------------------------------------------------= +// the container has decided to pass on a key that the end-user has pressed to +// us. default implementation will be to just activate the control. people +// looking for more functionality should override this method. +// +// Parameters: +// LPMSG - [in] message for this mnemonic +// +// Output: +// HRESULT - S_OK, E_POINTER +// +// Notes: +// +STDMETHODIMP tLuaControl::OnMnemonic(LPMSG pMsg) +{ + // OVERRIDE: default implementation is to just activate our control. + // user can override if they want more interesting behaviour. + // + return InPlaceActivate(TRUE); +} + +//=--------------------------------------------------------------------------= +// COleControl:OnAmbientPropertyChange [IOleControl] +//=--------------------------------------------------------------------------= +// a container calls this whenever it changes an ambient property. +// +// Parameters: +// DISPID - [in] dispid of the property that changed. +// +// Output: +// HRESULT - S_OK +// +// Notes: +// +STDMETHODIMP tLuaControl::OnAmbientPropertyChange(DISPID dispid) +{ + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::FreezeEvents [IOleControl] +//=--------------------------------------------------------------------------= +// allows a container to freeze all of a controls events. when events are +// frozen, a control will not fire any of them. +// +// Parameters: +// BOOL - [in] TRUE means FREEZE, FALSE means THAW +// +// Output: +// HRESULT - S_OK +// +STDMETHODIMP tLuaControl::FreezeEvents(BOOL fFreeze) +{ + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::SetClientSite [IOleObject] +//=--------------------------------------------------------------------------= +// informs the embedded object [control] of it's client site [display +// location] within it's container +// +// Parameters: +// IOleClientSite * - [in] pointer to client site. +// +// Output: +// HRESULT - S_OK, E_UNEXPECTED +// +// Notes: +// +STDMETHODIMP tLuaControl::SetClientSite(IOleClientSite* pcs) { + RELEASE_OBJECT(m_pClientSite); + RELEASE_OBJECT(m_pControlSite); + RELEASE_OBJECT(m_pSimpleFrameSite); + + // store away the new client site + // + m_pClientSite = pcs; + + // if we've actually got one, then get some other interfaces we want to keep + // around, and keep a handle on it + // + if (m_pClientSite) { + m_pClientSite->AddRef(); + m_pClientSite->QueryInterface(IID_IOleControlSite, (void **)&m_pControlSite); + } + + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::GetClientSite [IOleObject] +//=--------------------------------------------------------------------------= +// obtains a pointer to the controls client site. +// +// Parameters: +// IOleClientSite ** - [out] +// +// Output: +// HRESULT - S_OK +// +// Notes: +// +STDMETHODIMP tLuaControl::GetClientSite(IOleClientSite **ppClientSite) +{ + CHECK_POINTER(ppClientSite); + + *ppClientSite = m_pClientSite; + ADDREF_OBJECT(*ppClientSite); + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::SetHostNames [IOleObject] +//=--------------------------------------------------------------------------= +// Provides the control with the name of its container application and the +// compound document in which it is embedded +// +// Parameters: +// LPCOLESTR - [in] name of container application +// LPCOLESTR - [in] name of container document +// +// Output: +// HRESULT - S_OK +// +// Notes: +// - we don't care about this +// +STDMETHODIMP tLuaControl::SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj) { + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::Close [IOleObject] +//=--------------------------------------------------------------------------= +// Changes the control from the running to the loaded state +// +// Parameters: +// DWORD - [in] indicates whether to save the object before closing +// +// Output: +// HRESULT - S_OK, OLE_E_PROMPTSAVECANCELLED +// +// Notes: +// +STDMETHODIMP tLuaControl::Close(DWORD dwSaveOption) +{ + HRESULT hr; + + if (m_fInPlaceActive) { + hr = InPlaceDeactivate(); + RETURN_ON_FAILURE(hr); + } + + // handle the save flag. + // + if ((dwSaveOption == OLECLOSE_SAVEIFDIRTY || dwSaveOption == OLECLOSE_PROMPTSAVE) && m_fDirty) { + if (m_pOleAdviseHolder) m_pOleAdviseHolder->SendOnSave(); + } + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::SetMoniker [IOleObject] +//=--------------------------------------------------------------------------= +// Notifies an object of its container's moniker, the object's own moniker +// relative to the container, or the object's full moniker +// +// Parameters: +// DWORD - [in] which moniker is being set +// IMoniker * - [in] the moniker +// +// Output: +// HRESULT - S_OK, E_FAIL +// +// Notes: +// - we don't support monikers. +// +STDMETHODIMP tLuaControl::SetMoniker(DWORD dwWitchMoniker, IMoniker* pmk) { + return E_NOTIMPL; +} + +//=--------------------------------------------------------------------------= +// COleControl::GetMoniker [IOleObject] +//=--------------------------------------------------------------------------= +// Returns a embedded object's moniker, which the caller can use to link to +// the object +// +// Parameters: +// DWORD - [in] how it's assigned +// DWORD - [in] which moniker +// IMoniker ** - [out] duh. +// +// Output: +// HRESULT - E_NOTIMPL +// +// Notes: +// - we don't support monikers +// +STDMETHODIMP tLuaControl::GetMoniker(DWORD dwAssign, DWORD dwWitchMoniker, IMoniker** ppMoniker) { + return E_NOTIMPL; +} + +//=--------------------------------------------------------------------------= +// COleControl::InitFromData [IOleObject] +//=--------------------------------------------------------------------------= +// Initializes a newly created object with data from a specified data object, +// which can reside either in the same container or on the Clipboard +// +// Parameters: +// IDataObject* - [in] data object with the data +// BOOL - [in] how object is created +// DWORD - reserved +// +// Output: +// HRESULT - S_OK, S_FALSE, E_NOTIMPL, OLE_E_NOTRUNNING +// +// Notes: +// - we don't have data object support +// +STDMETHODIMP tLuaControl::InitFromData(IDataObject* pDataObject, BOOL fCreation, DWORD dwReserved) { + return E_NOTIMPL; +} + +//=--------------------------------------------------------------------------= +// COleControl::IsUpToDate [IOleObject] +//=--------------------------------------------------------------------------= +// Checks recursively whether or not an object is up to date. +// +// Output: +// HRESULT - S_OK, S_FALSE, OLE_E_UNVAILABLE +// +// Notes: +// +STDMETHODIMP tLuaControl::IsUpToDate() { + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::GetClipboardData [IOleObject] +//=--------------------------------------------------------------------------= +// Retrieves a data object containing the current contents of the control. +// Using the pointer to this data object, it is possible to create a new control +// with the same data as the original +// +// Parameters: +// DWORD - reserved +// IDataObject ** - [out] data object for this control +// +// Output: +// HREUSLT - S_OK, E_NOTIMPL, OLE_E_NOTRUNNING +// +// Notes: +// +STDMETHODIMP tLuaControl::GetClipboardData(DWORD dwReserved, IDataObject** ppDataObject) { + *ppDataObject = NULL; + return E_NOTIMPL; +} + +//=--------------------------------------------------------------------------= +// COleControl::DoVerb [IOleObject] +//=--------------------------------------------------------------------------= +// Requests an object to perform an action in response to an end-user's +// action. +// +// Parameters: +// LONG - [in] verb to be performed +// LPMSG - [in] event that invoked the verb +// IOleClientSite * - [in] the controls active client site +// LONG - [in] reserved +// HWND - [in] handle of window containing the object. +// LPCRECT - [in] pointer to objects's display rectangle +// +// Output: +// HRESULT - S_OK, OLE_E_NOTINPLACEACTIVE, OLE_E_CANT_BINDTOSOURCE, +// DV_E_LINK, OLEOBJ_S_CANNOT_DOVERB_NOW, OLEOBJ_S_INVALIDHWND, +// OLEOBJ_E_NOVERBS, OLEOBJ_S_INVALIDVERB, MK_E_CONNECT, +// OLE_CLASSDIFF, E_NOTIMPL +// +// Notes: +// +STDMETHODIMP tLuaControl::DoVerb(LONG lVerb, LPMSG pMsg, IOleClientSite *pActiveSite, + LONG lIndex, HWND hwndParent, LPCRECT prcPosRect) +{ + HRESULT hr = 0; + + switch (lVerb) { + case OLEIVERB_SHOW: + case OLEIVERB_INPLACEACTIVATE: + case OLEIVERB_UIACTIVATE: + hr = InPlaceActivate(lVerb==OLEIVERB_UIACTIVATE); + return (hr); + + case OLEIVERB_HIDE: + UIDeactivate(); + if (m_fInPlaceVisible) SetInPlaceVisible(FALSE); + return S_OK; + + default: + // if it's a derived-control defined verb, pass it on to them + // + if (lVerb > 0) { + if (hr == OLEOBJ_S_INVALIDVERB) { + // unrecognised verb -- just do the primary verb and + // activate the sucker. + // + hr = InPlaceActivate(0); + return (FAILED(hr)) ? hr : OLEOBJ_S_INVALIDVERB; + } else + return hr; + } else { + FAIL("Unrecognized Negative verb in DoVerb(). bad."); + return E_NOTIMPL; + } + break; + } + + // dead code + FAIL("this should be dead code!"); +} + +//=--------------------------------------------------------------------------= +// COleControl::EnumVerbs [IOleObject] +//=--------------------------------------------------------------------------= +// create an enumerator object for the verbs this object supports. +// +// Parameters: +// IEnumOleVERB ** - [out] new enumerator. +// +// Output: +// HRESULT - S_OK, E_OUTOFMEMORY +// +// Notes: +// +STDMETHODIMP tLuaControl::EnumVerbs(IEnumOLEVERB** ppEnumVerbs) { + return CEnumOLEVERB::CreateInstance(verbs, 5, ppEnumVerbs); +} + +//=--------------------------------------------------------------------------= +// COleControl::Update [IOleObject] +//=--------------------------------------------------------------------------= +// Updates an object handler's or link object's data or view caches. +// +// Output: +// HRESULT - S_OK +// +// Notes: +// +STDMETHODIMP tLuaControl::Update() { + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::GetUserClassID [IOleObject] +//=--------------------------------------------------------------------------= +// Returns the controls class identifier, the CLSID corresponding to the +// string identifying the object to an end user. +// +// Parameters: +// CLSID * - [in] where to put the CLSID +// +// Output: +// HRESULT - S_OK, E_FAIL +// +// Notes: +// +STDMETHODIMP tLuaControl::GetUserClassID(CLSID* pClsid) { + if(!pClsid) return E_POINTER; + lua_getref(L, table_ref); + lua_pushstring(L, "GetClass"); + lua_gettable(L, -2); + lua_pushvalue(L, -2); + lua_remove(L, -3); + if(luaCompat_call(L, 1, 1, NULL)) return E_FAIL; + const char * classID = lua_tostring(L, -1); + return CLSIDFromString(tUtil::string2bstr(classID),pClsid); +} + +//=--------------------------------------------------------------------------= +// COleControl::GetUserType [IOleObject] +//=--------------------------------------------------------------------------= +// Retrieves the user-type name of the control for display in user-interface +// elements such as menus, list boxes, and dialog boxes. +// +// Parameters: +// DWORD - [in] specifies the form of the type name. +// LPOLESTR * - [out] where to put user type +// +// Output: +// HRESULT - S_OK, OLE_S_USEREG, E_OUTOFMEMORY +// +// Notes: +// +STDMETHODIMP tLuaControl::GetUserType(DWORD dwFormOfType, LPOLESTR* pszUserType) { + CLSID clsid; + this->GetUserClassID(&clsid); + return OleRegGetUserType(clsid, dwFormOfType, pszUserType); +} + +//=--------------------------------------------------------------------------= +// COleControl::SetExtent [IOleObject] +//=--------------------------------------------------------------------------= +// Informs the control of how much display space its container has assigned it. +// +// Parameters: +// DWORD - [in] which form or 'aspect' is to be displayed. +// SIZEL * - [in] size limit for the control. +// +// Output: +// HRESULT - S_OK, E_FAIL, OLE_E_NOTRUNNING +// +// Notes: +// +STDMETHODIMP tLuaControl::SetExtent(DWORD dwDrawAspect, SIZEL *psizel) +{ + SIZEL sl; + RECT rect; + + if (dwDrawAspect & DVASPECT_CONTENT) { + + // change the units to pixels, and resize the control. + // + HimetricToPixel(psizel, &sl); + + // first call the user version. if they return FALSE, they want + // to keep their current size + // + lua_getref(L, table_ref); + lua_pushstring(L, "SetExtent"); + lua_gettable(L, -2); + lua_pushvalue(L, -2); + lua_remove(L, -3); + lua_pushnumber(L, sl.cx); + lua_pushnumber(L, sl.cy); + if(luaCompat_call(L, 3, 1, NULL)) return E_FAIL; + + if(luaCompat_toCBool(L,-1)) + HimetricToPixel(psizel, &m_Size); + + // set things up with our HWND + // + if (m_fInPlaceActive) { + + // theoretically, one should not need to call OnPosRectChange + // here, but there appear to be a few host related issues that + // will make us keep it here. we won't, however, both with + // windowless ole controls, since they are all new hosts who + // should know better + // + GetWindowRect(m_hwnd, &rect); + MapWindowPoints(NULL, m_hwndParent, (LPPOINT)&rect, 2); + rect.right = rect.left + m_Size.cx; + rect.bottom = rect.top + m_Size.cy; + m_pInPlaceSite->OnPosRectChange(&rect); + + if (m_hwnd) { + // just go and resize + // + SetWindowPos(m_hwnd, m_hwndParent, 0, 0, m_Size.cx, m_Size.cy, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + } + } else if (m_hwnd) { + SetWindowPos(m_hwnd, m_hwndParent, 0, 0, m_Size.cx, m_Size.cy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + } + + // return code depending on whether or not user accepted given + // size + // + return (luaCompat_toCBool(L,-1)) ? S_OK : E_FAIL; + } else { + // we don't support any other aspects. + // + return DV_E_DVASPECT; + } + + // dead code + FAIL("This should be dead code"); +} + +//=--------------------------------------------------------------------------= +// COleControl::GetExtent [IOleObject] +//=--------------------------------------------------------------------------= +// Retrieves the control's current display size. +// +// Parameters: +// DWORD - [in] aspect +// SIZEL * - [in] where to put results +// +// Output: +// S_OK, E_INVALIDARG +// +// Notes: +// +STDMETHODIMP tLuaControl::GetExtent(DWORD dwDrawAspect, SIZEL *pSizeLOut) +{ + if (dwDrawAspect & DVASPECT_CONTENT) { + PixelToHimetric((const SIZEL *)&m_Size, pSizeLOut); + return S_OK; + } else { + return DV_E_DVASPECT; + } +} + +//=--------------------------------------------------------------------------= +// COleControl::Advise [IOleObject] +//=--------------------------------------------------------------------------= +// establishes and advisory connection between the control and the container, +// in which the control will notify the container of certain events. +// +// Parameters: +// IAdviseSink * - [in] advise sink of calling object +// DWORD - [out] cookie +// +// Output: +// HRESULT - S_OK, E_OUTOFMEMORY +// +// Notes: +// +STDMETHODIMP tLuaControl::Advise(IAdviseSink *pAdviseSink, DWORD *pdwConnection) +{ + HRESULT hr; + + // if we haven't yet created a standard advise holder object, do so + // now + // + if (!m_pOleAdviseHolder) { + hr = CreateOleAdviseHolder(&m_pOleAdviseHolder); + RETURN_ON_FAILURE(hr); + } + + // just get it to do the work for us! + // + return m_pOleAdviseHolder->Advise(pAdviseSink, pdwConnection); +} + +//=--------------------------------------------------------------------------= +// COleControl::Unadvise [IOleObject] +//=--------------------------------------------------------------------------= +// Deletes a previously established advisory connection. +// +// Parameters: +// DWORD - [in] connection cookie +// +// Output: +// HRESULT - S_OK, E_FAIL, OLE_E_NOCONNECTION +// +// Notes: +// +STDMETHODIMP tLuaControl::Unadvise(DWORD dwConnection) +{ + if (!m_pOleAdviseHolder) { + FAIL("Somebody called Unadvise on IOleObject without calling Advise!"); + return E_FAIL; + } + + return m_pOleAdviseHolder->Unadvise(dwConnection); +} + +//=--------------------------------------------------------------------------= +// COleControl::EnumAdvise [IOleObject] +//=--------------------------------------------------------------------------= +// Enumerates the advisory connections registered for an object, so a container +// can know what to release prior to closing down. +// +// Parameters: +// IEnumSTATDATA ** - [out] where to put enumerator +// +// Output: +// HRESULT - S_OK, E_FAIL, E_NOTIMPL +// +// Notes: +// +STDMETHODIMP tLuaControl::EnumAdvise(IEnumSTATDATA **ppEnumOut) +{ + if (!m_pOleAdviseHolder) { + FAIL("Somebody Called EnumAdvise without setting up any connections"); + *ppEnumOut = NULL; + return E_FAIL; + } + + return m_pOleAdviseHolder->EnumAdvise(ppEnumOut); +} + +//=--------------------------------------------------------------------------= +// COleControl::GetMiscStatus [IOleObject] +//=--------------------------------------------------------------------------= +// Returns a value indicating the status of an object at creation and loading. +// +// Parameters: +// DWORD - [in] aspect desired +// DWORD * - [out] where to put the bits. +// +// Output: +// HRESULT - S_OK, OLE_S_USEREG, CO_E_CLASSNOTREG, CO_E_READREGDB +// +// Notes: +// +STDMETHODIMP tLuaControl::GetMiscStatus(DWORD dwAspect, DWORD* pdwStatus) { + if(!pdwStatus) return E_POINTER; + if(dwAspect != DVASPECT_CONTENT) return *pdwStatus = 0, E_FAIL; + *pdwStatus = OLEMISC_RECOMPOSEONRESIZE | OLEMISC_INSIDEOUT | OLEMISC_ACTIVATEWHENVISIBLE + | OLEMISC_ALWAYSRUN; + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::SetColorScheme [IOleObject] +//=--------------------------------------------------------------------------= +// Specifies the color palette that the object application should use when it +// edits the specified object. +// +// Parameters: +// LOGPALETTE * - [in] new palette +// +// Output: +// HRESULT - S_OK, E_NOTIMPL, OLE_E_PALETTE, OLE_E_NOTRUNNING +// +// Notes: +// - we don't care. +// +STDMETHODIMP tLuaControl::SetColorScheme(LOGPALETTE* pLogpal) { + return E_NOTIMPL; +} + +//=--------------------------------------------------------------------------= +// COleControl::GetWindow [IOleWindow/IOleInPlaceObject] +//=--------------------------------------------------------------------------= +// Returns the window handle to one of the windows participating in in-place +// activation (frame, document, parent, or in-place object window). +// +// Parameters: +// HWND * - [out] where to return window handle. +// +// Output: +// HRESULT - S_OK, E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL +// +// Notes: +// - this routine has slightly different semantics for windowless controls +// +STDMETHODIMP tLuaControl::GetWindow(HWND* phwnd) { + *phwnd = m_hwnd; + + return (*phwnd) ? S_OK : E_UNEXPECTED; +} + +//=--------------------------------------------------------------------------= +// COleControl::ContextSensitiveHelp [IOleWindow/IOleInPlaceObject] +//=--------------------------------------------------------------------------= +// Determines whether context-sensitive help mode should be entered during an +// in-place activation session. +// +// Parameters: +// BOOL - [in] whether or not to enter help mode. +// +// Output: +// HRESULT - S_OK, E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED +// +// Notes: +// +STDMETHODIMP tLuaControl::ContextSensitiveHelp(BOOL fEnterMode) { + return E_NOTIMPL; +} + +//=--------------------------------------------------------------------------= +// COleControl::InPlaceActivate +//=--------------------------------------------------------------------------= +// activates the control, and depending on the verb, optionally ui activates +// it as well. +// +// Parameters: +// LONG - [in] the verb that caused us to activate +// +// Output: +// HRESULT +// +// Notes: +// - this is spaghetti code at it's worst. effectively, we have to +// be able to handle three types of site pointers -- IOleInPlaceSIte, +// IOleInPlaceSiteEx, and IOleInPlaceSiteWindowless. not terribly +// pretty. +// +HRESULT tLuaControl::InPlaceActivate(BOOL lVerb) +{ + SIZEL sizel; + IOleInPlaceSiteEx *pIPSEx = NULL; + HRESULT hr; + BOOL fNoRedraw = FALSE; + + // if we don't have a client site, then there's not much to do. + // + if (!m_pClientSite) + return S_OK; + + // get an InPlace site pointer. + // + hr = m_pClientSite->QueryInterface(IID_IOleInPlaceSite, (void **)&m_pInPlaceSite); + RETURN_ON_FAILURE(hr); + + // if we're not already active, go and do it. + // + if (!m_fInPlaceActive) { + OLEINPLACEFRAMEINFO InPlaceFrameInfo; + RECT rcPos, rcClip; + + hr = m_pInPlaceSite->CanInPlaceActivate(); + if (hr != S_OK) { + hr = (FAILED(hr)) ? E_FAIL : hr; + goto CleanUp; + } + + // if we are here, then we have permission to go in-place active. + // now, announce our intentions to actually go ahead and do this. + // + m_pInPlaceSite->OnInPlaceActivate(); + CLEANUP_ON_FAILURE(hr); + + // if we're here, we're ready to go in-place active. we just need + // to set up some flags, and then create the window [if we have + // one] + // + m_fInPlaceActive = TRUE; + + // we need to get some information about our location in the parent + // window, as well as some information about the parent + // + InPlaceFrameInfo.cb = sizeof(OLEINPLACEFRAMEINFO); + hr = m_pInPlaceSite->GetWindow(&m_hwndParent); + if (SUCCEEDED(hr)) + hr = m_pInPlaceSite->GetWindowContext(&m_pInPlaceFrame, &m_pInPlaceUIWindow, &rcPos, &rcClip, &InPlaceFrameInfo); + CLEANUP_ON_FAILURE(hr); + + // make sure we'll display ourselves in the correct location with the correct size + // + sizel.cx = rcPos.right - rcPos.left; + sizel.cy = rcPos.bottom - rcPos.top; + m_Size = sizel; + SetObjectRects(&rcPos, &rcClip); + + // finally, create our window if we have to! + // create the window, and display it. die horribly if we couldnt' + // + if (!CreateInPlaceWindow(rcPos.left, rcPos.top, fNoRedraw)) { + hr = E_FAIL; + goto CleanUp; + } + } + + // if we're not inplace visible yet, do so now. + // + if (!m_fInPlaceVisible) + SetInPlaceVisible(TRUE); + + // if we weren't asked to UIActivate, then we're done. + // + if (!lVerb) + return S_OK; + + // if we're not already UI active, do sow now. + // + if (!m_fUIActive) { + m_fUIActive = TRUE; + + // inform the container of our intent + // + m_pInPlaceSite->OnUIActivate(); + + // take the focus [which is what UI Activation is all about !] + // + SetFocus(m_hwnd); + + // set ourselves up in the host. + // + m_pInPlaceFrame->SetActiveObject((IOleInPlaceActiveObject *)this, NULL); + if (m_pInPlaceUIWindow) + m_pInPlaceUIWindow->SetActiveObject((IOleInPlaceActiveObject *)this, NULL); + + // we have to explicitly say we don't wany any border space. + // + m_pInPlaceFrame->SetBorderSpace(NULL); + if (m_pInPlaceUIWindow) + m_pInPlaceUIWindow->SetBorderSpace(NULL); + } + + // be-de-be-de-be-de that's all folks! + // + return S_OK; + + CleanUp: + // something catastrophic happened [or, at least something bad]. + // die a horrible fiery mangled painful death. + // + m_fInPlaceActive = FALSE; + return hr; +} + +//=--------------------------------------------------------------------------= +// COleControl::InPlaceDeactivate [IOleInPlaceObject] +//=--------------------------------------------------------------------------= +// Deactivates an active in-place object and discards the object's undo state. +// +// Output: +// HRESULT - S_OK, E_UNEXPECTED +// +// Notes: +// +STDMETHODIMP tLuaControl::InPlaceDeactivate(void) +{ + // if we're not in-place active yet, then this is easy. + // + if (!m_fInPlaceActive) + return S_OK; + + // transition from UIActive back to active + // + if (m_fUIActive) + UIDeactivate(); + + m_fInPlaceActive = FALSE; + m_fInPlaceVisible = FALSE; + + // if we have a window, tell it to go away. + // + if (m_hwnd) { + // so our window proc doesn't crash. + // + DestroyWindow(); + m_hwnd = NULL; + } + + RELEASE_OBJECT(m_pInPlaceFrame); + RELEASE_OBJECT(m_pInPlaceUIWindow); + m_pInPlaceSite->OnInPlaceDeactivate(); + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::UIDeactivate [IOleInPlaceObject] +//=--------------------------------------------------------------------------= +// transitions us from UI Active to merely being active [visible] for +// a control, this doesn't mean all that much. +// +// Output: +// HRESULT - S_OK, E_UNEXPECTED +// +// Notes: +// +STDMETHODIMP tLuaControl::UIDeactivate(void) +{ + // if we're not UIActive, not much to do. + // + if (!m_fUIActive) + return S_OK; + + m_fUIActive = FALSE; + + // notify frame windows, if appropriate, that we're no longer ui-active. + // + if (m_pInPlaceUIWindow) m_pInPlaceUIWindow->SetActiveObject(NULL, NULL); + m_pInPlaceFrame->SetActiveObject(NULL, NULL); + + // we don't need to explicitly release the focus here since somebody + // else grabbing the focus is what is likely to cause us to get lose it + // + m_pInPlaceSite->OnUIDeactivate(FALSE); + + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::SetObjectRects [IOleInPlaceObject] +//=--------------------------------------------------------------------------= +// Indicates how much of the control is visible. +// +// Parameters: +// LPCRECT - [in] position of the control. +// LPCRECT - [in] clipping rectangle for the control. +// +// Output: +// HRESULT - S_OK, E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED +// +// Notes: +// +STDMETHODIMP tLuaControl::SetObjectRects(LPCRECT prcPos, LPCRECT prcClip) +{ + BOOL fRemoveWindowRgn; + + // move our window to the new location and handle clipping. not applicable + // for windowless controls, since the container will be responsible for all + // clipping. + // + if (m_hwnd) { + fRemoveWindowRgn = m_fUsingWindowRgn; + if (prcClip) { + // the container wants us to clip, so figure out if we really + // need to + // + RECT rcIXect; + if ( IntersectRect(&rcIXect, prcPos, prcClip) ) { + if (!EqualRect(&rcIXect, prcPos)) { + OffsetRect(&rcIXect, -(prcPos->left), -(prcPos->top)); + + HRGN tempRgn = CreateRectRgnIndirect(&rcIXect); + SetWindowRgn(m_hwnd, tempRgn, TRUE); + + if (m_hRgn != NULL) + DeleteObject(m_hRgn); + m_hRgn = tempRgn; + + m_fUsingWindowRgn = TRUE; + fRemoveWindowRgn = FALSE; + } + } + } + + if (fRemoveWindowRgn) { + SetWindowRgn(m_hwnd, NULL, TRUE); + if (m_hRgn != NULL) + { + DeleteObject(m_hRgn); + m_hRgn = NULL; + } + m_fUsingWindowRgn = FALSE; + } + + // set our control's location, but don't change it's size at all + // [people for whom zooming is important should set that up here] + // + int cx, cy; + cx = prcPos->right - prcPos->left; + cy = prcPos->bottom - prcPos->top; + SetWindowPos(m_hwnd, m_hwndParent, prcPos->left, prcPos->top, cx, cy, SWP_NOZORDER | SWP_NOACTIVATE); + } + + // save out our current location. windowless controls want this more + // that windowed ones do, but everybody can have it just in case + // + m_rcLocation = *prcPos; + + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::ReactivateAndUndo [IOleInPlaceObject] +//=--------------------------------------------------------------------------= +// Reactivates a previously deactivated object, undoing the last state of the object. +// +// Output: +// HRESULT - S_OK, E_NOTUNDOABLE +// +// Notes: +// +STDMETHODIMP tLuaControl::ReactivateAndUndo +( + void +) +{ + return E_NOTIMPL; +} + +//=--------------------------------------------------------------------------= +// COleControl::TranslateAccelerator [IOleInPlaceActiveObject] +//=--------------------------------------------------------------------------= +// Processes menu accelerator-key messages from the container's message queue. +// +// Parameters: +// LPMSG - [in] the message that has the special key in it. +// +// Output: +// HRESULT - S_OK, S_FALSE, E_UNEXPECTED +// +// Notes: +// +STDMETHODIMP tLuaControl::TranslateAccelerator(LPMSG pmsg) +{ + // we didn't want it. + // + return S_FALSE; +} + +//=--------------------------------------------------------------------------= +// COleControl::OnFrameWindowActivate [IOleInPlaceActiveObject] +//=--------------------------------------------------------------------------= +// Notifies the control when the container's top-level frame window is +// activated or deactivated. +// +// Parameters: +// BOOL - [in] state of containers top level window. +// +// Output: +// HRESULT - S_OK +// +// Notes: +// +STDMETHODIMP tLuaControl::OnFrameWindowActivate +( + BOOL fActivate +) +{ + // we're supposed to go UI active in this case + // + return InPlaceActivate(TRUE); +} + +//=--------------------------------------------------------------------------= +// COleControl::OnDocWindowActivate [IOleInPlaceActiveObject] +//=--------------------------------------------------------------------------= +// Notifies the active control when the container's document window is +// activated or deactivated. +// +// Parameters: +// BOOL - state of mdi child window. +// +// Output: +// HRESULT - S_OK +// +// Notes: +// +STDMETHODIMP tLuaControl::OnDocWindowActivate +( + BOOL fActivate +) +{ + // we're supposed to go UI active in this case + // + return InPlaceActivate(TRUE); +} + +//=--------------------------------------------------------------------------= +// COleControl::ResizeBorder [IOleInPlaceActiveObject] +//=--------------------------------------------------------------------------= +// Alerts the control that it needs to resize its border space. +// +// Parameters: +// LPCRECT - [in] new outer rectangle for border space +// IOleInPlaceUIWindow * - [in] the document or frame who's border has changed +// BOOL - [in] true if it was the fram window taht called. +// +// Output: +// HRESULT - S_OK +// +// Notes: +// +STDMETHODIMP tLuaControl::ResizeBorder(LPCRECT prcBorder, + IOleInPlaceUIWindow *pUIWindow, + BOOL fFrameWindow) { + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::EnableModeless [IOleInPlaceActiveObject] +//=--------------------------------------------------------------------------= +// Enables or disables modeless dialog boxes when the container creates or +// destroys a modal dialog box. +// +// Parameters: +// BOOL - [in] enable or disable modeless dialogs. +// +// Output: +// HRESULT - S_OK +// +// Notes: +// +STDMETHODIMP tLuaControl::EnableModeless(BOOL fEnable) { + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::Draw [IViewObject2] +//=--------------------------------------------------------------------------= +// Draws a representation of an object onto the specified device context. +// +// Parameters: +// DWORD - [in] draw aspect +// LONG - [in] part of object to draw [not relevant] +// void * - NULL +// DVTARGETDEVICE * - [in] specifies the target device +// HDC - [in] information context for target device +// HDC - [in] target device context +// LPCRECTL - [in] rectangle in which the object is drawn +// LPCRECTL - [in] window extent and origin for metafiles +// BOOL (*)(DWORD) - [in] callback for continuing or cancelling drawing +// DWORD - [in] parameter to pass to callback. +// +// Output: +// HRESULT +// +// Notes: +// - we support the following OCX 96 extensions +// a. flicker free drawing [multi-pass drawing] +// b. pvAspect != NULL for optimized DC handling +// c. prcBounds == NULL for windowless inplace active objects +// +STDMETHODIMP tLuaControl::Draw(DWORD dwDrawAspect, LONG lIndex, void *pvAspect, + DVTARGETDEVICE *ptd, HDC hicTargetDevice, HDC hdcDraw, LPCRECTL prcBounds, + LPCRECTL prcWBounds, BOOL (__stdcall *pfnContinue)(DWORD dwContinue), DWORD dwContinue) +{ + RECT rcClient; + int iMapMode; + POINT ptWOrg, ptVOrg; + SIZE sWOrg, sVOrg; + + // support the aspects required for multi-pass drawing + // + switch (dwDrawAspect) { + case DVASPECT_CONTENT: + break; + default: + return DV_E_DVASPECT; + } + + if (hicTargetDevice) + return E_NOTIMPL; + + if (!m_hwnd) + return E_FAIL; + + GetClientRect(m_hwnd, &rcClient); + + // set up the DC for painting. this code largely taken from the MFC CDK + // DoSuperClassPaint() fn. doesn't always get things like command + // buttons quite right ... + // + // NOTE: there is a windows 95 problem in which the font instance manager + // will leak a bunch of bytes in the global GDI pool whenever you + // change your extents and have an active font. this code gets around + // this for on-screen cases, but not for printing [which shouldn't be + // too serious, because you're not often changing your control size and + // printing rapidly in succession] + // + if ((rcClient.right - rcClient.left != prcBounds->right - prcBounds->left) + && (rcClient.bottom - rcClient.top != prcBounds->bottom - prcBounds->top)) { + + iMapMode = SetMapMode(hdcDraw, MM_ANISOTROPIC); + SetWindowExtEx(hdcDraw, rcClient.right, rcClient.bottom, &sWOrg); + SetViewportExtEx(hdcDraw, prcBounds->right - prcBounds->left, prcBounds->bottom - prcBounds->top, &sVOrg); + } + + SetWindowOrgEx(hdcDraw, 0, 0, &ptWOrg); + SetViewportOrgEx(hdcDraw, prcBounds->left, prcBounds->top, &ptVOrg); + +// SendMessage(WindowFromDC(hdcDraw), WM_PAINT, NULL, NULL); + + LRESULT wndProc = GetWindowLong(m_hwnd, GWL_WNDPROC); + if(!wndProc) + wndProc = GetWindowLong(m_hwnd, DWL_DLGPROC); + CallWindowProc((WNDPROC)wndProc, m_hwnd, WM_PAINT, (WPARAM)hdcDraw, 0); + + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::GetColorSet [IViewObject2] +//=--------------------------------------------------------------------------= +// Returns the logical palette that the control will use for drawing in its +// IViewObject::Draw method with the corresponding parameters. +// +// Parameters: +// DWORD - [in] how the object is to be represented +// LONG - [in] part of the object to draw [not relevant] +// void * - NULL +// DVTARGETDEVICE * - [in] specifies the target device +// HDC - [in] information context for the target device +// LOGPALETTE ** - [out] where to put palette +// +// Output: +// S_OK - Control has a palette, and returned it through the out param. +// S_FALSE - Control does not currently have a palette. +// E_NOTIMPL - Control will never have a palette so optimize handling of this control. +// +// Notes: +// +STDMETHODIMP tLuaControl::GetColorSet(DWORD dwDrawAspect, LONG lindex, + void *IgnoreMe, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet) +{ + if (dwDrawAspect != DVASPECT_CONTENT) + return DV_E_DVASPECT; + + return E_NOTIMPL; +} + +//=--------------------------------------------------------------------------= +// COleControl::Freeze [IViewObject2] +//=--------------------------------------------------------------------------= +// Freezes a certain aspect of the object's presentation so that it does not +// change until the IViewObject::Unfreeze method is called. +// +// Parameters: +// DWORD - [in] aspect +// LONG - [in] part of object to draw +// void * - NULL +// DWORD * - [out] for Unfreeze +// +// Output: +// HRESULT +// +// Notes: +// +STDMETHODIMP tLuaControl::Freeze(DWORD dwDrawAspect, LONG lIndex, void *IgnoreMe, DWORD *pdwFreeze) +{ + return E_NOTIMPL; +} + +//=--------------------------------------------------------------------------= +// COleControl::Unfreeze [IVewObject2] +//=--------------------------------------------------------------------------= +// Releases a previously frozen drawing. The most common use of this method +// is for banded printing. +// +// Parameters: +// DWORD - [in] cookie from freeze +// +// Output: +// HRESULT +// +// Notes: +// +STDMETHODIMP tLuaControl::Unfreeze(DWORD dwFreeze) +{ + return E_NOTIMPL; +} + +//=--------------------------------------------------------------------------= +// COleControl::SetAdvise [IViewObject2] +//=--------------------------------------------------------------------------= +// Sets up a connection between the control and an advise sink so that the +// advise sink can be notified about changes in the control's view. +// +// Parameters: +// DWORD - [in] aspect +// DWORD - [in] info about the sink +// IAdviseSink * - [in] the sink +// +// Output: +// HRESULT +// +// Notes: +// +STDMETHODIMP tLuaControl::SetAdvise(DWORD dwAspects, DWORD dwAdviseFlags, IAdviseSink *pAdviseSink) +{ + // if it's not a content aspect, we don't support it. + // + if (!(dwAspects & DVASPECT_CONTENT)) { + return DV_E_DVASPECT; + } + + // set up some flags [we gotta stash for GetAdvise ...] + // + m_fViewAdvisePrimeFirst = (dwAdviseFlags & ADVF_PRIMEFIRST) ? TRUE : FALSE; + m_fViewAdviseOnlyOnce = (dwAdviseFlags & ADVF_ONLYONCE) ? TRUE : FALSE; + + RELEASE_OBJECT(m_pViewAdviseSink); + m_pViewAdviseSink = pAdviseSink; + ADDREF_OBJECT(m_pViewAdviseSink); + + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::GetAdvise [IViewObject2] +//=--------------------------------------------------------------------------= +// Retrieves the existing advisory connection on the control if there is one. +// This method simply returns the parameters used in the most recent call to +// the IViewObject::SetAdvise method. +// +// Parameters: +// DWORD * - [out] aspects +// DWORD * - [out] advise flags +// IAdviseSink ** - [out] the sink +// +// Output: +// HRESULT +// +// Notes; +// +STDMETHODIMP tLuaControl::GetAdvise(DWORD *pdwAspects, DWORD *pdwAdviseFlags, IAdviseSink **ppAdviseSink) +{ + // if they want it, give it to them + // + if (pdwAspects) + *pdwAspects = DVASPECT_CONTENT; + + if (pdwAdviseFlags) { + *pdwAdviseFlags = 0; + if (m_fViewAdviseOnlyOnce) *pdwAdviseFlags |= ADVF_ONLYONCE; + if (m_fViewAdvisePrimeFirst) *pdwAdviseFlags |= ADVF_PRIMEFIRST; + } + + if (ppAdviseSink) { + *ppAdviseSink = m_pViewAdviseSink; + ADDREF_OBJECT(*ppAdviseSink); + } + + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::GetExtent [IViewObject2] +//=--------------------------------------------------------------------------= +// Returns the size that the control will be drawn on the +// specified target device. +// +// Parameters: +// DWORD - [in] draw aspect +// LONG - [in] part of object to draw +// DVTARGETDEVICE * - [in] information about target device +// LPSIZEL - [out] where to put the size +// +// Output: +// HRESULT +// +// Notes: +// +STDMETHODIMP tLuaControl::GetExtent(DWORD dwDrawAspect, LONG lindex, DVTARGETDEVICE *ptd, LPSIZEL psizel) +{ + // we already have an implementation of this [from IOleObject] + // + return GetExtent(dwDrawAspect, psizel); +} + + +//=--------------------------------------------------------------------------= +// COleControl::SetInPlaceVisible [helper] +//=--------------------------------------------------------------------------= +// controls the visibility of the control window. +// +// Parameters: +// BOOL - TRUE shows FALSE hides. +// +// Notes: +// +void tLuaControl::SetInPlaceVisible(BOOL fShow) +{ + BOOL fVisible; + + m_fInPlaceVisible = fShow; + + // don't do anything if we don't have a window. otherwise, set it + // + if (m_hwnd) { + fVisible = ((GetWindowLong(m_hwnd, GWL_STYLE) & WS_VISIBLE) != 0); + + if (fVisible && !fShow) + ShowWindow(m_hwnd, SW_HIDE); + else if (!fVisible && fShow) + ShowWindow(m_hwnd, SW_SHOWNA); + } +} + +//=--------------------------------------------------------------------------= +// COleControl::CreateInPlaceWindow +//=--------------------------------------------------------------------------= +// creates the window with which we will be working. +// yay. +// +// Parameters: +// int - [in] left +// int - [in] top +// BOOL - [in] can we skip redrawing? +// +// Output: +// HWND +// +// Notes: +// - DANGER! DANGER! this function is protected so that anybody can call it +// from their control. however, people should be extremely careful of when +// and why they do this. preferably, this function would only need to be +// called by an end-control writer in design mode to take care of some +// hosting/painting issues. otherwise, the framework should be left to +// call it when it wants. +// +HWND tLuaControl::CreateInPlaceWindow(int x, int y, BOOL fNoRedraw) +{ + BOOL fVisible; + + // if we've already got a window, do nothing. + // + if (m_hwnd) + return m_hwnd; + + // create window visible if parent hidden (common case) + // otherwise, create hidden, then shown. this is a little subtle, but + // it makes sense eventually. + // + if (!m_hwndParent) + m_hwndParent = GetParkingWindow(); + + fVisible = IsWindowVisible(m_hwndParent); + + // we have to mutex the entire create window process since we need to use + // the s_pLastControlCreated to pass in the object pointer. nothing too + // serious + // + m_fCreatingWindow = TRUE; + + lua_getref(L, table_ref); + lua_pushstring(L, "CreateWindow"); + lua_gettable(L, -2); + lua_pushvalue(L, -2); + lua_remove(L, -3); + luaCompat_pushPointer(L, m_hwndParent); + lua_pushnumber(L, x); + lua_pushnumber(L, y); + lua_pushnumber(L, m_Size.cx); + lua_pushnumber(L, m_Size.cy); + const char *err; + int res = luaCompat_call(L, 6, 1, &err); + if(res) return NULL; + + m_hwnd = (HWND)luaCompat_getPointer(L, -1); + lua_pop(L, 1); + + // clean up some variables, and leave the critical section + // + m_fCreatingWindow = FALSE; + + if (m_hwnd) { + // if we didn't create the window visible, show it now. + // + + if (fVisible) + { + SetWindowPos(m_hwnd, m_hwndParent, x, y, m_Size.cx, m_Size.cy, + SWP_NOZORDER | SWP_SHOWWINDOW | ((fNoRedraw) ? SWP_NOREDRAW : 0)); + } + } + + // finally, tell the host of this + // + if (m_pClientSite) + m_pClientSite->ShowObject(); + + return m_hwnd; +} + +//=--------------------------------------------------------------------------= +// COleControl::GetClassID [IPersistStreamInit] +//=--------------------------------------------------------------------------= +// returns the classid of this mamma +// +// Parameters: +// CLSID * - [out] where to put the clsid +// +// Output: +// HRESULT +// +// Notes: +// +STDMETHODIMP tLuaControl::GetClassID(CLSID *pclsid) +{ + return GetUserClassID(pclsid); +} + + +//=--------------------------------------------------------------------------= +// COleControl::IsDirty [IPersistStreamInit] +//=--------------------------------------------------------------------------= +// asks if we're dirty or not. duh. +// +// Output: +// HRESULT - S_OK: dirty, S_FALSE: not dirty +// +// Notes: +// +STDMETHODIMP tLuaControl::IsDirty(void) +{ + return S_FALSE; +} + +//=--------------------------------------------------------------------------= +// COleControl::InitNew [IPersistStreamInit] +//=--------------------------------------------------------------------------= +// causes the control to intialize itself with a new bunch of state information +// +// Output: +// HRESULT +// +// Notes: +// +STDMETHODIMP tLuaControl::InitNew(void) +{ + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::GetSizeMax [IPersistStreamInit] +//=--------------------------------------------------------------------------= +// +// Parameters: +// ULARGE_INTEGER * - [out] +// +// Output: +// HRESULT +// +// Notes: +// +STDMETHODIMP tLuaControl::GetSizeMax(ULARGE_INTEGER *pulMaxSize) +{ + return E_NOTIMPL; +} + +//=--------------------------------------------------------------------------= +// COleControl::Load [IPersistStreamInit] +//=--------------------------------------------------------------------------= +// load from an IStream +// +// Parameters: +// IStream * - [in] stream from which to load +// +// Output: +// HRESULT +// +// Notes: +// +STDMETHODIMP tLuaControl::Load(IStream *pStream) +{ + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::Save [IPersistStreamInit] +//=--------------------------------------------------------------------------= +// saves out our state using streams +// +// Parameters: +// IStream * - [in] +// BOOL - [in] clear dirty bit? +// +// Output: +// HRESULT +// +// Notes: +// +STDMETHODIMP tLuaControl::Save(IStream *pStream, BOOL fClearDirty) +{ + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::InitNew [IPersistStorage] +//=--------------------------------------------------------------------------= +// ipersiststorage version of this. fweee +// +// Parameters: +// IStorage * - [in] we don't use this +// +// Output: +// HRESULT +// +// Notes: +// +STDMETHODIMP tLuaControl::InitNew(IStorage *pStorage) +{ + return InitNew(); +} + +//=--------------------------------------------------------------------------= +// COleControl::Load [IPersistStorage] +//=--------------------------------------------------------------------------= +// Ipersiststorage version of this +// +// Parameters: +// IStorage * - [in] DUH. +// +// Output: +// HRESULT +// +// Notes: +// +STDMETHODIMP tLuaControl::Load(IStorage *pStorage) +{ + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::Save [IPersistStorage] +//=--------------------------------------------------------------------------= +// save into the contents stream of the given storage object. +// +// Parameters: +// IStorage * - [in] 10 points if you figure it out +// BOOL - [in] is the storage the same as the load storage? +// +// Output: +// HRESULT +// +// Notes: +// +STDMETHODIMP tLuaControl::Save(IStorage *pStorage, BOOL fSameAsLoad) +{ + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::SaveCompleted [IPersistStorage] +//=--------------------------------------------------------------------------= +// lets us clear out our flags. +// +// Parameters: +// IStorage * - ignored +// +// Output: +// HRESULT +// +// Notes: +// +STDMETHODIMP tLuaControl::SaveCompleted(IStorage *pStorageNew) +{ + // if our save succeeded, then we can do our post save work. + // + /*if (m_fSaveSucceeded) { + m_fDirty = FALSE; + if (m_pOleAdviseHolder) + m_pOleAdviseHolder->SendOnSave(); + }*/ + + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::HandsOffStorage [IPersistStorage] +//=--------------------------------------------------------------------------= +// not interesting +// +// Output: +// S_OK +// +// Notes: +// +STDMETHODIMP tLuaControl::HandsOffStorage(void) +{ + // we don't ever hold on to a storage pointer, so this is remarkably + // uninteresting to us. + // + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::QuickActivate [IQuickActivate] +//=--------------------------------------------------------------------------= +// allows the container to activate the control. +// +// Parameters: +// QACONTAINER * - [in] info about the container +// QACONTROL * - [out] info about the control +// +// Output: +// HRESULT +// +// Notes: +// +STDMETHODIMP tLuaControl::QuickActivate(QACONTAINER *pContainer, QACONTROL *pControl) +{ + HRESULT hr; + DWORD dw; + + // we need these guys. + // + if (!pContainer) return E_UNEXPECTED; + if (!pControl) return E_UNEXPECTED; + + // start grabbing things from the QACONTAINER structure and apply them + // as relevant + // + if (pContainer->cbSize < sizeof(QACONTAINER)) return E_UNEXPECTED; + if (pControl->cbSize < sizeof(QACONTROL)) return E_UNEXPECTED; + + // save out the client site, of course. + // + if (pContainer->pClientSite) { + hr = SetClientSite(pContainer->pClientSite); + RETURN_ON_FAILURE(hr); + } + + // then the event sink. + // + if (pContainer->pUnkEventSink) { + tLuaCOMConnPointContainer* cpc = GetConnPointContainer(); + IConnectionPoint *connection_point; + hr = cpc->FindConnectionPoint(IID_IUnknown, &connection_point); + if (FAILED(hr)) { + pContainer->pUnkEventSink->Release(); + return hr; + } + hr = connection_point->Advise(pContainer->pUnkEventSink, &pControl->dwEventCookie); + if (FAILED(hr)) { + pContainer->pUnkEventSink->Release(); + return hr; + } + } + + // finally, the advise sink. + // + if (pContainer->pAdviseSink) { + // don't need to pass the cookie back since there can only be one + // person advising at a time. + // + hr = Advise(pContainer->pAdviseSink, &dw); + RETURN_ON_FAILURE(hr); + } + + // set up a few things in the QACONTROL structure. we're opaque by default + // + pControl->dwMiscStatus = OLEMISC_RECOMPOSEONRESIZE | OLEMISC_INSIDEOUT | OLEMISC_ACTIVATEWHENVISIBLE | OLEMISC_ALWAYSRUN; + pControl->dwViewStatus = VIEWSTATUS_OPAQUE; + pControl->dwPointerActivationPolicy = POINTERINACTIVE_ACTIVATEONENTRY; + + // that's pretty much all we're interested in. we will, however, pass on the + // rest of the things to the end control writer and see if they want to do + // anything with them. they shouldn't touch any of the above except for the + // ambients. + // + return S_OK; +} + +//=--------------------------------------------------------------------------= +// COleControl::SetContentExtent [IQuickActivate] +//=--------------------------------------------------------------------------= +// the container calls this to set the content extent of the control. +// +// Parameters: +// LPSIZEL - [in] the size of the content extent +// +// Output: +// HRESULT - S_OK, or E_FAIL for fixed size control +// +// Notes: +// +STDMETHODIMP tLuaControl::SetContentExtent(LPSIZEL pSize) +{ + return SetExtent(DVASPECT_CONTENT, pSize); +} + +//=--------------------------------------------------------------------------= +// COleControl::GetContentExtent [IQuickActivate] +//=--------------------------------------------------------------------------= +// the container calls this to get the content extent of the control +// +// Parameters: +// LPSIZEL - [out] returns current size +// +// Output: +// HRESULT +// +// Notes: +// +STDMETHODIMP tLuaControl::GetContentExtent(LPSIZEL pSize) +{ + return GetExtent(DVASPECT_CONTENT, pSize); +} + + +tLuaControl *tLuaControl::CreateLuaControl(lua_State* L, + ITypeInfo* interface_typeinfo, + int ref + ) +{ + tLuaControl *pcont = + new tLuaControl(L, interface_typeinfo, ref); + + lua_getref(L, ref); + luaCompat_pushPointer(L, idxDispatch); + luaCompat_pushPointer(L, pcont); + lua_rawset(L,-3); + lua_pop(L, 1); + + pcont->AddRef(); + + return pcont; +} diff --git a/luacom/tLuaControl.h b/luacom/tLuaControl.h new file mode 100644 index 00000000..e5404b6d --- /dev/null +++ b/luacom/tLuaControl.h @@ -0,0 +1,226 @@ +/* + * tLuaControl.h + */ + +#ifndef __TLUACONTROL_H +#define __TLUACONTROL_H + +#include +#include +#include + +#include "tLuaDispatch.h" + +class tLuaControl: public tLuaDispatch, public IOleObject, + public IOleControl, public IOleInPlaceObject, + public IOleInPlaceActiveObject, public IViewObject2, + public IPersistStreamInit, public IPersistStorage, public IQuickActivate +{ +public: + tLuaControl(lua_State* L, ITypeInfo *pTypeinfo, int ref); + ~tLuaControl(); + STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj); + STDMETHODIMP_(unsigned long) AddRef(void); + STDMETHODIMP_(unsigned long) Release(void); + + //=--------------------------------------------------------------------------= + // IPersist methods. used by IPersistStream and IPersistStorage + // + STDMETHOD(GetClassID)(THIS_ LPCLSID lpClassID); + + // IPersistStreamInit methods + // + STDMETHOD(IsDirty)(THIS); + STDMETHOD(Load)(LPSTREAM pStm); + STDMETHOD(Save)(LPSTREAM pStm, BOOL fClearDirty); + STDMETHOD(GetSizeMax)(ULARGE_INTEGER FAR* pcbSize); + STDMETHOD(InitNew)(); + + // IPersistStorage + // + STDMETHOD(InitNew)(IStorage *pStg); + STDMETHOD(Load)(IStorage *pStg); + STDMETHOD(Save)(IStorage *pStgSave, BOOL fSameAsLoad); + STDMETHOD(SaveCompleted)(IStorage *pStgNew); + STDMETHOD(HandsOffStorage)(void); + + // IOleControl methods + // + STDMETHOD(GetControlInfo)(LPCONTROLINFO pCI); + STDMETHOD(OnMnemonic)(LPMSG pMsg); + STDMETHOD(OnAmbientPropertyChange)(DISPID dispid); + STDMETHOD(FreezeEvents)(BOOL bFreeze); + + // IOleObject implementation (yikes) + STDMETHOD(SetClientSite)(IOleClientSite* pcs); + STDMETHOD(GetClientSite)(IOleClientSite** ppcs); + STDMETHOD(SetHostNames)(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj); + STDMETHOD(Close)(DWORD dwSaveOption); + STDMETHOD(SetMoniker)(DWORD dwWitchMoniker, IMoniker* pmk); + STDMETHOD(GetMoniker)(DWORD dwAssign, DWORD dwWitchMoniker, IMoniker** ppMoniker); + STDMETHOD(InitFromData)(IDataObject* pDataObject, BOOL fCreation, DWORD dwReserved); + STDMETHOD(IsUpToDate)(); + STDMETHOD(GetClipboardData)(DWORD dwReserved, IDataObject** ppDataObject); + STDMETHOD(DoVerb)(long iVerb, MSG* lpmsg, IOleClientSite* pActiveSite, + long lIndex, HWND hwndParent, LPCRECT lprcPosRect); + STDMETHOD(EnumVerbs)(IEnumOLEVERB** ppEnumOleVerb); + STDMETHOD(Update)(); + STDMETHOD(GetUserClassID)(CLSID* pClsid); + STDMETHOD(GetUserType)(DWORD dwFormOfType, LPOLESTR* pszUserType); + STDMETHOD(SetExtent)(DWORD dwAspect, SIZEL* pSizel); + STDMETHOD(GetExtent)(DWORD dwAspect, SIZEL* pSizel); + STDMETHOD(Advise)(IAdviseSink* pAdvSink, DWORD* pdwConnection); + STDMETHOD(Unadvise)(DWORD dwConnection); + STDMETHOD(EnumAdvise)(IEnumSTATDATA** ppEnumAdvise); + STDMETHOD(GetMiscStatus)(DWORD dwAspect, DWORD* pdwStatus); + STDMETHOD(SetColorScheme)(LOGPALETTE* pLogpal); + + // IOleInPlaceObject implementation + STDMETHOD(GetWindow)(HWND* phwnd); + STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode); + STDMETHOD(InPlaceDeactivate)(); + STDMETHOD(UIDeactivate)(); + STDMETHOD(SetObjectRects)(LPCRECT lprcPosRect, LPCRECT lprcClipRect); + STDMETHOD(ReactivateAndUndo)(); + + // IOleInPlaceActiveObject + STDMETHOD(TranslateAccelerator)(LPMSG lpmsg); + STDMETHOD(OnFrameWindowActivate)(BOOL fActivate); + STDMETHOD(OnDocWindowActivate)(BOOL fActivate); + STDMETHOD(ResizeBorder)(LPCRECT prcBorder, + IOleInPlaceUIWindow *pUIWindow, + BOOL fFrameWindow); + STDMETHOD(EnableModeless)(BOOL fEnable); + + // IViewObject2 + STDMETHOD(Draw)(DWORD dwDrawAspect, LONG lindex, void *pvAspect, + DVTARGETDEVICE *ptd, HDC hdcTargetDev, HDC hdcDraw, + LPCRECTL lprcBounds, LPCRECTL lprcWBounds, + BOOL ( __stdcall *pfnContinue )(DWORD dwContinue), + DWORD dwContinue); + STDMETHOD(GetColorSet)(DWORD dwDrawAspect,LONG lindex, void *pvAspect, + DVTARGETDEVICE *ptd, HDC hicTargetDev, + LOGPALETTE * *ppColorSet); + STDMETHOD(Freeze)(DWORD dwDrawAspect, LONG lindex, + void *pvAspect,DWORD *pdwFreeze); + STDMETHOD(Unfreeze)(DWORD dwFreeze); + STDMETHOD(SetAdvise)(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink); + STDMETHOD(GetAdvise)(DWORD *pAspects, DWORD *pAdvf, IAdviseSink * *ppAdvSink); + STDMETHOD(GetExtent)(DWORD dwDrawAspect, LONG lindex, DVTARGETDEVICE __RPC_FAR *ptd, LPSIZEL lpsizel); + + // IQuickActivate methods + // + STDMETHOD(QuickActivate)(QACONTAINER *pqacontainer, QACONTROL *pqacontrol); + STDMETHOD(SetContentExtent)(LPSIZEL); + STDMETHOD(GetContentExtent)(LPSIZEL); + + HRESULT InPlaceActivate(BOOL lVerb); + void SetInPlaceVisible(BOOL fShow); + HWND CreateInPlaceWindow(int x, int y, BOOL fNoRedraw); + void DestroyWindow(); + + static tLuaControl *CreateLuaControl( + lua_State* L, + ITypeInfo* typeinfo, + int ref + ); +private: + IOleAdviseHolder *m_pOleAdviseHolder; // IOleObject::Advise holder object + IAdviseSink *m_pViewAdviseSink; // IViewAdvise sink for IViewObject2 + + IOleClientSite *m_pClientSite; // client site + IOleControlSite *m_pControlSite; // IOleControlSite ptr on client site + IOleInPlaceSite *m_pInPlaceSite; // IOleInPlaceSite for managing activation + IOleInPlaceFrame *m_pInPlaceFrame; // IOleInPlaceFrame ptr on client site + IOleInPlaceUIWindow *m_pInPlaceUIWindow; // for negotiating border space with client + ISimpleFrameSite *m_pSimpleFrameSite; // simple frame site + IDispatch *m_pDispAmbient; // ambient dispatch pointer + SIZEL m_Size; // the size of this control + RECT m_rcLocation; // where we at + HWND m_hwnd; // our window + HWND m_hwndParent; // our parent window + HRGN m_hRgn; + + unsigned m_fDirty:1; // does the control need to be resaved? + unsigned m_fInPlaceActive:1; // are we in place active or not? + unsigned m_fInPlaceVisible:1; // we are in place visible or not? + unsigned m_fUIActive:1; // are we UI active or not. + unsigned m_fCreatingWindow:1; // indicates if we're in CreateWindowEx or not + unsigned m_fUsingWindowRgn:1; // for SetObjectRects and clipping + unsigned m_fViewAdvisePrimeFirst: 1; // for IViewobject2::setadvise + unsigned m_fViewAdviseOnlyOnce: 1; // for iviewobject2::setadvise +}; + +class CEnumOLEVERB : public IEnumOLEVERB { + ULONG _refCount; + int _nextVerb; + const OLEVERB* _verbs; + int _size; +public: + CEnumOLEVERB(const OLEVERB* verbs, int size) : _refCount(0), + _nextVerb(0), _size(size), _verbs(verbs) { + } + ~CEnumOLEVERB() { } + ULONG _stdcall AddRef() { return ++_refCount; } + ULONG _stdcall Release() { + ULONG ret(_refCount); if(!ret) delete this; return ret; + } + HRESULT _stdcall QueryInterface(REFIID riid, void** ppv) { + if(!ppv) return E_POINTER; + if(riid == IID_IUnknown) *ppv = this; + else if(riid == IID_IEnumOLEVERB) *ppv = this; + else return *ppv = 0, E_NOINTERFACE; + return AddRef(), S_OK; + } + + static HRESULT CreateInstance(const OLEVERB* verbs, int size, + IUnknown* pOuter, REFIID riid, void** ppv) { + if(!ppv) return E_POINTER; + if(pOuter) return *ppv = 0, CLASS_E_NOAGGREGATION; + CEnumOLEVERB* pEnum = new CEnumOLEVERB(verbs, size); + pEnum->AddRef(); + HRESULT hr = pEnum->QueryInterface(riid, ppv); + pEnum->Release(); + return S_OK; + } + + static HRESULT CreateInstance(const OLEVERB* verbs, int size, + IEnumOLEVERB** ppEnumOLEVERB) { + return CreateInstance(verbs, size, 0, IID_IEnumOLEVERB, + reinterpret_cast(ppEnumOLEVERB)); + } + + HRESULT _stdcall Next(ULONG celt, OLEVERB* rgelt, ULONG* pceltFetched) { + if(!rgelt) return E_POINTER; + ULONG curPos(0); + for(int nextVerb(_nextVerb); (nextVerb < _size) && (curPos < celt); + ++nextVerb, ++curPos) { + rgelt[curPos] = _verbs[nextVerb]; + rgelt[curPos].lpszVerbName = static_cast( + CoTaskMemAlloc(lstrlenW(_verbs[nextVerb].lpszVerbName) * 2 + 2)); + lstrcpyW(rgelt[curPos].lpszVerbName, _verbs[nextVerb].lpszVerbName); + } + _nextVerb += curPos; + if(pceltFetched) *pceltFetched = curPos; + return (curPos == celt) ? S_OK : S_FALSE; + } + + HRESULT _stdcall Clone(IEnumOLEVERB** ppenum) { + HRESULT hr = CreateInstance(_verbs, _size, 0, IID_IEnumOLEVERB, + reinterpret_cast(ppenum)); + if(hr) return hr; + (*ppenum)->Skip(_nextVerb); + return S_OK; + } + + HRESULT _stdcall Reset() { + return _nextVerb = 0, S_OK; + } + + HRESULT _stdcall Skip(ULONG celt) { + _nextVerb = min(_size, _nextVerb + static_cast(celt)); + return S_OK; + } +}; + +#endif // __TLUACONTROL_H \ No newline at end of file diff --git a/luacom/tLuaDispatch.cpp b/luacom/tLuaDispatch.cpp new file mode 100644 index 00000000..17d69eed --- /dev/null +++ b/luacom/tLuaDispatch.cpp @@ -0,0 +1,778 @@ +/* + * tLuaDispatch.cpp + * + * Vinicius Almendra + */ + +// RCS Info +static char *rcsid = "$Id: tLuaDispatch.cpp,v 1.30 2004/11/25 13:40:01 fqueiroz Exp $"; +static char *rcsname = "$Name: $"; + + +#include "tLuaDispatch.h" +#include "tLuaCOM.h" +#include "tLuaCOMException.h" +#include "tCOMUtil.h" +#include "LuaAux.h" +#include "tUtil.h" + +extern "C" +{ +#include "LuaCompat.h" +} + +long tLuaDispatch::NEXT_ID = 0; + +tLuaDispatch::ProvideClassInfo2::ProvideClassInfo2(ITypeInfo* p_coclassinfo, + IUnknown* p_pUnk) +{ + coclassinfo = p_coclassinfo; + pUnk = p_pUnk; +} + +STDMETHODIMP tLuaDispatch::ProvideClassInfo2::QueryInterface( + REFIID riid, + void ** ppvObj) +{ + return pUnk->QueryInterface(riid, ppvObj); +} + +STDMETHODIMP_(unsigned long) tLuaDispatch::ProvideClassInfo2::AddRef(void) +{ + return pUnk->AddRef(); +} + +STDMETHODIMP_(unsigned long) tLuaDispatch::ProvideClassInfo2::Release(void) +{ + return pUnk->Release(); +} + + +STDMETHODIMP tLuaDispatch::ProvideClassInfo2::GetClassInfo(ITypeInfo** ppTypeInfo) +{ + *ppTypeInfo = coclassinfo; + coclassinfo->AddRef(); + + return S_OK; +} + +STDMETHODIMP tLuaDispatch::ProvideClassInfo2::GetGUID(DWORD dwGuidKind, + GUID * pGUID) +{ + ITypeInfo* source_typeinfo = NULL; + TYPEATTR *typeattr = NULL; + HRESULT hr = S_OK; + + if(!pGUID) + return E_POINTER; + + if(dwGuidKind == GUIDKIND_DEFAULT_SOURCE_DISP_IID) + { + source_typeinfo = + tCOMUtil::GetDefaultInterfaceTypeInfo(coclassinfo, true); + + if(!source_typeinfo) + return E_UNEXPECTED; + + hr = source_typeinfo->GetTypeAttr(&typeattr); + + if(FAILED(hr)) + { + source_typeinfo->Release(); + return E_UNEXPECTED; + } + + *pGUID = typeattr->guid; + + source_typeinfo->ReleaseTypeAttr(typeattr); + source_typeinfo->Release(); + } + else + return E_INVALIDARG; + + return S_OK; +} + + + + + +//--------------------------------------------------------------------- +// IUnknown Methods +//--------------------------------------------------------------------- + + +STDMETHODIMP +tLuaDispatch::QueryInterface(REFIID riid, void FAR* FAR* ppv) +{ + + if(IsEqualIID(riid, IID_IUnknown) || + IsEqualIID(riid, IID_IDispatch) || + IsEqualIID(riid, interface_iid)) { + *ppv = (IDispatch*)this; + AddRef(); + return NOERROR; + } + + if((IsEqualIID(riid, IID_IProvideClassInfo) || + IsEqualIID(riid, IID_IProvideClassInfo2) ) && + classinfo2) + { + *ppv = classinfo2; + classinfo2->AddRef(); + return NOERROR; + } + + if(IsEqualIID(riid, IID_IConnectionPointContainer) && + cpc) + { + *ppv = cpc; + cpc->AddRef(); + return NOERROR; + } + + if(IsEqualIID(riid, IID_ILuaDispatch)) + { + *ppv = (ILuaDispatch*)this; + AddRef(); + return NOERROR; + } + + *ppv = NULL; + return ResultFromScode(E_NOINTERFACE); +} + + +STDMETHODIMP_(unsigned long) +tLuaDispatch::AddRef() +{ + return ++m_refs; +} + + +STDMETHODIMP_(unsigned long) +tLuaDispatch::Release() +{ + assert(m_refs > 0); + if(--m_refs == 0) + { + // destrava tabela LUA + lua_unref(L, table_ref); + + // libera libs + + while(num_methods--) + { + typeinfo->ReleaseFuncDesc(funcinfo[num_methods].funcdesc); + delete funcinfo[num_methods].name; + } + + delete funcinfo; + typeinfo->Release(); + typeinfo = NULL; + + delete typehandler; + + if(cpc) + delete cpc; + + if(classinfo2) + delete classinfo2; + + // destroi objeto + delete this; + return 0; + } + + return m_refs; +} + + +//--------------------------------------------------------------------- +// IDispatch Methods +//--------------------------------------------------------------------- + + + +STDMETHODIMP +tLuaDispatch::GetTypeInfoCount(unsigned int FAR* pctinfo) +{ + *pctinfo = 1; + return NOERROR; +} + + +STDMETHODIMP +tLuaDispatch::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo) +{ + if(itinfo != 0) + return ResultFromScode(TYPE_E_ELEMENTNOTFOUND); + + if(pptinfo == NULL) + return ResultFromScode(E_POINTER); + + typeinfo->AddRef(); + *pptinfo = typeinfo; + + return NOERROR; +} + + +STDMETHODIMP +tLuaDispatch::GetIDsOfNames( + REFIID riid, + OLECHAR FAR* FAR* rgszNames, + unsigned int cNames, + LCID lcid, + DISPID FAR* rgdispid) +{ + // this object only exposes a "default" interface. + // + if(!IsEqualIID(riid, IID_NULL)) + return ResultFromScode(DISP_E_UNKNOWNINTERFACE); + + return DispGetIDsOfNames(typeinfo, rgszNames, cNames, rgdispid); +} + +STDMETHODIMP +tLuaDispatch::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + unsigned short wFlags, + DISPPARAMS FAR* pdispparams, + VARIANT FAR* pvarResult, + EXCEPINFO FAR* pexcepinfo, + unsigned int FAR* puArgErr) +{ + HRESULT hresult = 0; + int index = 0; + stkIndex member = -1; + int current_arg = 0; + HRESULT retval = NOERROR; + stkIndex return_value_pos = 0; + + if(wFlags & ~(DISPATCH_METHOD | DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT | + DISPATCH_PROPERTYPUTREF)) + return ResultFromScode(E_INVALIDARG); + + if(!IsEqualIID(riid, IID_NULL)) + return ResultFromScode(DISP_E_UNKNOWNINTERFACE); + + /* descobre qual o nome do metodo */ + + for(index = 0; index < num_methods; index++) + { + if(funcinfo[index].funcdesc->memid == dispidMember && + funcinfo[index].funcdesc->invkind & wFlags) + break; + } + + if(index >= num_methods) + { + tUtil::log_verbose("tLuaDispatch", "DISPID 0x%.8x not found.", + dispidMember); + return (ResultFromScode(DISP_E_MEMBERNOTFOUND)); + } + + // gets a reference to the implementation table + lua_getref(L, table_ref); + int implementation_table = lua_gettop(L); + + try + { + switch(wFlags) + { + case DISPATCH_METHOD: + retval = method( + funcinfo[index].name, + funcinfo[index].funcdesc, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + break; + + case DISPATCH_METHOD | DISPATCH_PROPERTYGET: + + // sometimes the caller can't tell the difference between + // a property get and a method call. We try first a + // method call and then, if it's not successful, try + // a property get + + { + HRESULT ret = method( + funcinfo[index].name, + funcinfo[index].funcdesc, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + if(ret != S_OK) + { + retval = propertyget( + funcinfo[index].name, + funcinfo[index].funcdesc, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + } + + } + break; + + case DISPATCH_PROPERTYGET: + + retval = propertyget( + funcinfo[index].name, + funcinfo[index].funcdesc, + pdispparams, + pvarResult, + pexcepinfo,puArgErr); + + break; + + case DISPATCH_PROPERTYPUT: + + retval = propertyput( + funcinfo[index].name, + pdispparams, + pvarResult, + pexcepinfo,puArgErr); + + break; + + case DISPATCH_PROPERTYPUTREF: + retval = DISP_E_EXCEPTION; + FillExceptionInfo(pexcepinfo, "Property putref not supported."); + break; + + default: // we can't arrive here unless for a bug... + retval = DISP_E_MEMBERNOTFOUND; + break; + } + } + catch(class tLuaCOMException& e) + { + retval = DISP_E_EXCEPTION; + FillExceptionInfo(pexcepinfo, e.getMessage()); + } + + // removes implementation table + lua_remove(L, implementation_table); + + if(retval == DISP_E_MEMBERNOTFOUND) + { + tUtil::log_verbose("tLuaDispatch", "Member '%s' not found (0x%.8x)", + funcinfo[index].name, dispidMember); + } + else + { + tUtil::log_verbose("tLuaDispatch", "Member '%s' called (0x%.8x)", + funcinfo[index].name, dispidMember); + } + + return retval; +} + +STDMETHODIMP tLuaDispatch::PushIfSameState(lua_State *p_L) { +#ifdef LUA4 + if(L == p_L) { + lua_getref(L, table_ref); + return S_OK; + } else return E_FAIL; +#else + lua_getref(p_L, table_ref); + if(lua_isnil(p_L, -1)) { + lua_pop(p_L,1); + return E_FAIL; + } + const void *p1 = lua_topointer(p_L, -1); + lua_getref(L, table_ref); + const void *p2 = lua_topointer(L, -1); + if(p1 == p2) { + lua_pop(L, 1); + return S_OK; + } else { + lua_pop(L, 1); + lua_pop(p_L, 1); + return E_FAIL; + } +#endif +} + +tLuaDispatch::tLuaDispatch(lua_State* p_L, ITypeInfo * pTypeinfo, int ref) +{ + HRESULT hr; + + L = p_L; + + // gets a locked reference to the implementation object + lua_getref(L, ref); + int locked_ref = lua_ref(L, 1); + table_ref = locked_ref; + + m_refs = 0; + + typeinfo = pTypeinfo; + + typeinfo->AddRef(); + + // inicializa conversor de tipos + typehandler = new tLuaCOMTypeHandler(typeinfo); + + { + TYPEATTR * ptypeattr = NULL; + FUNCDESC *funcdesc = NULL; + unsigned int i, n; + + hr = typeinfo->GetTypeAttr(&ptypeattr); + + CHECK(SUCCEEDED(hr), INTERNAL_ERROR); + + memcpy(&interface_iid, &ptypeattr->guid, sizeof(IID)); + + + /* Obtem todas as descricoes das funcoes e guarda-as em + uma tabela */ + + n = ptypeattr->cFuncs; + typeinfo->ReleaseTypeAttr(ptypeattr); + + funcinfo = new tFuncInfo[n]; + + num_methods = 0; + + for (i = 0; i < n;i++) + { + hr = typeinfo->GetFuncDesc(i, &funcdesc); + + CHECK(SUCCEEDED(hr) && funcdesc != NULL, INTERNAL_ERROR); + + // ignores functions not accessible via Automation + if(funcdesc->wFuncFlags & FUNCFLAG_FRESTRICTED) + continue; + + funcinfo[num_methods].funcdesc = funcdesc; + + BSTR names[1]; + unsigned int dumb; + typeinfo->GetNames(funcdesc->memid, names, 1, &dumb); + + const int str_size = SysStringLen(names[0]); + + funcinfo[num_methods].name = new char[str_size + 1]; + wcstombs(funcinfo[num_methods].name, names[0], str_size+1); + + num_methods++; + } + } + + cpc = NULL; + classinfo2 = NULL; + + ID = tLuaDispatch::NEXT_ID++; + tUtil::log_verbose("tLuaDispatch", "%.4d:created", ID); + + // agora sim esta' inicializado + + return; +} + + +tLuaDispatch * tLuaDispatch::CreateLuaDispatch(lua_State* L, + ITypeInfo* interface_typeinfo, + int ref + ) +{ + tLuaDispatch *pdisp = + new tLuaDispatch(L, interface_typeinfo, ref); + + lua_getref(L, ref); + luaCompat_pushPointer(L, idxDispatch); + luaCompat_pushPointer(L, pdisp); + lua_rawset(L,-3); + lua_pop(L, 1); + + pdisp->AddRef(); + + return pdisp; +} + +/* + * Fills an EXCEPINFO structure + * + */ + +void tLuaDispatch::FillExceptionInfo(EXCEPINFO *pexcepinfo, const char *text) +{ + CHECKPARAM(text); + + tUtil::log("tLuaDispatch", "Exception (%s)", text); + + if(!pexcepinfo) + return; + + pexcepinfo->wCode = 1000; + pexcepinfo->wReserved = 0; + pexcepinfo->bstrSource = tUtil::string2bstr("LuaCOM"); + pexcepinfo->bstrDescription = tUtil::string2bstr(text); + pexcepinfo->bstrHelpFile = NULL; + pexcepinfo->pvReserved = NULL; + pexcepinfo->pfnDeferredFillIn = NULL; + pexcepinfo->scode = 0; +} + + + +HRESULT tLuaDispatch::propertyget(const char* name, + FUNCDESC* funcdesc, + DISPPARAMS *pdispparams, + VARIANT *pvarResult, + EXCEPINFO *pexcepinfo, + unsigned int *puArgErr) +{ + /* le valor contido na tabela */ + lua_pushstring(L, name); + + lua_gettable(L, -2); + stkIndex member = lua_gettop(L); + + if(lua_isnil(L, member)) + { + lua_remove(L, member); + return DISP_E_MEMBERNOTFOUND; + } + + // if field holds a function, calls it passing the parameters + if(lua_isfunction(L, member)) + { + // first, the self parameter + lua_pushvalue(L, -2); + int i = pdispparams->cArgs; + + while(i--) + typehandler->com2lua(L, pdispparams->rgvarg[i]); + + const char* err = NULL; + luaCompat_call(L, pdispparams->cArgs + 1, 1, &err); + + if(err) + { + FillExceptionInfo(pexcepinfo, err); + return DISP_E_EXCEPTION; + } + } + + if(pdispparams->cArgs > 0) // propertyget parametrizado + { + if(lua_istable(L, member)) + { + lua_pushvalue(L, member); + typehandler->com2lua(L, pdispparams->rgvarg[pdispparams->cArgs - 1]); + + lua_gettable(L, -2); + member = lua_gettop(L); + } + else + { + // funciona como um propget normal, ignorando parametro + } + } + + /* converte resultado para COM */ + + if(pvarResult != NULL) + { + typehandler->setRetval(L, funcdesc, member, pvarResult); + } + + return S_OK; +} + + +HRESULT tLuaDispatch::propertyput(const char* name, + DISPPARAMS *pdispparams, + VARIANT *pvarResult, + EXCEPINFO *pexcepinfo, + unsigned int *puArgErr) +{ + // gets the current of the field + lua_pushstring(L, name); + lua_gettable(L, -2); + + // If field to be set holds a function, calls it passing the + // value to be set + if(lua_isfunction(L, -1)) + { + stkIndex function = lua_gettop(L); + + // first, the self param + lua_pushvalue(L, -2); + + // pushes all the arguments + int i = pdispparams->cArgs; + + while(i--) + typehandler->com2lua(L, pdispparams->rgvarg[i]); + + const char* err = NULL; + luaCompat_call(L, pdispparams->cArgs + 1, 0, &err); + + if(err) + { + FillExceptionInfo(pexcepinfo, err); + return DISP_E_EXCEPTION; + } + } + else if(pdispparams->cArgs == 1) // propput normal + { + lua_pop(L, 1); // removes value of the field + + lua_pushstring(L, name); + + // Valor a ser setado + typehandler->com2lua(L, pdispparams->rgvarg[pdispparams->cArgs - 1]); + + lua_settable(L, -3); + } + else if(pdispparams->cArgs == 2) // propertyput parametrizado + { + stkIndex member = lua_gettop(L); + + if(lua_istable(L, member) || lua_isuserdata(L, member)) // se for, + { + lua_pushvalue(L, member); + + // indice + typehandler->com2lua(L, pdispparams->rgvarg[pdispparams->cArgs - 1]); + + // Valor a ser setado + typehandler->com2lua(L, pdispparams->rgvarg[pdispparams->cArgs - 2]); + + lua_settable(L, -3); + } + else + { + FillExceptionInfo(pexcepinfo, "Parametrized property puts only " + "implemented for tables and userdata's."); + + return DISP_E_EXCEPTION; + } + } + else + { + FillExceptionInfo(pexcepinfo, "Property puts with more than two " + "parameters aren't supported."); + + return DISP_E_EXCEPTION; + } + + return S_OK; +} + + +HRESULT tLuaDispatch::method(const char* name, + FUNCDESC* funcdesc, + DISPPARAMS *pdispparams, + VARIANT *pvarResult, + EXCEPINFO *pexcepinfo, + unsigned int *puArgErr) +{ + // gets lua function from implementation table + lua_pushstring(L, name); + lua_gettable(L, -2); + + // stores position of the member function + stkIndex member = lua_gettop(L); + + // tests whether it's really a function + + if(!lua_isfunction(L, member)) + { + lua_remove(L, member); + return DISP_E_MEMBERNOTFOUND; + } + + /* converte parametros e empilha */ + + // parametro self + lua_getref(L, table_ref); + + // Parametros passados via COM + typehandler->pushLuaArgs( + L, + pdispparams, + funcdesc->lprgelemdescParam); + + // chama funcao lua + const char* errmsg = NULL; + int result = 0; + + result = luaCompat_call(L, lua_gettop(L) - member, LUA_MULTRET, &errmsg); + + if(result) + { + FillExceptionInfo(pexcepinfo, LuaAux::makeLuaErrorMessage(result, errmsg)); + + return DISP_E_EXCEPTION; + } + + + // return values will be put in the place of the function + // and beyond + stkIndex return_value_pos = member; + + if(lua_type(L, return_value_pos) != LUA_TNONE) + { + if(pvarResult != NULL && funcdesc->elemdescFunc.tdesc.vt != VT_VOID) + { + VARIANTARG result; + VariantInit(&result); + + typehandler->lua2com(L, return_value_pos, result, funcdesc->elemdescFunc.tdesc.vt); + + *pvarResult = result; + + return_value_pos++; + } + } + + // sets out values + if(lua_type(L, return_value_pos) != LUA_TNONE) + typehandler->setOutValues(L, funcdesc, pdispparams, return_value_pos); + + return S_OK; +} + +void tLuaDispatch::SetCoClassinfo(ITypeInfo *coclassinfo) +{ + classinfo2 = new ProvideClassInfo2(coclassinfo, (IDispatch*)this); + CHKMALLOC(classinfo2); +} + +void tLuaDispatch::BeConnectable(void) +{ + try + { + cpc = new tLuaCOMConnPointContainer(L, (IDispatch*)this); + } + catch(class tLuaCOMException& e) + { + UNUSED(e); + cpc = NULL; + } +} + +tLuaCOMConnPointContainer* tLuaDispatch::GetConnPointContainer() +{ + return cpc; +} + +tLuaDispatch::~tLuaDispatch() +{ + tUtil::log_verbose("tLuaDispatch", "%.4d:destroyed", ID); +} diff --git a/luacom/tLuaDispatch.h b/luacom/tLuaDispatch.h new file mode 100644 index 00000000..90939183 --- /dev/null +++ b/luacom/tLuaDispatch.h @@ -0,0 +1,154 @@ +/* + * tLuaDispatch.h + */ + +#ifndef __TLUADISPATCH_H +#define __TLUADISPATCH_H + +#include +//#include + +#include +#include + +#include +#include + +extern "C" +{ +#include "..\lua.h" +#include "..\lauxlib.h" +} + +#include "luabeans.h" +#include "tLuaCOMTypeHandler.h" +#include "tLuaCOMConnPoints.h" + +class ILuaDispatch : public IUnknown { +public: + STDMETHOD(PushIfSameState)(lua_State *L)=0; +}; + + +// {FE5AC331-0A3B-4093-A02F-41C39DDD06D8} +static const GUID IID_ILuaDispatch = +{ 0xfe5ac331, 0xa3b, 0x4093, { 0xa0, 0x2f, 0x41, 0xc3, 0x9d, 0xdd, 0x6, 0xd8 } }; + +static void *idxDispatch; + +class tLuaDispatch : public IDispatch, public ILuaDispatch +{ +public: + tLuaCOMConnPointContainer* GetConnPointContainer(void); + void BeConnectable(void); + void SetCoClassinfo(ITypeInfo* coclassinfo); + void FillExceptionInfo(EXCEPINFO *pexcepinfo, const char* text); + static tLuaDispatch * CreateLuaDispatch( + lua_State* L, + ITypeInfo* typeinfo, + int ref + ); + + tLuaDispatch(lua_State* L, ITypeInfo *pTypeinfo, int ref); + tLuaDispatch::~tLuaDispatch(); + + /* IUnknown methods */ + STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj); + STDMETHOD_(unsigned long, AddRef)(void); + STDMETHOD_(unsigned long, Release)(void); + + /* IDispatch methods */ + STDMETHOD(GetTypeInfoCount)(unsigned int FAR* pcTypeInfo); + + STDMETHOD(GetTypeInfo)( + unsigned int iTypeInfo, + LCID lcid, + ITypeInfo FAR* FAR* ppTypeInfo); + + STDMETHOD(GetIDsOfNames)( + REFIID riid, + OLECHAR FAR* FAR* rgszNames, + unsigned int cNames, + LCID lcid, + DISPID FAR* rgdispid); + + STDMETHOD(Invoke)( + DISPID dispidMember, + REFIID riid, + LCID lcid, + unsigned short wFlags, + DISPPARAMS FAR* pdispparams, + VARIANT FAR* pvarResult, + EXCEPINFO FAR* pexcepinfo, + unsigned int FAR* puArgErr); + + STDMETHOD(PushIfSameState)(lua_State *L); + + ITypeInfo *typeinfo; + +protected: + tLuaCOMConnPointContainer* cpc; + HRESULT propertyget( + const char* name, + FUNCDESC* funcdesc, + DISPPARAMS* pdispparams, + VARIANT* pvarResult, + EXCEPINFO* pexcepinfo, + unsigned int* puArgErr); + + HRESULT propertyput( + const char* name, + DISPPARAMS *pdispparams, + VARIANT *pvarResult, + EXCEPINFO *pexcepinfo, + unsigned int *puArgErr); + + HRESULT method( + const char* name, + FUNCDESC* funcdesc, + DISPPARAMS *pdispparams, + VARIANT *pvarResult, + EXCEPINFO *pexcepinfo, + unsigned int *puArgErr); + + lua_State* L; + IID interface_iid; + tLuaCOMTypeHandler * typehandler; + static int tag; + + unsigned long m_refs; + + struct tFuncInfo + { + FUNCDESC *funcdesc; + char *name; + } *funcinfo; + + class ProvideClassInfo2 : IProvideClassInfo2 + { + public: + ProvideClassInfo2(ITypeInfo* p_coclassinfo, IUnknown* p_pUnk); + + STDMETHODIMP_(unsigned long) AddRef(void); + STDMETHODIMP_(unsigned long) Release(void); + STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj); + STDMETHOD(GetClassInfo)(ITypeInfo** ppTypeInfo); + STDMETHOD(GetGUID)(DWORD dwGuidKind, GUID * pGUID); + + protected: + ITypeInfo* coclassinfo; + IUnknown* pUnk; + }; + + ProvideClassInfo2* classinfo2; + + int num_methods; + int table_ref; + +private: + static long NEXT_ID; + long ID; + +}; + +#endif // __TLUADISPATCH_H \ No newline at end of file diff --git a/luacom/tLuaObjList.cpp b/luacom/tLuaObjList.cpp new file mode 100644 index 00000000..e145557e --- /dev/null +++ b/luacom/tLuaObjList.cpp @@ -0,0 +1,41 @@ +// tLuaObjList.cpp: implementation of the tLuaObjList class. +// +////////////////////////////////////////////////////////////////////// + +#include "tLuaObjList.h" +#include "tLuaCOMException.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + + +tLuaObjList::tLuaObjList(stkIndex first_param_pos, long num_params_p) +{ + CHECKPARAM(first_param_pos >= 0 && num_params_p >= 0); + + first_param = first_param_pos; + num_params = num_params_p; + +} + +tLuaObjList::tLuaObjList(void) +{ + first_param = 0; + num_params = 0; +} + +stkIndex tLuaObjList::getparam(long i) +{ + CHECKPARAM(i >= 0); + + if(i < num_params) + return first_param + i; + else + return 0; +} + +long tLuaObjList::getNumParams() +{ + return num_params; +} diff --git a/luacom/tLuaObjList.h b/luacom/tLuaObjList.h new file mode 100644 index 00000000..67674efb --- /dev/null +++ b/luacom/tLuaObjList.h @@ -0,0 +1,32 @@ +// tLuaObjList.h: interface for the tLuaObjList class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_TLUAOBJLIST_H__D9585072_945D_11D4_B881_0000B45D7541__INCLUDED_) +#define AFX_TLUAOBJLIST_H__D9585072_945D_11D4_B881_0000B45D7541__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#include "..\lua.h" + +#include "tUtil.h" +#include "LuaAux.h" + +class tLuaObjList +{ +protected: + stkIndex first_param; + long num_params; + +public: + long getNumParams(void); + + tLuaObjList(stkIndex first_param_pos, long num_params_p); + tLuaObjList(void); + + stkIndex getparam(long i); +}; + +#endif // !defined(AFX_TLUAOBJLIST_H__D9585072_945D_11D4_B881_0000B45D7541__INCLUDED_) diff --git a/luacom/tLuaObject.cpp b/luacom/tLuaObject.cpp new file mode 100644 index 00000000..cab2733b --- /dev/null +++ b/luacom/tLuaObject.cpp @@ -0,0 +1,331 @@ +// tLuaObject.cpp: implementation of the tLuaObject class. +// +////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "tLuaObject.h" +#include "LuaAux.h" +#include "tLuaCOMException.h" +#include "luacom_internal.h" +#include "tUtil.h" + +extern "C" +{ +#include "LuaCompat.h" +} + +#ifndef MODULENAME +#define MODULENAME "__tLuaObject_object_types" +#endif + +const char TLUAOBJECT_POINTER_FIELD[] = "__TLUAOBJECT_pointer__"; + + +int tLuaObject::garbagecollect(lua_State *L) +{ + tLuaObject* lua_obj = (tLuaObject*) luaCompat_getTypedObject(L, -1); + + delete lua_obj; + + return 0; +} + +tLuaObject* tLuaObject::getObject(lua_State *L, int pos) +{ + LUASTACK_SET(L); + + if(pos < 0) + pos += lua_gettop(L) + 1; + + // gets lua object + lua_pushstring(L, TLUAOBJECT_POINTER_FIELD); + lua_rawget(L, pos); + tLuaObject* lua_obj = (tLuaObject*) luaCompat_getTypedObject(L, -1); + lua_pop(L, 1); + + LUASTACK_CLEAN(L, 0); + + return lua_obj; +} + +int tLuaObject::generic_index(lua_State *L) +{ + tLuaObject* lua_obj = tLuaObject::getObject(L, index_table_param); + + // gets the field name + const char* field_name = lua_tostring(L, index_index_param); + + // finds in the method table + tMethodType method_type; + tLuaObjectMethod method; + + bool found = lua_obj->method_table.FindMethod(field_name, &method, &method_type); + if(!found) + return lua_obj->index(L); + + // calls method + switch(method_type) + { + case FUNC: + luaCompat_pushPointer(L, (void *) method); + lua_pushcclosure(L, closure, 1); + return 1; + break; + + default: + return method(lua_obj, L); + break; + } +} + +int tLuaObject::generic_newindex(lua_State *L) +{ + lua_rawset(L, -3); + + // must avoid redefinition of pointer field + return 0; +} + + + +int tLuaObject::generic_PushNew(lua_State* L, + tLuaObject* lua_obj, + const char* type_name, + const char* pointer_type_name + ) +{ + LUASTACK_SET(L); + + // creates table + lua_newtable(L); + luaCompat_pushTypeByName(L, MODULENAME, type_name); + + luaCompat_setType(L, -2); + + lua_pushstring(L, TLUAOBJECT_POINTER_FIELD); + + // pushes typed pointer + luaCompat_pushTypeByName(L, MODULENAME, pointer_type_name); + + luaCompat_newTypedObject(L, lua_obj); + + // stores in the table + lua_settable(L, -3); + + LUASTACK_CLEAN(L, 1); + + return 1; +} + +void tLuaObject::RegisterType(lua_State* L, + const char* type_name, + const char* pointer_type_name) +{ + LUASTACK_SET(L); + + luaCompat_moduleCreate(L, MODULENAME); + lua_pop(L, 1); + + // Registers the table type and the pointer type + luaCompat_newLuaType(L, MODULENAME, type_name); + + luaCompat_newLuaType(L, MODULENAME, pointer_type_name); + +#ifdef LUA5 + // Registers the weak table to store the pairs + // (pointer, LuaObject) to avoid duplication + // of Lua objects. This step must be done + // only once + luaCompat_moduleGet(L, MODULENAME, INSTANCES_CACHE); + + if(lua_isnil(L, -1)) + { + lua_pop(L, 1); + // pushes tables + lua_newtable(L); + + // pushes metatable and initializes it + lua_newtable(L); + lua_pushstring(L, "__mode"); + lua_pushstring(L, "v"); + lua_settable(L, -3); + lua_setmetatable(L, -2); + + // stores in the registry + luaCompat_moduleSet(L, MODULENAME, INSTANCES_CACHE); + } + else + lua_pop(L, 1); +#endif + + luaCompat_pushTypeByName(L, MODULENAME, type_name); + + lua_pushcfunction(L, tLuaObject::generic_index); + luaCompat_handleNoIndexEvent(L); + + lua_pushcfunction(L, tLuaObject::generic_newindex); + luaCompat_handleSettableEvent(L); + + lua_pop(L, 1); + + luaCompat_pushTypeByName(L, MODULENAME, pointer_type_name); + + lua_pushcfunction(L, tLuaObject::garbagecollect); + luaCompat_handleGCEvent(L); + + lua_pop(L, 1); + + LUASTACK_CLEAN(L, 0); +} + +int tLuaObject::index(lua_State* L) +{ + lua_rawget(L, -2); + return 1; +} + +int tLuaObject::newindex(lua_State* L) +{ + lua_rawset(L, -3); + return 0; +} + +int tLuaObject::closure(lua_State *L) +{ + tLuaObjectMethod method = (tLuaObjectMethod) + luaCompat_getPointer(L, luaCompat_upvalueIndex(L, 1, 1)); + + tLuaObject* lua_obj = getObject(L, 1); + + if(lua_obj == NULL) + { + luacom_error(L, "Error: self parameter is not a tLuaObject."); + return 0; + } + + int retval = 0; + + try + { + retval = method(lua_obj, L); + } + catch(class tLuaCOMException& e) + { + luacom_error(L, e.getMessage()); + + return 0; + } + + return retval; +} + + +/////////////////////////////////////////// +// tLuaObject::MethodTable +/////////////////////////////////////////// + +bool tLuaObject::MethodTable::Add(const char* name, + tLuaObjectMethod m, + tMethodType type) +{ + CHECKPRECOND(name && m); + + if(num_methods >= MAX_METHODS) + return false; + + method_list[num_methods].name = name; + method_list[num_methods].method = m; + method_list[num_methods].type = type; + + num_methods++; + + return true; +} + +bool tLuaObject::MethodTable::FindMethod(const char* name, + tLuaObjectMethod* p_m, + tMethodType* ptype) +{ + for(int i = 0; i < num_methods; i++) + { + if(strcmp(name, method_list[i].name) == 0) + { + *p_m = method_list[i].method; + *ptype = method_list[i].type; + + return true; + } + } + + return false; +} + +bool tLuaObject::MethodTable::GetNthMethod(long i, + const char **name, + tLuaObjectMethod* p_m, + tMethodType* ptype) +{ + if(i < 0 || i >= num_methods) + return false; + else + { + *name = method_list[i].name; + *p_m = method_list[i].method; + *ptype = method_list[i].type; + } + + return true; +} + + +tLuaObject::MethodTable::MethodTable() +{ + num_methods = 0; +} + +bool tLuaObject::pushCachedObject(lua_State *L, void *pointer) +{ + LUASTACK_SET(L); + +#ifdef LUA5 + luaCompat_moduleGet(L, MODULENAME, INSTANCES_CACHE); + + lua_pushlightuserdata(L, pointer); + lua_gettable(L, -2); + + lua_remove(L, -2); + + if(lua_isnil(L, -1)) + { + lua_pop(L, 1); + + LUASTACK_CLEAN(L, 0); + return false; + } + + LUASTACK_CLEAN(L, 1); + + return true; +#else + return false; +#endif +} + +void tLuaObject::cacheObject(lua_State *L, void* pointer) +{ + LUASTACK_SET(L); + +#ifdef LUA5 + luaCompat_moduleGet(L, MODULENAME, INSTANCES_CACHE); + + lua_pushlightuserdata(L, pointer); + lua_pushvalue(L, -3); + lua_settable(L, -3); + + lua_remove(L, -1); +#endif + + LUASTACK_CLEAN(L, 0); +} diff --git a/luacom/tLuaObject.h b/luacom/tLuaObject.h new file mode 100644 index 00000000..613e50da --- /dev/null +++ b/luacom/tLuaObject.h @@ -0,0 +1,100 @@ +// tLuaObject.h: interface for the tLuaObject class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_TLUAOBJECT_H__459DE88B_29C0_4245_AEA7_122F2749F202__INCLUDED_) +#define AFX_TLUAOBJECT_H__459DE88B_29C0_4245_AEA7_122F2749F202__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +extern "C" +{ +#include "..\lua.h" +} + +#define index_table_param -2 +#define index_index_param -1 + +#define newindex_table_param -3 +#define newindex_index_param -2 +#define newindex_value_param -1 + + +#define INSTANCES_CACHE "__luacom_instances_cache" + + +class tLuaObject; + +typedef int (*tLuaObjectMethod) (tLuaObject* lua_object, lua_State *L); + +typedef enum +{ + GET, + SET, + FUNC +} tMethodType; + +#define MAX_METHODS 40 + +class tLuaObject +{ +public: + static void cacheObject(lua_State* L, void* pointer); + static bool pushCachedObject(lua_State* L, void* pointer); + + class MethodTable + { + public: + MethodTable(); + bool Add(const char* name, tLuaObjectMethod m, tMethodType type); + + bool FindMethod(const char* name, + tLuaObjectMethod* p_m, + tMethodType* ptype); + + bool GetNthMethod(long i, + const char **name, + tLuaObjectMethod* p_m, + tMethodType* ptype); + + + protected: + struct tMethodList + { + const char* name; + tLuaObjectMethod method; + tMethodType type; + } method_list[MAX_METHODS]; + + long num_methods; + } method_table; + +protected: + static int closure(lua_State* L); + virtual int newindex(lua_State* L); + virtual int index(lua_State* L); + + static void RegisterType(lua_State* L, + const char* type_name, + const char* pointer_type_name + ); + + static int generic_PushNew(lua_State* L, + tLuaObject* lua_obj, + const char* type_name, + const char* pointer_type_name + ); + + static tLuaObject* getObject(lua_State* L, int pos); + +private: + static int garbagecollect(lua_State* L); + static int generic_index(lua_State* L); + static int generic_newindex(lua_State* L); +}; + + + +#endif // !defined(AFX_TLUAOBJECT_H__459DE88B_29C0_4245_AEA7_122F2749F202__INCLUDED_) diff --git a/luacom/tLuaTLB.cpp b/luacom/tLuaTLB.cpp new file mode 100644 index 00000000..04b3baae --- /dev/null +++ b/luacom/tLuaTLB.cpp @@ -0,0 +1,858 @@ +// tLuaTLB.cpp: implementation of the tLuaTLB class. +// +////////////////////////////////////////////////////////////////////// + +#include "tLuaTLB.h" + +#include "tCOMUtil.h" +#include "tLuaCOMException.h" +#include "tUtil.h" +#include "luacom_internal.h" +#include "LuaAux.h" + +#include "tLuaCOM.h" +#include "tLuaCOMTypeHandler.h" + +extern "C" +{ +#include "LuaCompat.h" +} + +#pragma warning(disable: 4018 4244) + + +const char tLuaTLB::type_name[] = "ITypeLib"; +const char tLuaTLB::pointer_type_name[] = "ITypeLib_pointer"; + +const char tLuaTypeInfo::type_name[] = "ITypeInfo"; +const char tLuaTypeInfo::pointer_type_name[] = "ITypeInfo_pointer"; + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +tLuaTLB::tLuaTLB(lua_State* L, ITypeLib *p_typelib) +{ + method_table.Add("ShowHelp", ShowHelp, FUNC); + method_table.Add("GetDocumentation", GetDocumentation, FUNC); + method_table.Add("GetTypeInfo", GetTypeInfo, FUNC); + method_table.Add("GetTypeInfoCount", GetTypeInfoCount, FUNC); + method_table.Add("ExportConstants", ExportConstants, FUNC); + method_table.Add("ExportEnumerations", ExportEnumerations, FUNC); + + typelib = p_typelib; + typelib->AddRef(); +} + +tLuaTLB::~tLuaTLB() +{ + COM_RELEASE(typelib); +} + +int tLuaTLB::index(lua_State* L) +{ + return 0; +} + +int tLuaTLB::pushNew(lua_State *L, ITypeLib *p_typelib) +{ + CHECKPRECOND(p_typelib); + + // tests whether we have a cached instance + if(pushCachedObject(L, p_typelib)) + return 1; + + LUASTACK_SET(L); + + tLuaTLB* lua_tlb = new tLuaTLB(L, p_typelib); + + int retval = generic_PushNew(L, lua_tlb, type_name, pointer_type_name); + cacheObject(L, (void*) p_typelib); + + LUASTACK_CLEAN(L, 1); + + return retval; +} + +int tLuaTLB::GetTypeInfoCount(tLuaObject* lua_obj, lua_State* L) +{ + tLuaTLB* lua_tlb = dynamic_cast(lua_obj); + + CHECKPRECOND(lua_tlb); + + int count = lua_tlb->typelib->GetTypeInfoCount(); + + lua_pushnumber(L, count); + + return 1; +} + +int tLuaTLB::GetTypeInfo(tLuaObject* lua_obj, lua_State* L) +{ + tLuaTLB* lua_tlb = dynamic_cast(lua_obj); + CHECKPRECOND(lua_tlb); + + int typeinfo_pos = (int)lua_tonumber(L, 2); + + ITypeInfo* typeinfo = NULL; + HRESULT hr = lua_tlb->typelib->GetTypeInfo(typeinfo_pos , &typeinfo); + + CHK_COM_CODE(hr); + + tLuaTypeInfo::pushNew(L, typeinfo); + COM_RELEASE(typeinfo); + + return 1; +} + +int tLuaTLB::GetDocumentation(tLuaObject* lua_obj, lua_State* L) +{ + tLuaTLB* lua_tlb = dynamic_cast(lua_obj); + + CHECKPRECOND(lua_tlb); + + HRESULT hr = S_OK; + BSTR name; + BSTR helpstring; + BSTR helpfile; + ULONG helpcontext; + + hr = lua_tlb->typelib->GetDocumentation(-1, + &name, &helpstring, &helpcontext, &helpfile); + + CHK_COM_CODE(hr); + + lua_newtable(L); + + lua_pushstring(L, "name"); + lua_pushstring(L, tUtil::bstr2string(name)); + lua_settable(L, -3); + + lua_pushstring(L, "helpstring"); + lua_pushstring(L, tUtil::bstr2string(helpstring)); + lua_settable(L, -3); + + lua_pushstring(L, "helpfile"); + lua_pushstring(L, tUtil::bstr2string(helpfile)); + lua_settable(L, -3); + + lua_pushstring(L, "helpcontext"); + lua_pushnumber(L, helpcontext); + lua_settable(L, -3); + + SysFreeString(name); + SysFreeString(helpstring); + SysFreeString(helpfile); + + return 1; +} + +int tLuaTLB::ShowHelp(tLuaObject* lua_obj, lua_State* L) +{ + tLuaTLB* lua_tlb = + dynamic_cast(lua_obj); + + CHECKPRECOND(lua_tlb); + + HRESULT hr = S_OK; + BSTR helpfile; + ULONG helpcontext; + + hr = lua_tlb->typelib->GetDocumentation( + -1, NULL, NULL, &helpcontext, &helpfile); + + CHK_COM_CODE(hr); + + tUtil::ShowHelp(tUtil::bstr2string(helpfile), helpcontext); + + SysFreeString(helpfile); + + return 0; +} + +int tLuaTLB::ExportConstants(tLuaObject* lua_obj, lua_State* L) +{ + tLuaTLB* lua_tlb = dynamic_cast(lua_obj); + CHECKPRECOND(lua_tlb); + CHECKPARAM(lua_type(L, -1) == LUA_TTABLE); + + TYPEKIND tkind; + ITypeInfo* ptypeinfo = NULL; + VARDESC* pvardesc = NULL; + TYPEATTR* ptypeattr = NULL; + BSTR name; + HRESULT hr = S_OK; + tLuaCOMTypeHandler* typehandler = NULL; + + long count = lua_tlb->typelib->GetTypeInfoCount(); + + while(count--) + { + lua_tlb->typelib->GetTypeInfoType(count, &tkind); + + if(tkind == TKIND_ENUM) + { + hr = lua_tlb->typelib->GetTypeInfo(count, &ptypeinfo); + CHK_COM_CODE(hr); + + typehandler = new tLuaCOMTypeHandler(ptypeinfo); + + hr = ptypeinfo->GetTypeAttr(&ptypeattr); + CHK_COM_CODE(hr); + + long var_count = ptypeattr->cVars; + + ptypeinfo->ReleaseTypeAttr(ptypeattr); + ptypeattr = NULL; + + while(var_count--) + { + hr = ptypeinfo->GetVarDesc(var_count, &pvardesc); + CHK_COM_CODE(hr); + + ptypeinfo->GetDocumentation(pvardesc->memid, &name, NULL, NULL, NULL); + + lua_pushstring(L, tUtil::bstr2string(name)); + SysFreeString(name); + + typehandler->com2lua(L, *pvardesc->lpvarValue); + + // sets in the table + lua_settable(L, -3); + + ptypeinfo->ReleaseVarDesc(pvardesc); + pvardesc = NULL; + } + + SAFEDELETE(typehandler); + COM_RELEASE(ptypeinfo); + } + } + + return 1; +} + + +int tLuaTLB::ExportEnumerations(tLuaObject* lua_obj, lua_State* L) +{ + tLuaTLB* lua_tlb = dynamic_cast(lua_obj); + CHECKPRECOND(lua_tlb); + if(lua_gettop(L) == 0) + lua_newtable(L); + else CHECKPARAM(lua_type(L, -1) == LUA_TTABLE); + + TYPEKIND tkind; + ITypeInfo* ptypeinfo = NULL; + VARDESC* pvardesc = NULL; + TYPEATTR* ptypeattr = NULL; + BSTR name; + HRESULT hr = S_OK; + tLuaCOMTypeHandler* typehandler = NULL; + + long count = lua_tlb->typelib->GetTypeInfoCount(); + + while(count--) + { + lua_tlb->typelib->GetTypeInfoType(count, &tkind); + + if(tkind == TKIND_ENUM) + { + + hr = lua_tlb->typelib->GetTypeInfo(count, &ptypeinfo); + CHK_COM_CODE(hr); + + hr = lua_tlb->typelib->GetDocumentation(count, &name, NULL, NULL, NULL); + CHK_COM_CODE(hr); + lua_pushstring(L, tUtil::bstr2string(name)); + SysFreeString(name); + lua_newtable(L); + + typehandler = new tLuaCOMTypeHandler(ptypeinfo); + + hr = ptypeinfo->GetTypeAttr(&ptypeattr); + CHK_COM_CODE(hr); + + long var_count = ptypeattr->cVars; + + ptypeinfo->ReleaseTypeAttr(ptypeattr); + ptypeattr = NULL; + + while(var_count--) + { + hr = ptypeinfo->GetVarDesc(var_count, &pvardesc); + CHK_COM_CODE(hr); + + ptypeinfo->GetDocumentation(pvardesc->memid, &name, NULL, NULL, NULL); + + lua_pushstring(L, tUtil::bstr2string(name)); + SysFreeString(name); + + typehandler->com2lua(L, *pvardesc->lpvarValue); + + // sets in the table + lua_settable(L, -3); + + ptypeinfo->ReleaseVarDesc(pvardesc); + pvardesc = NULL; + } + + lua_settable(L, -3); + + SAFEDELETE(typehandler); + COM_RELEASE(ptypeinfo); + } + } + + return 1; +} + + + +//////////////////////// +// tLuaTypeInfo class // +//////////////////////// + + +tLuaTypeInfo::tLuaTypeInfo(lua_State* L, ITypeInfo *p_typeinfo) +{ + method_table.Add("GetTypeLib", GetTypeLib, FUNC); + method_table.Add("GetFuncDesc", GetFuncDesc, FUNC); + method_table.Add("GetVarDesc", GetVarDesc, FUNC); + method_table.Add("GetDocumentation", GetDocumentation, FUNC); + method_table.Add("GetTypeAttr", GetTypeAttr, FUNC); + method_table.Add("GetImplType", GetImplType, FUNC); + method_table.Add("GetImplTypeFlags", GetImplTypeFlags, FUNC); + + typeinfo = p_typeinfo; + typeinfo->AddRef(); + + typehandler = new tLuaCOMTypeHandler(p_typeinfo); +} + +tLuaTypeInfo::~tLuaTypeInfo() +{ + delete typehandler; + COM_RELEASE(typeinfo); +} + + +void tLuaTypeInfo::pushNew(lua_State *L, ITypeInfo *p_typeinfo) +{ + CHECKPRECOND(p_typeinfo); + + // tests whether we have a cached instance + if(pushCachedObject(L, p_typeinfo)) + return; + + tLuaTypeInfo* lua_typeinfo = new tLuaTypeInfo(L, p_typeinfo); + generic_PushNew(L, lua_typeinfo, type_name, pointer_type_name); + cacheObject(L, (void*) p_typeinfo); + + return; +} + +void tLuaTLB::Init(lua_State* L) +{ + RegisterType(L, type_name, pointer_type_name); + tLuaTypeInfo::Init(L); +} + + +void tLuaTypeInfo::Init(lua_State* L) +{ + RegisterType(L, type_name, pointer_type_name); +} + +int tLuaTypeInfo::GetFuncDesc(tLuaObject* lua_obj, lua_State* L) +{ + LUASTACK_SET(L); + + HRESULT hr = S_OK; + + tLuaTypeInfo* lua_typeinfo = dynamic_cast(lua_obj); + CHECKPRECOND(lua_typeinfo); + + // we just deal with oleautomation-compatible interfaces + unsigned short flags = 0 ; + { + TYPEATTR* ptypeattr = NULL; + + hr = lua_typeinfo->typeinfo->GetTypeAttr(&ptypeattr); + CHK_COM_CODE(hr); + + flags = ptypeattr->wTypeFlags; + + lua_typeinfo->typeinfo->ReleaseTypeAttr(ptypeattr); + + if(!(flags & TYPEFLAG_FDISPATCHABLE)) + return 0; + } + + // gets funcdesc + + FUNCDESC* pfuncdesc = NULL; + { + int i = lua_tonumber(L, 2); + + hr = lua_typeinfo->typeinfo->GetFuncDesc(i, &pfuncdesc); + CHK_COM_CODE(hr); + } + + if(pfuncdesc->wFuncFlags & FUNCFLAG_FRESTRICTED) + { + lua_typeinfo->typeinfo->ReleaseFuncDesc(pfuncdesc); + return 0; + } + + // creates table to hold the funcdesc + lua_newtable(L); + + // stores the various fields + lua_pushstring(L, "memid"); + lua_pushnumber(L, pfuncdesc->memid); + lua_settable(L, -3); + + lua_pushstring(L, "invkind"); + lua_pushstring(L, tCOMUtil::getPrintableInvokeKind(pfuncdesc->invkind)); + lua_settable(L, -3); + + lua_pushstring(L, "Params"); + lua_pushnumber(L, pfuncdesc->cParams); + lua_settable(L, -3); + + lua_pushstring(L, "ParamsOpt"); + lua_pushnumber(L, pfuncdesc->cParamsOpt); + lua_settable(L, -3); + + // gets all the names + BSTR* names = new BSTR[pfuncdesc->cParams+1]; + UINT found = 0; + + // gets the name of the functions and the names of the + // parameters + lua_typeinfo->typeinfo->GetNames( + pfuncdesc->memid, names, pfuncdesc->cParams+1, &found); + + lua_pushstring(L, "name"); + lua_pushstring(L, tUtil::bstr2string(names[0])); + lua_settable(L, -3); + + SysFreeString(names[0]); + + // gets other documentation + { + BSTR description, helpfile; + ULONG helpcontext; + + lua_typeinfo->typeinfo->GetDocumentation( + pfuncdesc->memid, NULL, &description, &helpcontext, &helpfile); + + lua_pushstring(L, "description"); + lua_pushstring(L, tUtil::bstr2string(description)); + lua_settable(L, -3); + + lua_pushstring(L, "helpfile"); + lua_pushstring(L, tUtil::bstr2string(helpfile)); + lua_settable(L, -3); + + lua_pushstring(L, "helpcontext"); + lua_pushnumber(L, helpcontext); + lua_settable(L, -3); + + SysFreeString(description); + SysFreeString(helpfile); + } + + // now stores information for each parameter (if + // this is an oleautomation interface + + // table to hold all parameters and stores it + lua_newtable(L); + lua_pushstring(L, "parameters"); + lua_pushvalue(L, -2); + lua_settable(L, -4); + + int i = 0; + + while(i < pfuncdesc->cParams) + { + // creates table to hold information for this parameter + lua_newtable(L); + lua_pushvalue(L, -1); + lua_rawseti(L, -3, i+1); + + // gets the name + lua_pushstring(L, "name"); + + if((i+1) < found) + { + lua_pushstring(L, tUtil::bstr2string(names[i+1])); + SysFreeString(names[i+1]); + } + else + { + char buffer[50]; + sprintf(buffer, "p%d", i+1); + lua_pushstring(L, buffer); + } + + lua_settable(L, -3); + + // gets the type + TYPEDESC tdesc = pfuncdesc->lprgelemdescParam[i].tdesc; + bool incompatible_type = false; + + try + { + tdesc = + tLuaCOMTypeHandler::processTYPEDESC(lua_typeinfo->typeinfo, tdesc); + } + catch(class tLuaCOMException& e) + { + UNUSED(e); + incompatible_type = true; + } + + if(!incompatible_type) + { + lua_pushstring(L, "type"); + lua_pushstring(L, tCOMUtil::getPrintableTypeDesc(tdesc)); + lua_settable(L, -3); + } + + USHORT paramFlags = pfuncdesc->lprgelemdescParam[i].paramdesc.wParamFlags; + + lua_pushstring(L, "in"); + luaCompat_pushBool(L,paramFlags & PARAMFLAG_FIN); + lua_settable(L, -3); + + lua_pushstring(L, "out"); + luaCompat_pushBool(L,paramFlags & PARAMFLAG_FOUT); + lua_settable(L, -3); + + lua_pushstring(L, "opt"); + luaCompat_pushBool(L,paramFlags & PARAMFLAG_FOPT); + lua_settable(L, -3); + + lua_pushstring(L, "default"); + if(paramFlags & PARAMFLAG_FHASDEFAULT) { + lua_typeinfo->typehandler->com2lua(L,pfuncdesc->lprgelemdescParam[i].paramdesc.pparamdescex->varDefaultValue); + } else lua_pushnil(L); + lua_settable(L, -3); + + // removes copy of the table + lua_pop(L, 1); + + i++; + } + + // removes copy of the table + lua_pop(L, 1); + + SAFEDELETEARR(names); + + // Stores the type for the return value + TYPEDESC tdesc = pfuncdesc->elemdescFunc.tdesc; + bool incompatible_type = false; + + try + { + tdesc = + tLuaCOMTypeHandler::processTYPEDESC(lua_typeinfo->typeinfo, tdesc); + } + catch(class tLuaCOMException& e) + { + UNUSED(e); + incompatible_type = true; + } + + if(!incompatible_type) + { + lua_pushstring(L, "type"); + lua_pushstring(L, tCOMUtil::getPrintableTypeDesc(tdesc)); + lua_settable(L, -3); + } + + lua_typeinfo->typeinfo->ReleaseFuncDesc(pfuncdesc); + + LUASTACK_CLEAN(L, 1); + + return 1; +} + + +int tLuaTypeInfo::GetVarDesc(tLuaObject* lua_obj, lua_State* L) +{ + LUASTACK_SET(L); + + HRESULT hr = S_OK; + + tLuaTypeInfo* lua_typeinfo = dynamic_cast(lua_obj); + CHECKPRECOND(lua_typeinfo); + + // gets vardesc + + VARDESC* pvardesc = NULL; + { + int i = lua_tonumber(L, 2); + + hr = lua_typeinfo->typeinfo->GetVarDesc(i, &pvardesc); + CHK_COM_CODE(hr); + } + + // table to hold the vardesc + lua_newtable(L); + + // stores variable name + lua_pushstring(L, "name"); + { + BSTR name; + lua_typeinfo->typeinfo->GetDocumentation( + pvardesc->memid, &name, NULL, NULL, NULL); + + lua_pushstring(L, tUtil::bstr2string(name)); + SysFreeString(name); + } + lua_settable(L, -3); + + // if it is a constant, stores it's value + if(pvardesc->varkind == VAR_CONST) + { + lua_pushstring(L, "value"); + + lua_typeinfo->typehandler->com2lua(L, *pvardesc->lpvarValue); + + // sets in the table + lua_settable(L, -3); + } + + lua_typeinfo->typeinfo->ReleaseVarDesc(pvardesc); + pvardesc = NULL; + + LUASTACK_CLEAN(L, 1); + + return 1; +} + +int tLuaTypeInfo::GetImplType(tLuaObject* lua_obj, lua_State* L) +{ + LUASTACK_SET(L); + + HRESULT hr = S_OK; + + tLuaTypeInfo* lua_typeinfo = dynamic_cast(lua_obj); + CHECKPRECOND(lua_typeinfo); + + // gets implemented type + + ITypeInfo* ptinfo = NULL; + { + int i = lua_tonumber(L, 2); + + HREFTYPE hreftype; + hr = lua_typeinfo->typeinfo->GetRefTypeOfImplType(i, &hreftype); + CHK_COM_CODE(hr); + + hr = lua_typeinfo->typeinfo->GetRefTypeInfo(hreftype, &ptinfo); + CHK_COM_CODE(hr); + } + + tLuaTypeInfo::pushNew(L, ptinfo); + COM_RELEASE(ptinfo); + + LUASTACK_CLEAN(L, 1); + + return 1; +} + +int tLuaTypeInfo::GetImplTypeFlags(tLuaObject* lua_obj, lua_State* L) +{ + LUASTACK_SET(L); + + HRESULT hr = S_OK; + + tLuaTypeInfo* lua_typeinfo = dynamic_cast(lua_obj); + CHECKPRECOND(lua_typeinfo); + + int typeflags = 0; + int i = lua_tonumber(L, 2); + + hr = lua_typeinfo->typeinfo->GetImplTypeFlags(i, &typeflags); + CHK_COM_CODE(hr); + + lua_newtable(L); + + lua_pushstring(L, "default"); + luaCompat_pushBool(L, typeflags & IMPLTYPEFLAG_FDEFAULT); + lua_settable(L, -3); + + lua_pushstring(L, "source"); + luaCompat_pushBool(L, typeflags & IMPLTYPEFLAG_FSOURCE); + lua_settable(L, -3); + + lua_pushstring(L, "restricted"); + luaCompat_pushBool(L, typeflags & IMPLTYPEFLAG_FRESTRICTED); + lua_settable(L, -3); + + lua_pushstring(L, "defaultvtable"); + luaCompat_pushBool(L, typeflags & IMPLTYPEFLAG_FDEFAULTVTABLE); + lua_settable(L, -3); + + LUASTACK_CLEAN(L, 1); + + return 1; +} + + + +int tLuaTypeInfo::GetDocumentation(tLuaObject* lua_obj, lua_State* L) +{ + tLuaTypeInfo* lua_typeinfo = dynamic_cast(lua_obj); + + CHECKPRECOND(lua_typeinfo); + + HRESULT hr = S_OK; + BSTR name; + BSTR helpstring; + BSTR helpfile; + ULONG helpcontext; + + hr = lua_typeinfo->typeinfo->GetDocumentation(MEMBERID_NIL, + &name, &helpstring, &helpcontext, &helpfile); + + CHK_COM_CODE(hr); + + lua_newtable(L); + + lua_pushstring(L, "name"); + lua_pushstring(L, tUtil::bstr2string(name)); + lua_settable(L, -3); + + lua_pushstring(L, "helpstring"); + lua_pushstring(L, tUtil::bstr2string(helpstring)); + lua_settable(L, -3); + + lua_pushstring(L, "helpfile"); + lua_pushstring(L, tUtil::bstr2string(helpfile)); + lua_settable(L, -3); + + lua_pushstring(L, "helpcontext"); + lua_pushnumber(L, helpcontext); + lua_settable(L, -3); + + SysFreeString(name); + SysFreeString(helpstring); + SysFreeString(helpfile); + + return 1; +} + +int tLuaTypeInfo::GetTypeAttr(tLuaObject* lua_obj, lua_State* L) +{ + tLuaTypeInfo* lua_typeinfo = dynamic_cast(lua_obj); + CHECKPRECOND(lua_typeinfo); + + TYPEATTR* ptypeattr = NULL; + + HRESULT hr = lua_typeinfo->typeinfo->GetTypeAttr(&ptypeattr); + CHK_COM_CODE(hr); + + // creates table to hold type attributes + lua_newtable(L); + + // stores guid + { + char *pGuid = NULL; + + hr = tCOMUtil::GUID2String(ptypeattr->guid, &pGuid); + if(SUCCEEDED(hr)) + { + lua_pushstring(L, "GUID"); + lua_pushstring(L, pGuid); + lua_settable(L, -3); + delete pGuid; + } + } + + // stores typekind + lua_pushstring(L, "typekind"); + lua_pushstring(L, tCOMUtil::getPrintableTypeKind(ptypeattr->typekind)); + lua_settable(L, -3); + + // stores numbers + lua_pushstring(L, "Funcs"); + lua_pushnumber(L, ptypeattr->cFuncs); + lua_settable(L, -3); + + lua_pushstring(L, "Vars"); + lua_pushnumber(L, ptypeattr->cVars); + lua_settable(L, -3); + + lua_pushstring(L, "ImplTypes"); + lua_pushnumber(L, ptypeattr->cImplTypes); + lua_settable(L, -3); + + + // stores flags in a separate table + lua_newtable(L); + + lua_pushstring(L, "flags"); + lua_pushvalue(L, -2); + lua_settable(L, -4); + + lua_pushstring(L, "hidden"); + luaCompat_pushBool(L, ptypeattr->wTypeFlags & TYPEFLAG_FHIDDEN); + lua_settable(L, -3); + + lua_pushstring(L, "control"); + luaCompat_pushBool(L, ptypeattr->wTypeFlags & TYPEFLAG_FCONTROL); + lua_settable(L, -3); + + lua_pushstring(L, "appobject"); + luaCompat_pushBool(L, ptypeattr->wTypeFlags & TYPEFLAG_FAPPOBJECT); + lua_settable(L, -3); + + lua_pushstring(L, "dispatchable"); + luaCompat_pushBool(L, ptypeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE); + lua_settable(L, -3); + + lua_pushstring(L, "oleautomation"); + luaCompat_pushBool(L, ptypeattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION); + lua_settable(L, -3); + + lua_pushstring(L, "cancreate"); + luaCompat_pushBool(L, ptypeattr->wTypeFlags & TYPEFLAG_FCANCREATE); + lua_settable(L, -3); + + + // removes attributes table + lua_pop(L, 1); + + return 1; +} + +int tLuaTypeInfo::GetTypeLib(tLuaObject* lua_obj, lua_State* L) +{ + LUASTACK_SET(L); + + tLuaTypeInfo* lua_typeinfo = dynamic_cast(lua_obj); + + CHECKPRECOND(lua_typeinfo); + + // stores a reference to the type library + ITypeLib* typelib = NULL; + unsigned int dumb = 0; + + HRESULT hr = lua_typeinfo->typeinfo->GetContainingTypeLib(&typelib, &dumb); + + if(SUCCEEDED(hr)) + { + tLuaTLB::pushNew(L, typelib); + } + COM_RELEASE(typelib); + + LUASTACK_CLEAN(L, 1); + + return 1; +} diff --git a/luacom/tLuaTLB.h b/luacom/tLuaTLB.h new file mode 100644 index 00000000..df729517 --- /dev/null +++ b/luacom/tLuaTLB.h @@ -0,0 +1,74 @@ +// tLuaTLB.h: interface for the tLuaTLB class. +// +////////////////////////////////////////////////////////////////////// + +#ifndef _TLUATLB_H +#define _TLUATLB_H + +#include + +#include "tLuaObject.h" +#include "tLuaCOMTypeHandler.h" + + +class tLuaTLB : public tLuaObject +{ +public: + static int pushNew(lua_State* L, ITypeLib* p_typelib); + static void Init(lua_State* L); + +protected: + int index(lua_State* L); + ITypeLib* typelib; + + static const char type_name[]; + static const char pointer_type_name[]; + + static int ShowHelp(tLuaObject* lua_obj, lua_State* L); + static int GetDocumentation(tLuaObject* lua_obj, lua_State* L); + static int GetTypeInfo(tLuaObject* lua_obj, lua_State* L); + static int GetTypeInfoCount(tLuaObject* lua_obj, lua_State* L); + static int ExportConstants(tLuaObject* lua_obj, lua_State* L); + static int ExportEnumerations(tLuaObject* lua_obj, lua_State* L); + + tLuaTLB(lua_State* L, ITypeLib *p_typelib); + virtual ~tLuaTLB(); +public: + int GetDocumentation(void); +}; + + + +// +// tLuaTypeInfo: generic Lua proxy for ITypeInfo objects +// + +class tLuaTypeInfo: public tLuaObject +{ +public: + static void pushNew(lua_State* L, ITypeInfo* p_typeinfo); + static void Init(lua_State* L); + +protected: + static int GetTypeLib(tLuaObject* lua_obj, lua_State* L); + static int GetFuncDesc(tLuaObject* lua_obj, lua_State* L); + static int GetVarDesc(tLuaObject* lua_obj, lua_State* L); + static int GetDocumentation(tLuaObject* lua_obj, lua_State* L); + static int GetTypeAttr(tLuaObject* lua_obj, lua_State* L); + static int GetImplType(tLuaObject* lua_obj, lua_State* L); + static int GetImplTypeFlags(tLuaObject* lua_obj, lua_State* L); + + ITypeInfo* typeinfo; + tLuaCOMTypeHandler* typehandler; + + static const char type_name[]; + static const char pointer_type_name[]; + + tLuaTypeInfo(lua_State* L, + ITypeInfo *p_typeinfo + ); + + virtual ~tLuaTypeInfo(); +}; + +#endif // _TLUATLB_H diff --git a/luacom/tLuaVector.cpp b/luacom/tLuaVector.cpp new file mode 100644 index 00000000..95b8ceae --- /dev/null +++ b/luacom/tLuaVector.cpp @@ -0,0 +1,528 @@ +// tLuaVector.cpp: implementation of the tLuaVector class. +// +////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "tLuaVector.h" +#include "tLuaCOM.h" +#include "LuaAux.h" +#include "tLuaCOMException.h" + +extern "C" +{ +#include "LuaCompat.h" +} + + +#define LUA_NOOBJECT 0 + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +tLuaVector::tLuaVector() +{ + initialized = false; +} + +tLuaVector::~tLuaVector() +{ + // destroi escalares ou luavectors + freeData(); +} + + +unsigned long tLuaVector::get_Dimensions() +{ + CHECKPRECOND(length != 0 && elem_type != UNKNOWN); + + if(elem_type == SCALAR) + return 1; + else + return 1 + vectors[0]->get_Dimensions(); +} + +unsigned long tLuaVector::get_Nth_Dimension(unsigned long n) +{ + // precond + CHECKPRECOND(length >= 0 && n >= 0 && (n == 1 || elem_type == VECTOR)); + + if(n == 1) + return length; + else + return vectors[0]->get_Nth_Dimension(n - 1); +} + +stkIndex tLuaVector::getindex(long * indices, + unsigned long size, + const SAFEARRAYBOUND* bounds ) +{ + CHECKPARAM(indices != NULL && size != 0); + + const long index = indices[size - 1] - bounds[size - 1].lLbound; + + CHECKPARAM(index < (long)length); + + if(size > 1) + { + CHECKPRECOND(elem_type == VECTOR); + + return vectors[index]->getindex(indices, size - 1, bounds); + } + else + { + return luavals[index]; + } +} + +unsigned long tLuaVector::getLength() +{ + return length; +} + +tLuaVector::Type tLuaVector::getType() +{ + return array_type; +} + +tLuaVector::Type tLuaVector::lua2Type(lua_State* L, stkIndex luaval) +{ + switch(lua_type(L, luaval)) + { + case LUA_TNUMBER: + return NUMBER; + break; + + case LUA_TSTRING: + return STRING; + break; + + case LUA_TUSERDATA: + return USERDATA; + break; + + default: + return OTHER; + break; + } +} + +void tLuaVector::freeData() +{ + unsigned long i; + + if(vectors != NULL) + { + for(i = 0; i < length; i++) + delete vectors[i]; + + delete[] vectors; + vectors = NULL; + } + else if(luavals != NULL) + { + delete[] luavals; + luavals = NULL; + } + + initialized = false; + + return; +} + +// +// Cria uma tabela Lua a partir da matriz contida no luavector +// +bool tLuaVector::CreateTable(lua_State* L) +{ + lua_newtable(L); + stkIndex table = lua_gettop(L); + + // if no elements have been set, returns an empty table + if(array_type == NOTYPE) + return true; + + switch(elem_type) + { + case VECTOR: + { + unsigned long index = 0; + + for(index = 0; index < length; index++) + { + bool succeeded = vectors[index]->CreateTable(L); + + if(!succeeded) + return false; + + stkIndex child_table = lua_gettop(L); + + lua_pushvalue(L, table); + lua_pushnumber(L, index + 1); + + lua_pushvalue(L, child_table); + + lua_settable(L, -3); + lua_settop(L, table); + } + } + + break; + + case SCALAR: + { + unsigned long int index = 0; + + for(index = 0; index < length; index++) + { + if(luavals[index] == LUA_NOOBJECT) + return false; + + lua_pushvalue(L, table); + lua_pushnumber(L, index + 1); + + lua_pushvalue(L, luavals[index]); + + lua_settable(L, -3); + lua_settop(L, table); + } + } + + break; + + default: + return false; + } + + return true; +} + +void tLuaVector::setindex(lua_State* L, + stkIndex luaval, + long * indices, + unsigned long size, + const SAFEARRAYBOUND* bounds) +{ + CHECKPARAM(indices != NULL && size != 0); + + const long index = indices[size - 1] - bounds[size - 1].lLbound; + + CHECKPARAM(index < (long)length); + + if(size > 1) + { + if(elem_type != VECTOR) + TYPECONV_ERROR("Cannot convert table to safearray"); + + vectors[index]->setindex(L, luaval, indices, size - 1, bounds); + + if(array_type == NOTYPE) + array_type = vectors[index]->getType(); + else if(vectors[index]->getType() != array_type) + array_type = MANY; + } + else + { + luavals[index] = luaval; + + if(array_type == NOTYPE) + array_type = lua2Type(L, luaval); + else if(lua2Type(L, luaval) != array_type) + array_type = MANY; + } +} + +void tLuaVector::InitVectorFromDimensions(long * dimensions, + unsigned long num_dimensions) +{ + CHECKPRECOND(initialized != true); + CHECKPARAM(dimensions != NULL && num_dimensions != 0); + + length = 0; + vectors = NULL; + luavals = NULL; + array_type = NOTYPE; + elem_type = UNKNOWN; + max_length = 0; + + if(num_dimensions == 1) + { + elem_type = SCALAR; + length = max_length = dimensions[0]; + + luavals = new stkIndex[length]; + assert(luavals); + + { + unsigned long i = 0; + + for(i = 0; i < length; i++) + luavals[i] = LUA_NOOBJECT; + } + + // cria array de luavals e inicializa resto + + initialized = true; + } + else + { + elem_type = VECTOR; + length = max_length = dimensions[0]; + + vectors = new tLuaVector*[length]; + + // inicializa vetores recursivamente + + { + unsigned long i = 0; + + for(i = 0; i < length; i++) + { + vectors[i] = new tLuaVector(); + vectors[i]->InitVectorFromDimensions(&dimensions[1], num_dimensions - 1); + } + } + + initialized = true; + } + + return; +} + +void tLuaVector::InitVectorFromTable(lua_State* L, stkIndex table) +{ + CHECKPRECOND(!initialized); + + stkIndex luaval = LUA_NOOBJECT; + + length = 0; + vectors = NULL; + luavals = NULL; + array_type = NOTYPE; + elem_type = UNKNOWN; + max_length = 0; + + // so' podem ser criados vetores a partir + // de tabelas e de userdata + + if(lua_type(L, table) == LUA_TNONE || + (!lua_istable(L, table) && !lua_isuserdata(L, table)) + ) + { + TYPECONV_ERROR("Can't convert to safearray"); + } + + + try + { + // Itera em tabela ou userdata, criando LuaVectors recursivamente + while(1) + { + CHECKPRECOND((length <= 0 || elem_type != UNKNOWN) && + (length != 0 || elem_type == UNKNOWN)); + + lua_pushvalue(L, table); + + lua_pushnumber(L, length + 1); + + lua_gettable(L, -2); + + lua_remove(L, -2); + + luaval = lua_gettop(L); + + if(lua_isnil(L, luaval)) + { + lua_remove(L, luaval); + break; + } + + // assures there will be enough stack space + luaCompat_needStack(L, 1); + + // se nao for tabela, termina processo de calculo de dimensoes + // e guarda elemento + // se for, continua, chamando recursivamente + + if(lua_istable(L, luaval) && LuaBeans::from_lua(L, luaval) == NULL) + { + // garante que tabela e' uma matriz + if(elem_type == SCALAR) + TYPECONV_ERROR("Cannot convert table to safearray"); + + if(elem_type == UNKNOWN) + { + elem_type = VECTOR; + + max_length = 10; + + vectors = new tLuaVector*[max_length]; + } + + // realoca array + if(length == max_length) + { + tLuaVector **new_vectors = NULL; + + max_length *= 2; + + new_vectors = new tLuaVector*[max_length]; + + unsigned long i = 0; + + for(i = 0; i < length; i++) + new_vectors[i] = vectors[i]; + + delete[] vectors; + vectors = new_vectors; + } + + // obtem novo vetor + vectors[length] = new tLuaVector(); + + vectors[length]->InitVectorFromTable(L, luaval); + + length++; + + // caso nova tabela tenha dimensao diferente, aborta processo + // (nao e' uma matriz) + if(length == 1) + { + array_type = vectors[length - 1]->getType(); + } + else if( + vectors[length - 1]->getLength() != + vectors[length - 2]->getLength()) + { + TYPECONV_ERROR("Cannot convert table to safearray"); + } + else if( + vectors[length - 1]->getType() != + vectors[length - 2]->getType()) + { + array_type = MANY; + } + } + else + { + if(elem_type == VECTOR) + TYPECONV_ERROR("Cannot convert table to safearray"); + + if(elem_type == UNKNOWN) + { + elem_type = SCALAR; + + max_length = 10; + + luavals = new stkIndex[max_length]; + } + + // realoca luavals + if(length == max_length) + { + stkIndex *new_luavals = NULL; + + max_length *= 2; + + new_luavals = new stkIndex[max_length]; + + unsigned long i = 0; + + for(i = 0; i < length; i++) + new_luavals[i] = luavals[i]; + + delete[] luavals; + luavals = new_luavals ; + } + + + // guarda luaval + luavals[length] = luaval; + length++; + + // verifica se e' do mesmo tipo que o anterior + if(length > 1 && lua2Type(L, luaval) != array_type) + { + array_type = MANY; + } + else if(length == 1) + { + array_type = lua2Type(L, luaval); + } + } + } + } + catch(class tLuaCOMException) + { + freeData(); + initialized = false; + throw; + } + + initialized = true; + + return; +} + +void tLuaVector::InitVectorFromStack(lua_State* L, stkIndex first_elem) +{ + CHECKPRECOND(!initialized); + + // vector initialization + array_type = MANY; + elem_type = SCALAR; + vectors = NULL; + + stkIndex luaval = first_elem; + stkIndex last_elem = lua_gettop(L); + + length = 0; + max_length = lua_gettop(L) - first_elem + 1; + + luavals = new stkIndex[max_length]; + + try + { + while(luaval <= last_elem) + { + CHECKPARAM_MSG(lua_type(L, luaval) != LUA_TTABLE, + "Trying to create nested safearrays."); + + luavals[length] = luaval; + length++; + luaval++; + } + } + catch(class tLuaCOMException) + { + freeData(); + initialized = false; + throw; + } + + initialized = true; + + return; +} + + +long tLuaVector::size() +{ + long size = 0; + + if(vectors != NULL) + { + unsigned long i; + for(i = 0; i < length; i++) + size += vectors[i]->size(); + } + else if(luavals != NULL) + { + size = length; + } + + return size; +} diff --git a/luacom/tLuaVector.h b/luacom/tLuaVector.h new file mode 100644 index 00000000..7fdc1243 --- /dev/null +++ b/luacom/tLuaVector.h @@ -0,0 +1,69 @@ +// tLuaVector.h: interface for the tLuaVector class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_TLUAVECTOR_H__BAD115E6_A282_11D4_9DF6_0000B45D6611__INCLUDED_) +#define AFX_TLUAVECTOR_H__BAD115E6_A282_11D4_9DF6_0000B45D6611__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +extern "C" +{ +#include "..\lua.h" +} + +#include "tLuaCOM.h" +#include "luabeans.h" + + +class tLuaVector +{ +public: + long size(void); + enum Type {NOTYPE, NUMBER, STRING, USERDATA, OTHER, MANY}; + + void InitVectorFromTable(lua_State* L, stkIndex table); + void InitVectorFromStack(lua_State* L, stkIndex first_elem); + void InitVectorFromDimensions( + long *dimensions, + unsigned long num_dimensions); + + void setindex( + lua_State* L, + stkIndex luaval, + long *dimensions, + unsigned long size, + const SAFEARRAYBOUND* bounds); + + bool CreateTable(lua_State* L); + + Type lua2Type(lua_State* L, stkIndex luaval); + Type getType(void); + unsigned long getLength(void); + stkIndex getindex( + long *indices, + unsigned long size, + const SAFEARRAYBOUND* bounds ); + + unsigned long get_Nth_Dimension(unsigned long n); + unsigned long get_Dimensions(void); + tLuaVector(); + virtual ~tLuaVector(); + +protected: + enum {UNKNOWN, VECTOR, SCALAR} elem_type; + + void freeData(void); + + unsigned long max_length; + unsigned long length; + stkIndex* luavals; + tLuaVector** vectors; + bool initialized; + + Type array_type; +}; + +#endif // !defined(AFX_TLUAVECTOR_H__BAD115E6_A282_11D4_9DF6_0000B45D6611__INCLUDED_) diff --git a/luacom/tStringBuffer.cpp b/luacom/tStringBuffer.cpp new file mode 100644 index 00000000..798752db --- /dev/null +++ b/luacom/tStringBuffer.cpp @@ -0,0 +1,44 @@ +// tStringBuffer.cpp: implementation of the tStringBuffer class. +// +////////////////////////////////////////////////////////////////////// + +#include + +#include "tStringBuffer.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +tStringBuffer::tStringBuffer() +{ + size = 0; + buffer = NULL; +} + +tStringBuffer::~tStringBuffer() +{ + if(buffer!=NULL) + delete[] buffer; +} + +void tStringBuffer::copyToBuffer(char * source) +{ + long new_size = strlen(source) + 1; + + if(new_size > size) + { + if(buffer != NULL) + delete[] buffer; + + size = new_size; + buffer = new char[size]; + } + + strncpy(buffer, source, new_size); +} + +const char * tStringBuffer::getBuffer() +{ + return buffer; +} diff --git a/luacom/tStringBuffer.h b/luacom/tStringBuffer.h new file mode 100644 index 00000000..d75ddfc6 --- /dev/null +++ b/luacom/tStringBuffer.h @@ -0,0 +1,25 @@ +// tStringBuffer.h: interface for the tStringBuffer class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_TSTRINGBUFFER_H__35A7FE20_7CD4_11D4_B881_0000B45D7541__INCLUDED_) +#define AFX_TSTRINGBUFFER_H__35A7FE20_7CD4_11D4_B881_0000B45D7541__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +class tStringBuffer +{ +public: + const char * getBuffer(void); + void copyToBuffer(char *source); + tStringBuffer(); + virtual ~tStringBuffer(); + +protected: + long size; + char * buffer; +}; + +#endif // !defined(AFX_TSTRINGBUFFER_H__35A7FE20_7CD4_11D4_B881_0000B45D7541__INCLUDED_) diff --git a/luacom/tUtil.cpp b/luacom/tUtil.cpp new file mode 100644 index 00000000..ab315f3a --- /dev/null +++ b/luacom/tUtil.cpp @@ -0,0 +1,289 @@ +// tUtil.cpp: implementation of the tUtil class. +// +////////////////////////////////////////////////////////////////////// + +// RCS Info +static char *rcsid = "$Id: tUtil.cpp,v 1.14 2005/01/06 18:42:06 fqueiroz Exp $"; +static char *rcsname = "$Name: $"; + + +#include +#include + +#include "tUtil.h" +#include "tLuaCOMException.h" + +tStringBuffer tUtil::string_buffer = tStringBuffer(); +FILE* tUtil::log_file = NULL; + +#define MAX_VALID_STRING_SIZE 1000 + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +bool tUtil::IsValidString(LPCTSTR string) +{ + bool return_value = string != NULL && + !IsBadStringPtr(string, MAX_VALID_STRING_SIZE); + + assert(return_value); + + return return_value; +} + +const char *tUtil::GetErrorMessage(DWORD errorcode) +{ + LPTSTR lpMsgBuf; + DWORD result = 0; + + result = FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + errorcode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL); + + if(result == 0) + return NULL; + + // Strip the newline at the end of the message + + while((result > 1) && ((lpMsgBuf[result-1] == '\n') || (lpMsgBuf[result-1] == '\r'))) + result--; + lpMsgBuf[result] = '\0'; + + tUtil::string_buffer.copyToBuffer((char *) lpMsgBuf); + + // Free the buffer. + LocalFree( lpMsgBuf ); + + return tUtil::string_buffer.getBuffer(); +} + +const char * tUtil::bstr2string(BSTR bstr) +{ + char* str = NULL; + long size = 0; + int result = 0; + + try + { + if(bstr != NULL) + { + // gets the size of the buffer + size = WideCharToMultiByte( + CP_UTF8, // code page + 0, // performance and mapping flags + bstr, // wide-character string + -1, // number of chars in string + str, // buffer for new string + 0, // size of buffer + NULL, // default for unmappable chars + NULL // set when default char used + ); + + if(!size) + LUACOM_ERROR(tUtil::GetErrorMessage(GetLastError())); + + str = new char[size]; + + result = WideCharToMultiByte( + CP_UTF8, // code page + 0, // performance and mapping flags + bstr, // wide-character string + -1, // number of chars in string + str, // buffer for new string + size, // size of buffer + NULL, // default for unmappable chars + NULL // set when default char used + ); + + if(!result) + LUACOM_ERROR(tUtil::GetErrorMessage(GetLastError())); + + } + else + { + str = new char[1]; + str[0] = '\0'; + } + } + catch(class tLuaCOMException& e) + { + UNUSED(e); + + if(str) + delete[] str; + + str = new char[1]; + str[0] = '\0'; + } + + tUtil::string_buffer.copyToBuffer(str); + + delete[] str; + + return tUtil::string_buffer.getBuffer(); +} + +BSTR tUtil::string2bstr(const char * string) +{ + if(!string) + return NULL; + + BSTR bstr; + + long length = + MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0); + + try + { + if(length == 0) + LUACOM_ERROR(tUtil::GetErrorMessage(GetLastError())); + } + catch(class tLuaCOMException& e) + { + UNUSED(e); + + return NULL; + } + + wchar_t *widestr = new wchar_t[length]; + + MultiByteToWideChar(CP_UTF8, 0, string, -1, widestr, length); + + bstr = SysAllocString(widestr); + + delete[] widestr; + widestr = NULL; + + return bstr; +} + +bool tUtil::OpenLogFile(const char *name) +{ + tUtil::CloseLogFile(); + + tUtil::log_file = fopen(name, "w"); + + if(!tUtil::log_file) + return false; + else + return true; +} + +void tUtil::CloseLogFile() +{ + if(tUtil::log_file) + { + fclose(tUtil::log_file); + tUtil::log_file = NULL; + } +} + +void tUtil::log(const char *who, const char *what, ...) +{ + if(tUtil::log_file && who && what) + { + int size = 0; + + fprintf(tUtil::log_file, "%s:", who); + + va_list marker; + va_start(marker, what); + + size = vfprintf(tUtil::log_file, what, marker); + + va_end(marker); + + if(what[strlen(what) - 1] != '\n') + fprintf(tUtil::log_file, "\n"); + + fflush(tUtil::log_file); + +#ifdef VERBOSE + + char *buffer = new char[size+1]; + + sprintf(buffer, "%s:", who); + + va_start(marker, what); + + size = vsprintf(buffer, what, marker); + + va_end(marker); + + MessageBox(NULL, buffer, "LuaCOM Log", MB_OK | MB_ICONEXCLAMATION); + + delete[] buffer; + buffer = NULL; + +#endif // VERBOSE + } +} + +void tUtil::log_verbose(const char *who, const char *what, ...) +{ +#ifdef VERBOSE + if(tUtil::log_file && who && what) + { + fprintf(tUtil::log_file, "%s:", who); + + va_list marker; + va_start(marker, what); + + vfprintf(tUtil::log_file, what, marker); + + va_end(marker); + + if(what[strlen(what) - 1] != '\n') + fprintf(tUtil::log_file, "\n"); + + fflush(tUtil::log_file); + } +#endif +} + + +char * tUtil::strdup(const char *string) +{ + if(!string) + return NULL; + + char *new_string = (char *) malloc(strlen(string)+1); + + strcpy(new_string, string); + + return new_string; +} + +void tUtil::ShowHelp(const char *filename, unsigned long context) +{ + // filename must have at least the extension + if(!filename || strlen(filename) < 5) + return; + + const char* extension = &filename[strlen(filename) - 4]; + + if(_stricmp(extension, ".chm") == 0) + { + char context_param[50]; + + if(context != 0) + sprintf(context_param, "-mapid %d", context); + else + context_param[0] = '\0'; + + _spawnlp(_P_NOWAIT, "hh.exe", "hh.exe", context_param, filename, NULL); + } + else if(_stricmp(extension, ".hlp") == 0) + { + if(context != 0) + WinHelp(NULL, filename, HELP_CONTEXT, context); + else + WinHelp(NULL, filename, HELP_FINDER, 0); + } +} diff --git a/luacom/tUtil.h b/luacom/tUtil.h new file mode 100644 index 00000000..7b131183 --- /dev/null +++ b/luacom/tUtil.h @@ -0,0 +1,44 @@ +// tUtil.h: interface for the tUtil class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_TUTIL_H__0B3E0B68_981F_11D3_A906_0004ACE655F9__INCLUDED_) +#define AFX_TUTIL_H__0B3E0B68_981F_11D3_A906_0004ACE655F9__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#include +#include +#include "tStringBuffer.h" // Added by ClassView + +class tUtil +{ +public: + static void ShowHelp(const char* filename, unsigned long context); + static char * strdup(const char *string); + static void log(const char *who, const char *what,...); + static void log_verbose(const char *who, const char *what,...); + static void CloseLogFile(void); + static bool OpenLogFile(const char *name); + static BSTR string2bstr(const char *string); + static const char * bstr2string(BSTR bstr); + static const char *GetErrorMessage(DWORD errorcode); + static bool IsValidString(LPCTSTR string); + + static tStringBuffer string_buffer; + static FILE* log_file; +}; + +// algumas macros uteis + +#define UNUSED(x) (void)(x) + +#define SAFEFREE(x) {if(x){free(x); (x) = NULL;}} + +#define SAFEDELETE(x) {if(x){delete x; (x) = NULL;}} + +#define SAFEDELETEARR(x) {if(x){delete[] x; (x) = NULL;}} + +#endif // !defined(AFX_TUTIL_H__0B3E0B68_981F_11D3_A906_0004ACE655F9__INCLUDED_) diff --git a/scripting/lua_scripting.cpp b/scripting/lua_scripting.cpp index 5b2caee8..8df5b1a6 100644 --- a/scripting/lua_scripting.cpp +++ b/scripting/lua_scripting.cpp @@ -7,6 +7,7 @@ #include // for popen #include "..\pcre\config.h" #include "..\pcre\pcre_internal.h" +#include "..\luacom\luacom.h" set LuaFunctionsSet; set LuaTablesSet; @@ -25,8 +26,6 @@ extern "C" LUALIB_API int luaopen_progress_dialog(lua_State *L); - - static void BuildOneLuaFunction (lua_State * L, const char * sTableName) { lua_settop (L, 0); // get rid of stuff lying around @@ -162,8 +161,14 @@ static void BuildLuaTables (lua_State * L) } // end of BuildLuaTables -// I need this extra function to avoid: +// sigh - luacom_open returns void +int luacom_open_glue (lua_State *L) + { + luacom_open (L); + return 0; + } +// I need this extra function to avoid: // Compiler Error C2712 // cannot use __try in functions that require object unwinding @@ -219,6 +224,25 @@ void CScriptEngine::OpenLuaDelayed () m_pDoc->m_iCurrentActionSource = eUnknownActionSource; + + // add luacom to package.preload + lua_getglobal (L, LUA_LOADLIBNAME); /* "package" */ + + if (lua_istable (L, -1)) + { + lua_getfield (L, -1, "preload"); + + if (lua_istable (L, -1)) + { + lua_pushcfunction(L, luacom_open_glue); + lua_setfield(L, -2, "luacom"); + lua_pop (L, 1); // get rid of preload table from stack + } // have package.preload table + + lua_pop (L, 1); // get rid of package table from stack + } // have package table + + lua_settop(L, 0); // clear stack } // end of OpenLuaDelayed