1、After my investigation, I think it's possible to implement XPConnect with JS-Ctypes. 2、And more than that,we could be possible to override Native C++ XPCOM components with JS-Ctypes. 3、For support the full functional XPConnect in JS-Ctypes, we need to be able to pass the JSContext parameter along with JsObject with js-ctypes.
The following code the the exposed C API to be called with js-ctypes, so that js-ctypes would be able to implement full functional XPConnect: #include <stdio.h> #include <windows.h> #include <fcntl.h> #include <io.h> #include <ios> #include <math.h> #include <nsComponentManagerUtils.h> #include <nsServiceManagerUtils.h> #include <nsIComponentRegistrar.h> #include <nsIInterfaceInfoManager.h> #include <nsIComponentManager.h> #include <nsIInterfaceInfo.h> #include <nsIXPConnect.h> #include <xptinfo.h> #include <nsXPCOMGlue.h> #include <nsStringGlue.h> #include <jsapi.h> #include <xpt_struct.h> using namespace mozilla; static nsCOMPtr<nsIInterfaceInfoManager> iim = nullptr; static nsCOMPtr<nsIXPConnect> xpconnect = nullptr; static nsCOMPtr<nsIComponentRegistrar> registrar = nullptr; static nsCOMPtr<nsIComponentManager> compMgr = nullptr; static bool gShellInited = false; #define NS_NULL_ID \ { 0x00000000, 0x0000, 0x0000, \ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} } #define SHELL_EXPORT extern "C" NS_EXPORT // https://github.com/ivansafrin/Polycode/blob/master/Core/Contents/PolycodeView/MSVC/PolycodeView.cpp#L16 SHELL_EXPORT void OpenConsole(bool create) { int outHandle, errHandle, inHandle; FILE *outFile, *errFile, *inFile; bool hasConsole = AttachConsole(ATTACH_PARENT_PROCESS); if (!hasConsole) { if (!create) { return; } FreeConsole(); AllocConsole(); } CONSOLE_SCREEN_BUFFER_INFO coninfo; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); coninfo.dwSize.Y = 9999; SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); outHandle = _open_osfhandle((intptr_t)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT); errHandle = _open_osfhandle((intptr_t)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT); inHandle = _open_osfhandle((intptr_t)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT); outFile = _fdopen(outHandle, "w"); errFile = _fdopen(errHandle, "w"); inFile = _fdopen(inHandle, "r"); *stdout = *outFile; *stderr = *errFile; *stdin = *inFile; setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); setvbuf(stdin, NULL, _IONBF, 0); std::ios::sync_with_stdio(); } struct thread_data { uint32_t sleep_time; int32_t exit_code; thread_data(uint32_t sleep_time, int32_t exit_code) : sleep_time(sleep_time), exit_code(exit_code) { } }; DWORD WINAPI thread_func(LPVOID lpParameter) { thread_data *td = (thread_data*)lpParameter; Sleep(td->sleep_time); ExitProcess(td->exit_code); return 0; } SHELL_EXPORT void ForceExit(uint32_t sleep_time, int32_t exit_code) { CreateThread(NULL, 0, thread_func, new thread_data(sleep_time, exit_code), 0, 0); } SHELL_EXPORT void CopyBufferWithFree(void* destBuffer, void* sourceBuffer, uint32_t length) { memcpy(destBuffer, sourceBuffer, length); NS_Free(sourceBuffer); } SHELL_EXPORT uint32_t CopyStringWithFree(char*destString, char* sourceString, uint32_t destLength) { uint32_t tmpLength = strlen(sourceString); if (tmpLength <= destLength) { memcpy(destString, sourceString, tmpLength); } NS_Free(sourceString); return tmpLength; } SHELL_EXPORT nsresult XPCOM_Init(const char* filePath) { if (gShellInited) { return NS_OK; } nsresult rc = XPCOMGlueStartup(filePath); NS_ENSURE_SUCCESS(rc, rc); iim = do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CID, &rc); NS_ENSURE_SUCCESS(rc, rc); xpconnect = do_GetService(nsIXPConnect::GetCID(), &rc); NS_ENSURE_SUCCESS(rc, rc); rc = NS_GetComponentRegistrar(getter_AddRefs(registrar)); NS_ENSURE_SUCCESS(rc, rc); rc = NS_GetComponentManager(getter_AddRefs(compMgr)); gShellInited = true; return rc; } SHELL_EXPORT void* XPCOM_Alloc(size_t sz) { return NS_Alloc(sz); } SHELL_EXPORT void XPCOM_Free(void* ptr) { if (ptr) { NS_Free(ptr); } } SHELL_EXPORT uint32_t XPCOM_nsStringSize() { return sizeof(nsString); } SHELL_EXPORT uint32_t XPCOM_nsCStringSize() { return sizeof(nsCString); } SHELL_EXPORT void XPCOM_ContractIDToCID(const char* contractID, nsCID* cid) { nsCID* newCID; if (registrar->ContractIDToCID(contractID, &newCID) == NS_OK) { return CopyBufferWithFree(cid, newCID, sizeof(*cid)); } *cid = NS_NULL_ID; } SHELL_EXPORT uint32_t XPCOM_CIDToContractID(const nsCID* cid, char* contractID, uint32_t length) { char* newContractID; if (registrar->CIDToContractID(*cid, &newContractID) == NS_OK) { return CopyStringWithFree(contractID, newContractID, length); } *contractID = '\0'; return 0; } SHELL_EXPORT nsIFactory* XPCOM_GetClassObject(const char* contractID) { nsresult rc; nsCOMPtr<nsIFactory> sf = do_GetClassObject(contractID, &rc); if (rc != NS_OK) { return nullptr; } sf->AddRef(); return sf; } SHELL_EXPORT nsIFactory* XPCOM_GetClassObjectCID(const nsCID *cid) { nsresult rc; nsCOMPtr<nsIFactory> sf = do_GetClassObject(*cid, &rc); if (rc != NS_OK) { return nullptr; } sf->AddRef(); return sf; } SHELL_EXPORT void XPCOM_GetIIDForName(const char* name, nsIID* iid) { nsIID* newIID; if (iim->GetIIDForName(name, &newIID) == NS_OK) { return CopyBufferWithFree(iid, newIID, sizeof(*iid)); } *iid = NS_NULL_ID; } SHELL_EXPORT uint32_t XPCOM_GetNameForIID(const nsIID* iid, char* name, uint32_t length) { char* tmpName; if (iim->GetNameForIID(iid, &tmpName) == NS_OK) { return CopyStringWithFree(name, tmpName, length); } *name = '\0'; return 0; } SHELL_EXPORT uint32_t XPCOM_AddRef(nsISupports* instance) { return instance->AddRef(); } SHELL_EXPORT uint32_t XPCOM_Release(nsISupports* instance) { return instance->Release(); } SHELL_EXPORT void* XPCOM_QueryInterface(nsISupports* instance, const nsIID *iid) { void *result = nullptr; if (instance->QueryInterface(*iid, &result) != NS_OK) { result = nullptr; } return result; } SHELL_EXPORT void* XPCOM_QueryInterfaceByName(nsISupports* instance, const char* name) { nsIID* newIID; if (iim->GetIIDForName(name, &newIID) == NS_OK) { void *result = nullptr; if (instance->QueryInterface(*newIID, &result) != NS_OK) { result = nullptr; } NS_Free(newIID); return result; } return nullptr; } SHELL_EXPORT void* XPCOM_CreateInstance(const char* contractID) { nsISupports* result = nullptr; if (compMgr->CreateInstanceByContractID(contractID, nullptr, nsISupports::COMTypeInfo<nsISupports, void>::kIID, (void**)&result) != NS_OK) { return nullptr; } return result; } SHELL_EXPORT void* XPCOM_CreateInstanceByFactory(nsIFactory* factory, nsISupports* outer) { void* result = nullptr; if (factory->CreateInstance(outer, nsISupports::COMTypeInfo<nsISupports, void>::kIID, &result) != NS_OK) { result = nullptr; } return result; } SHELL_EXPORT void* XPCOM_CreateInstanceByCID(const nsCID* cid) { nsresult rc; nsCOMPtr<nsISupports> result = do_CreateInstance(*cid, &rc); if (rc == NS_OK) { result->AddRef(); return result.get(); } return nullptr; } SHELL_EXPORT void* XPCOM_GetService(const char* contractID) { nsISupports* result = nullptr; if (CallGetService(contractID, NS_ISUPPORTS_IID, reinterpret_cast<void**>(&result)) != NS_OK) { result = nullptr; } return result; } SHELL_EXPORT void* XPCOM_GetServiceCID(const nsCID* cid) { nsISupports* result = nullptr; if (CallGetService(*cid, NS_ISUPPORTS_IID, reinterpret_cast<void**>(&result)) != NS_OK) { result = nullptr; } return result; } /* Need to be free outside */ SHELL_EXPORT void* XPCOM_GetInterfaceInfo(const nsIID *iid) { nsIInterfaceInfo *info = nullptr; if (iim->GetInfoForIID(iid, &info) != NS_OK) { info = nullptr; } return info; } /* Need to be free outside */ SHELL_EXPORT nsIInterfaceInfo* XPCOM_GetInterfaceInfoForName(const char* name) { nsIInterfaceInfo *info = nullptr; if (iim->GetInfoForName(name, &info) != NS_OK) { info = nullptr; } return info; } SHELL_EXPORT uint16_t XPCOM_GetInterfaceMethodCount(nsIInterfaceInfo *info) { uint16_t result = 0; if (info && info->GetMethodCount(&result) == NS_OK) { return result; } return 0; } SHELL_EXPORT const XPTMethodDescriptor* XPCOM_GetInterfaceMethod(nsIInterfaceInfo *info, uint16_t index) { const nsXPTMethodInfo* method; if (info && info->GetMethodInfo(index, &method) == NS_OK) { return method; } return nullptr; } SHELL_EXPORT uint16_t XPCOM_GetInterfaceConstantCount(nsIInterfaceInfo *info) { uint16_t result = 0; if (info && info->GetConstantCount(&result) == NS_OK) { return result; } return 0; } // The return value need to be freed if not null SHELL_EXPORT char* XPCOM_GetInterfaceConstantName(nsIInterfaceInfo *info, uint16_t index) { if (!info) { return nullptr; } /* TODO: Retrieve the JSContext for the current thread */ JSContext* cx = xpconnect->GetCurrentJSContext(); JS::RootedValue rvalue(cx); JS::MutableHandleValue mvalue(&rvalue); char* tmpName; if (info->GetConstant(index, mvalue, &tmpName) != NS_OK) { return nullptr; } return tmpName; } SHELL_EXPORT uint32_t XPCOM_GetInterfaceConstant(nsIInterfaceInfo *info, uint16_t index) { if (!info) { return 0; } /* TODO: Retrieve the JSContext for the current thread */ JSContext* cx = xpconnect->GetCurrentJSContext(); JS::RootedValue rvalue(cx); JS::MutableHandleValue mvalue(&rvalue); JS::Value &value = mvalue.get(); char* tmpName; if (info->GetConstant(index, mvalue, &tmpName) == NS_OK) { NS_Free(tmpName); if (value.isNumber()) { return (uint32_t)value.toNumber(); } else if (value.isInt32()) { return value.toInt32(); } } return 0; } typedef void* ShellClassFactoryVtblFunction; typedef struct ShellClassFactory { ShellClassFactoryVtblFunction *lpVtbl; } ShellClassFactory; //http://blog.quarkslab.com/visual-c-rtti-inspection.html // Visual C++ // 详解virtual table // http://www.cppblog.com/dawnbreak/archive/2009/03/10/76084.aspx SHELL_EXPORT void** XPCOM_GetInterfaceVTable(void* instance) { ShellClassFactory* factory = (ShellClassFactory*)instance; return factory->lpVtbl; } DWORD tId = 0; BOOL WINAPI DllMain(HINSTANCE aInstance, DWORD aReason, LPVOID aReserved) { switch (aReason) { case DLL_PROCESS_ATTACH: { tId = TlsAlloc(); if (tId == 0xFFFFFFFF) return FALSE; break; } case DLL_PROCESS_DETACH: { TlsFree(tId); iim = nullptr; xpconnect = nullptr; registrar = nullptr; compMgr = nullptr; gShellInited = false; // TODO: Use the full mozjs environment //JS_ShutDown(); break; } } return TRUE; } 此致 礼 罗勇刚 Yours sincerely, Yonggang Luo _______________________________________________ dev-platform mailing list dev-platform@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-platform