From 8d56facea61dffd29e8b13f771d728fba98e07ce Mon Sep 17 00:00:00 2001 From: durs Date: Sun, 16 Apr 2017 10:52:39 +0300 Subject: [PATCH 1/2] sources corrected for new V8 interface (node > 4.0.0) --- README.md | 2 +- package.json | 6 +- src/client.cc | 378 ++++----- src/client.h | 8 +- src/force_gc_extension.cc | 70 +- src/force_gc_internal.cc | 63 +- src/node_win32ole.cc | 119 ++- src/node_win32ole.h | 69 +- src/ole32core.cpp | 20 +- src/ole32core.h | 71 +- src/v8variant.cc | 1400 +++++++++++++++++----------------- src/v8variant.h | 66 +- src/win32ole_gettimeofday.cc | 126 ++- 13 files changed, 1212 insertions(+), 1186 deletions(-) diff --git a/README.md b/README.md index c321ebf..6438574 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # NAME -node-win32ole - Asynchronous, non-blocking win32ole bindings for [node.js](https://github.com/joyent/node) powered by v8 engine . +node-win32ole - Windows COM bindings for [node.js](https://github.com/joyent/node) win32ole makes accessibility from node.js to Excel, Word, Access, Outlook, InternetExplorer, WSH ( ActiveXObject / COM ) and so on. It does not need TypeLibrary. diff --git a/package.json b/package.json index 2cbf014..26600aa 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "win32ole", - "version": "0.1.3", - "description": "Asynchronous, non-blocking win32ole bindings", + "version": "0.2.0", + "description": "Windows COM bindings", "homepage": "https://github.com/idobatter/node-win32ole", "keywords": [ "OLE", "COM", "ActiveX", "ActiveXObject", "CreateObject", "WSH", "WMI", @@ -33,7 +33,7 @@ "ref": ">= 0.1.3" }, "engines": { - "node": ">= 0.8.18 && < 0.9.0" + "node": ">= 4.0.0" }, "scripts": { "test": "nmake /a test" diff --git a/src/client.cc b/src/client.cc index 0c289b5..65e8e38 100644 --- a/src/client.cc +++ b/src/client.cc @@ -10,211 +10,223 @@ using namespace ole32core; namespace node_win32ole { -Persistent Client::clazz; - -void Client::Init(Handle target) -{ - HandleScope scope; - Local t = FunctionTemplate::New(New); - clazz = Persistent::New(t); - clazz->InstanceTemplate()->SetInternalFieldCount(2); - clazz->SetClassName(String::NewSymbol("Client")); -// NODE_SET_PROTOTYPE_METHOD(clazz, "New", New); - NODE_SET_PROTOTYPE_METHOD(clazz, "Dispatch", Dispatch); - NODE_SET_PROTOTYPE_METHOD(clazz, "Finalize", Finalize); - target->Set(String::NewSymbol("Client"), clazz->GetFunction()); -} - -Handle Client::New(const Arguments& args) -{ - HandleScope scope; - DISPFUNCIN(); - if(!args.IsConstructCall()) - return ThrowException(Exception::TypeError( - String::New("Use the new operator to create new Client objects"))); - std::string cstr_locale(".ACP"); // default - if(args.Length() >= 1){ - if(!args[0]->IsString()) - return ThrowException(Exception::TypeError( - String::New("Argument 1 is not a String"))); - String::Utf8Value u8s_locale(args[0]); - cstr_locale = std::string(*u8s_locale); - } - OLE32core *oc = new OLE32core(); - if(!oc) - return ThrowException(Exception::TypeError( - String::New("Can't create new Client object (null OLE32core)"))); - bool cnresult = false; - try{ - cnresult = oc->connect(cstr_locale); - }catch(OLE32coreException e){ - std::cerr << e.errorMessage((char *)cstr_locale.c_str()); - }catch(char *e){ - std::cerr << e << cstr_locale.c_str() << std::endl; - } - if(!cnresult) - return ThrowException(Exception::TypeError( - String::New("May be CoInitialize() is failed."))); - Local thisObject = args.This(); - Client *cl = new Client(); // must catch exception - cl->Wrap(thisObject); // InternalField[0] - thisObject->SetInternalField(1, External::New(oc)); - Persistent objectDisposer = Persistent::New(thisObject); - objectDisposer.MakeWeak(oc, Dispose); - DISPFUNCOUT(); - return args.This(); -} - -Handle Client::Dispatch(const Arguments& args) -{ - HandleScope scope; - DISPFUNCIN(); - BEVERIFY(done, args.Length() >= 1); - BEVERIFY(done, args[0]->IsString()); - wchar_t *wcs; - { - String::Utf8Value u8s(args[0]); // must create here - wcs = u8s2wcs(*u8s); - } - BEVERIFY(done, wcs); + Persistent Client::clazz; + + void Client::Init(Handle target) + { + Isolate* isolate = target->GetIsolate(); + + // Prepare constructor template + Local clazz_name(String::NewFromUtf8(isolate, "Client")); + Local clazz = FunctionTemplate::New(isolate, New); + clazz->SetClassName(clazz_name); + clazz->InstanceTemplate()->SetInternalFieldCount(2); + + NODE_SET_PROTOTYPE_METHOD(clazz, "Dispatch", Dispatch); + NODE_SET_PROTOTYPE_METHOD(clazz, "Finalize", Finalize); + + //constructor.Reset(isolate, clazz->GetFunction()); + target->Set(clazz_name, clazz->GetFunction()); + } + + void Client::New(const FunctionCallbackInfo& args) + { + Isolate* isolate = args.GetIsolate(); + DISPFUNCIN(); + if (!args.IsConstructCall()) RETURN_TYPE_ERROR("Use the new operator to create new Client objects") + std::string cstr_locale(".ACP"); // default + if (args.Length() >= 1) { + if (!args[0]->IsString()) RETURN_TYPE_ERROR("Argument 1 is not a String") + String::Utf8Value u8s_locale(args[0]); + cstr_locale = std::string(*u8s_locale); + } + OLE32core *oc = new OLE32core(); + if (!oc) RETURN_TYPE_ERROR("Can't create new Client object (null OLE32core)") + bool cnresult = false; + try { + cnresult = oc->connect(cstr_locale); + } + catch (OLE32coreException e) { + std::cerr << e.errorMessage((char *)cstr_locale.c_str()); + } + catch (char *e) { + std::cerr << e << cstr_locale.c_str() << std::endl; + } + if (!cnresult) RETURN_TYPE_ERROR("May be CoInitialize() is failed.") + + Local thisObject = args.This(); + Client *cl = new Client(); // must catch exception + cl->Wrap(thisObject); // InternalField[0] + thisObject->SetInternalField(1, External::New(isolate, oc)); + //Persistent objectDisposer = Persistent::New(isolate, thisObject); + //objectDisposer.MakeWeak(oc, Dispose); + + args.GetReturnValue().Set(thisObject); + DISPFUNCOUT(); + } + + void Client::Dispatch(const FunctionCallbackInfo& args) + { + Isolate* isolate = args.GetIsolate(); + DISPFUNCIN(); + BEVERIFY(done, args.Length() >= 1); + BEVERIFY(done, args[0]->IsString()); + wchar_t *wcs; + { + String::Utf8Value u8s(args[0]); // must create here + wcs = u8s2wcs(*u8s); + } + BEVERIFY(done, wcs); #ifdef DEBUG - char *mbs = wcs2mbs(wcs); - if(!mbs) free(wcs); - BEVERIFY(done, mbs); - fprintf(stderr, "ProgID: %s\n", mbs); - free(mbs); + char *mbs = wcs2mbs(wcs); + if (!mbs) free(wcs); + BEVERIFY(done, mbs); + fprintf(stderr, "ProgID: %s\n", mbs); + free(mbs); #endif - CLSID clsid; - HRESULT hr = CLSIDFromProgID(wcs, &clsid); - free(wcs); - BEVERIFY(done, !FAILED(hr)); + CLSID clsid; + HRESULT hr = CLSIDFromProgID(wcs, &clsid); + free(wcs); + BEVERIFY(done, !FAILED(hr)); #ifdef DEBUG - fprintf(stderr, "clsid:"); // 00024500-0000-0000-c000-000000000046 (Excel) ok - for(int i = 0; i < sizeof(CLSID); ++i) - fprintf(stderr, " %02x", ((unsigned char *)&clsid)[i]); - fprintf(stderr, "\n"); + fprintf(stderr, "clsid:"); // 00024500-0000-0000-c000-000000000046 (Excel) ok + for (int i = 0; i < sizeof(CLSID); ++i) + fprintf(stderr, " %02x", ((unsigned char *)&clsid)[i]); + fprintf(stderr, "\n"); #endif - Handle vApp = V8Variant::CreateUndefined(); - BEVERIFY(done, !vApp.IsEmpty()); - BEVERIFY(done, !vApp->IsUndefined()); - BEVERIFY(done, vApp->IsObject()); - OCVariant *app = castedInternalField(vApp); - CHECK_OCV(app); - app->v.vt = VT_DISPATCH; - // When 'CoInitialize(NULL)' is not called first (and on the same instance), - // next functions will return many errors. - // (old style) GetActiveObject() returns 0x000036b7 - // The requested lookup key was not found in any active activation context. - // (OLE2) CoCreateInstance() returns 0x000003f0 - // An attempt was made to reference a token that does not exist. - REFIID riid = IID_IDispatch; // can't connect to Excel etc with IID_IUnknown + Handle vApp; + V8Variant::CreateUndefined(isolate, vApp); + BEVERIFY(done, !vApp.IsEmpty()); + BEVERIFY(done, !vApp->IsUndefined()); + BEVERIFY(done, vApp->IsObject()); + OCVariant *app = castedInternalField(vApp); + CHECK_OCV(app); + app->v.vt = VT_DISPATCH; + // When 'CoInitialize(NULL)' is not called first (and on the same instance), + // next functions will return many errors. + // (old style) GetActiveObject() returns 0x000036b7 + // The requested lookup key was not found in any active activation context. + // (OLE2) CoCreateInstance() returns 0x000003f0 + // An attempt was made to reference a token that does not exist. + REFIID riid = IID_IDispatch; // can't connect to Excel etc with IID_IUnknown + #ifdef DEBUG // obsolete (it needs that OLE target has been already executed) - IUnknown *pUnk; - hr = GetActiveObject(clsid, NULL, (IUnknown **)&pUnk); - BEVERIFY(done, !FAILED(hr)); - hr = pUnk->QueryInterface(riid, (void **)&app->v.pdispVal); - pUnk->Release(); + IUnknown *pUnk; + hr = GetActiveObject(clsid, NULL, (IUnknown **)&pUnk); + BEVERIFY(done, !FAILED(hr)); + hr = pUnk->QueryInterface(riid, (void **)&app->v.pdispVal); + pUnk->Release(); #else // C -> C++ changes types (&clsid -> clsid, &IID_IDispatch -> IID_IDispatch) // options (CLSCTX_INPROC_SERVER CLSCTX_INPROC_HANDLER CLSCTX_LOCAL_SERVER) - DWORD ctx = CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER; - hr = CoCreateInstance(clsid, NULL, ctx, riid, (void **)&app->v.pdispVal); - if(FAILED(hr)){ - // Retry with WOW6432 bridge option. - // This may not be a right way, but better. - BDISPFUNCDAT("FAILED CoCreateInstance: %d: 0x%08x\n", 0, hr); + DWORD ctx = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER; + hr = CoCreateInstance(clsid, NULL, ctx, riid, (void **)&app->v.pdispVal); + if (FAILED(hr)) { + // Retry with WOW6432 bridge option. + // This may not be a right way, but better. + BDISPFUNCDAT("FAILED CoCreateInstance: %d: 0x%08x\n", 0, hr); #if defined(_WIN64) - ctx |= CLSCTX_ACTIVATE_32_BIT_SERVER; // 32bit COM server on 64bit OS + ctx |= CLSCTX_ACTIVATE_32_BIT_SERVER; // 32bit COM server on 64bit OS #else - ctx |= CLSCTX_ACTIVATE_64_BIT_SERVER; // 64bit COM server on 32bit OS + ctx |= CLSCTX_ACTIVATE_64_BIT_SERVER; // 64bit COM server on 32bit OS #endif - hr = CoCreateInstance(clsid, NULL, ctx, riid, (void **)&app->v.pdispVal); - } + hr = CoCreateInstance(clsid, NULL, ctx, riid, (void **)&app->v.pdispVal); + } #endif - if(FAILED(hr)) BDISPFUNCDAT("FAILED CoCreateInstance: %d: 0x%08x\n", 1, hr); - BEVERIFY(done, !FAILED(hr)); - DISPFUNCOUT(); - return scope.Close(vApp); -done: - DISPFUNCOUT(); - return ThrowException(Exception::TypeError(String::New("Dispatch failed"))); -} - -Handle Client::Finalize(const Arguments& args) -{ - HandleScope scope; - DISPFUNCIN(); + if (FAILED(hr)) BDISPFUNCDAT("FAILED CoCreateInstance: %d: 0x%08x\n", 1, hr); + BEVERIFY(done, !FAILED(hr)); + DISPFUNCOUT(); + args.GetReturnValue().Set(vApp); + return; + done: + DISPFUNCOUT(); + RETURN_TYPE_ERROR("Dispatch failed"); + } + + void Client::Finalize(const FunctionCallbackInfo& args) + { + Isolate* isolate = args.GetIsolate(); + DISPFUNCIN(); #if(0) - std::cerr << __FUNCTION__ << " Finalizer is called\a" << std::endl; - std::cerr.flush(); + std::cerr << __FUNCTION__ << " Finalizer is called\a" << std::endl; + std::cerr.flush(); #endif - Local thisObject = args.This(); + Local thisObject = args.This(); #if(0) - Client *cl = ObjectWrap::Unwrap(thisObject); - if(cl) delete cl; // it has been already deleted ? - thisObject->SetInternalField(0, External::New(NULL)); + Client *cl = ObjectWrap::Unwrap(thisObject); + if (cl) delete cl; // it has been already deleted ? + thisObject->SetInternalField(0, External::New(NULL)); #endif #if(1) // now GC will call Disposer automatically - OLE32core *oc = castedInternalField(thisObject); - if(oc){ - try{ - delete oc; // will call oc->disconnect(); - }catch(OLE32coreException e){ std::cerr << e.errorMessage(__FUNCTION__); - }catch(char *e){ std::cerr << e << __FUNCTION__ << std::endl; - } - } + OLE32core *oc = castedInternalField(thisObject); + if (oc) { + try { + delete oc; // will call oc->disconnect(); + } + catch (OLE32coreException e) { + std::cerr << e.errorMessage(__FUNCTION__); + } + catch (char *e) { + std::cerr << e << __FUNCTION__ << std::endl; + } + } #endif - thisObject->SetInternalField(1, External::New(NULL)); - DISPFUNCOUT(); - return args.This(); -} - -void Client::Dispose(Persistent handle, void *param) -{ - DISPFUNCIN(); + thisObject->SetInternalField(1, External::New(isolate, NULL)); + args.GetReturnValue().Set(thisObject); + DISPFUNCOUT(); + } + + void Client::Dispose(Isolate* isolate, Persistent handle, void *param) + { + DISPFUNCIN(); #if(0) -// std::cerr << __FUNCTION__ << " Disposer is called\a" << std::endl; - std::cerr << __FUNCTION__ << " Disposer is called" << std::endl; - std::cerr.flush(); + // std::cerr << __FUNCTION__ << " Disposer is called\a" << std::endl; + std::cerr << __FUNCTION__ << " Disposer is called" << std::endl; + std::cerr.flush(); #endif - Local thisObject = handle->ToObject(); + Local thisObject = handle.Get(isolate)->ToObject(); #if(0) // it has been already deleted ? - Client *cl = ObjectWrap::Unwrap(thisObject); - if(!cl){ - std::cerr << __FUNCTION__; - std::cerr << " InternalField[0] has been already deleted" << std::endl; - std::cerr.flush(); - }else delete cl; // it has been already deleted ? - BEVERIFY(done, thisObject->InternalFieldCount() > 0); - thisObject->SetInternalField(0, External::New(NULL)); + Client *cl = ObjectWrap::Unwrap(thisObject); + if (!cl) { + std::cerr << __FUNCTION__; + std::cerr << " InternalField[0] has been already deleted" << std::endl; + std::cerr.flush(); + } + else delete cl; // it has been already deleted ? + BEVERIFY(done, thisObject->InternalFieldCount() > 0); + thisObject->SetInternalField(0, External::New(NULL)); #endif - OLE32core *p = castedInternalField(thisObject); - if(!p){ - std::cerr << __FUNCTION__; - std::cerr << " InternalField[1] has been already deleted" << std::endl; - std::cerr.flush(); - } -// else{ - OLE32core *oc = static_cast(param); // oc may be same as p - if(oc){ - try{ - delete oc; // will call oc->disconnect(); - }catch(OLE32coreException e){ std::cerr << e.errorMessage(__FUNCTION__); - }catch(char *e){ std::cerr << e << __FUNCTION__ << std::endl; - } + OLE32core *p = castedInternalField(thisObject); + if (!p) { + std::cerr << __FUNCTION__; + std::cerr << " InternalField[1] has been already deleted" << std::endl; + std::cerr.flush(); + } + // else{ + OLE32core *oc = static_cast(param); // oc may be same as p + if (oc) { + try { + delete oc; // will call oc->disconnect(); + } + catch (OLE32coreException e) { + std::cerr << e.errorMessage(__FUNCTION__); + } + catch (char *e) { + std::cerr << e << __FUNCTION__ << std::endl; + } + } + // } + BEVERIFY(done, thisObject->InternalFieldCount() > 1); + thisObject->SetInternalField(1, External::New(isolate, NULL)); + done: + handle.Reset(); + DISPFUNCOUT(); + } + + void Client::Finalize() + { + assert(!finalized); + finalized = true; } -// } - BEVERIFY(done, thisObject->InternalFieldCount() > 1); - thisObject->SetInternalField(1, External::New(NULL)); -done: - handle.Dispose(); - DISPFUNCOUT(); -} - -void Client::Finalize() -{ - assert(!finalized); - finalized = true; -} } // namespace node_win32ole diff --git a/src/client.h b/src/client.h index 6a06c77..5d93d86 100644 --- a/src/client.h +++ b/src/client.h @@ -11,14 +11,14 @@ class Client : public node::ObjectWrap { public: static Persistent clazz; static void Init(Handle target); - static Handle New(const Arguments& args); - static Handle Dispatch(const Arguments& args); - static Handle Finalize(const Arguments& args); + static void New(const FunctionCallbackInfo& args); + static void Dispatch(const FunctionCallbackInfo& args); + static void Finalize(const FunctionCallbackInfo& args); public: Client() : node::ObjectWrap(), finalized(false) {} ~Client() { if(!finalized) Finalize(); } protected: - static void Dispose(Persistent handle, void *param); + static void Dispose(Isolate* isolate, Persistent handle, void *param); void Finalize(); protected: bool finalized; diff --git a/src/force_gc_extension.cc b/src/force_gc_extension.cc index 0cfa897..8f43b52 100644 --- a/src/force_gc_extension.cc +++ b/src/force_gc_extension.cc @@ -10,41 +10,39 @@ using namespace ole32core; namespace node_win32ole { -Handle Method_force_gc_extension(const Arguments& args) // v8/gc : gc() -{ - BDISPFUNCDAT("context %s "__FUNCTION__" %s\n", "preset", "start"); - // create context with extension(s) - const char *extensionNames[] = {"v8/gc",}; - ExtensionConfiguration extensions( - sizeof(extensionNames) / sizeof(extensionNames[0]), extensionNames); - Handle global = ObjectTemplate::New(); - // another way get 'global' by ( global = context->Global() ) but no context - // Persistent context = Context::New(NULL, global); - Persistent context = Context::New(&extensions, global); - Context::Scope context_scope(context); - BDISPFUNCDAT("context %s "__FUNCTION__" %s\n", "preset", "end"); - HandleScope scope; - BDISPFUNCIN(); - Local sourceObj = String::New("gc()"); - TryCatch try_catch; - Local