LUA很好用,在Windows下COM是老大,如果能結合它們的功能,那會是比較酷的。LuaCOM庫(目前版本1.4)非常好的扮演了這個牽線搭橋的角色,本文不討論Luacom的各項功能,大家可下載LuaCOM User Manual手冊作全面的了解。這面只是舉一個HelloWorld的例子,以及在實現這個例子過程的一點教訓。網上關於這方面的詳細例子不多(也可能是本人的搜索方法不是很對),基本上找不著HellowWorld檔次的例子,所以感覺有必要寫一個博客,與有興趣的讀者共享,也做為自己的筆記。 說廢話一向不是本人的風格,現在就開始。 准備必要的工具,如果有安裝了VS IDE那是最好的,除了MIDL.exe之外還有Visual Studio Command Prompt (2010)都可以輕松獲得。再就是Lua.exe和LuaCOM.dll,這裡有個教訓就是Lua.exe和LuaCOM.dll的版本要相適應(LuaCOM.dll最好是1.4版本的,1.3好像測試無法正常通過,也沒仔細去研究,用上1.4的就正常了,如果大家能在1.3下通過下邊這個例子,請給個跟貼,謝謝)。 准備一個idl文件,然後使用MIDL.exe生成一個tlb文件,文件名分別為test.idl和test.tlb。 test.idl [cpp] //VBScript and JScript do not support [in,out], use [in,out] or [out,retval] //import "unknwn.idl"; [ uuid(991AB5E0-97C4-4ecc-9926-D76038C517A1), version(1.0) ] library TEST { importlib("STDOLE2.TLB"); [ object, uuid(1AB5DCC7-11F7-441f-962C-57A528F85F47), dual, oleautomation, version(1.0), helpstring("luacom interface implement test 1.0") ] interface ITest : IDispatch { void Version([in,out]short* major, [in,out]short* minor); }; [uuid(340DFD25-59B2-49b4-A693-A7B19A13FD42)] coclass Test { [default] dispinterface ITest; } }; 本人不熟悉VBScript和JScript,一開始參數只是指定[out],結果一定得不到正常的返回結果(沒有返回結果),在網上搜了搜才知道不支持[out]參數,如果在LuaCOM,這樣的參數是能正常返回的。 准備一個實現COM的Lua腳本,在LuaCOM手冊上有一個,在這裡只是稍做改動,以實現上面的ITest接口。 testobj.lua [cpp] --This is the implementation of the COM object local LOON_DIR = os.getenv("loon"); package.cpath = LOON_DIR .. [[\..\lua\?.dll]] require "luacom" path_to_script = LOON_DIR .. [[\..\lua\idl\]] ------------------------------------------------------------------------------ TestObj = {} function TestObj:Version(a,b) return 123+a,455+b; end ------------------------------------------------------------------------------ COM = {} function COM:StartAutomation() --print("testobj.lua > StartAutomation"); -- Creates the object using its default interface COMAppObject, events, e = luacom.NewObject(TestObj, "TEST.Test"); --print("testobj.lua > " .. tostring(COMAppObject), events, e); -- This error will be caught by detectAutomation if COMAppObject == nil then error("NewObject failed: " .. e); end -- Exposes the object cookie = luacom.ExposeObject(COMAppObject); if cookie == nil then error("ExposeObject failed"); end --print("testobj.lua > ookie=" .. tostring(cookie)); end function COM:Register() -- Fills table with registration information local reginfo = {}; reginfo.VersionIndependentProgID = "TEST.Test"; reginfo.ProgID = reginfo.VersionIndependentProgID .. ".1"; reginfo.TypeLib = "test.tlb"; reginfo.CoClass = "Test"; reginfo.ComponentName = "Test Component use luacom"; reginfo.Arguments = "/Automation"; reginfo.ScriptFile = path_to_script .. "testobj.lua"; -- Stores compnent information in the registry local res = luacom.RegisterObject(reginfo); if res == nil then error("RegisterObject failed!"); end end function COM:UnRegister() -- Fills table with registration information local reginfo = {}; reginfo.VersionIndependentProgID = "Test.Test"; reginfo.ProgID = reginfo.VersionIndependentProgID .. ".1"; reginfo.TypeLib = "test.tlb"; reginfo.CoClass = "Test"; -- removes compnent information from the registry local res = luacom.UnRegisterObject(reginfo); if res == nil then error ("UnRegisterObject failed!"); end end -- starts automation server return luacom.DetectAutomation(COM); --xCom = { luacom.DetectAutomation(COM); }; --for k,v in pairs(xCom) do --print(k,v); --end --return unpack(xCom); 執行2個命名,一個是生成test.tlb,另一個是將COM注冊到注冊表中,執行完後,大家可到注冊表中去看看它的注冊內容 maketlb.bat [html] @REM SET MIDLDir="c:\Program Files\Microsoft SDKs\Windows\v7.0A\bin" SET MIDLDir="d:\Program Files\Microsoft SDKs\Windows\v6.0A\bin" SET IDLFile="%loon%\..\lua\idl\test.idl" SET TLBFile="%loon%\..\lua\idl\test.tlb" @SET PATH="%loon%\..\lua\";%PATH% chdir /d %MIDLDir% midl.exe "%IDLFile%" /tlb "%TLBFile%" /out "%loon%\..\lua\" chdir /d "%loon%\..\lua\idl" lua testobj.lua /register 實現(純Lua代碼)和注冊已經完成,下面就可以使用這個COM接口了。這裡分別是用LuaCOM腳本和VBS腳本來調用它。 test.lua [cpp] package.cpath = os.getenv("loon") .. [[\..\lua\?.dll]] require "luacom" obj = {}; print("testlua.lua > luacom=" .. tostring(luacom)); x = luacom.CreateObject("TEST.Test"); print("testlua.lua > comobj=" .. tostring(x)); for k,v in pairs(x) do www.2cto.com print(k,v); end print(x:Version(4,5)); test.vbs [cpp] ON ERROR RESUME NEXT Set x = CreateObject("TEST.Test") Dim a,b a=4 b=5 x.Version a,b MsgBox "Version: "+CStr(a)+"."+CStr(b), vbOK 可以看到輸出結果 127和460,說明輸進去的接收到了,修改後返回也正確接收到了。