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

Reply via email to