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
[email protected]
https://lists.mozilla.org/listinfo/dev-platform