├── .gitignore ├── Makefile ├── README.md ├── binding.gyp ├── examples ├── access_mdb_sample.js ├── activex_filesystemobject_sample.js ├── ie_sample.js ├── maze_creator.js ├── maze_solver.js ├── ole_args_test_client.js ├── ole_args_test_client_metamorphoses.js ├── ole_args_tester_client.py ├── ole_args_tester_server.py ├── outlook_sample.js ├── typelibrary_sample.js ├── uncfinder_sample.js ├── wmi_sample.js ├── word_sample.js └── wsh_sample.js ├── lib ├── index.js ├── trace.js └── win32ole.js ├── package.json ├── src ├── client.cc ├── client.h ├── force_gc_extension.cc ├── force_gc_internal.cc ├── node_win32ole.cc ├── node_win32ole.h ├── ole32core.cpp ├── ole32core.h ├── v8variant.cc ├── v8variant.h └── win32ole_gettimeofday.cc ├── test ├── init_win32ole.test.js └── unicode.test.js └── win32ole.js /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | node_modules 3 | Release 4 | Debug 5 | build 6 | out 7 | .deps 8 | .ref 9 | test/tmp 10 | *.*~ 11 | *.py[co] 12 | *.dylib 13 | *.so 14 | *.o 15 | *.obj 16 | *.lo 17 | *.Makefile 18 | *.target.gyp.mk 19 | Makefile.gyp 20 | gyp-mac-tool 21 | .dirstamp 22 | .lock-wscript 23 | .DS_Store 24 | Thumbs.db 25 | Desktop.ini 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # nmake build 2 | # nmake /a test 3 | # nmake clean 4 | 5 | # When using -g installed node-gyp 6 | #GYP = node-gyp 7 | # When using node.js-bundled node-gyp 8 | GYP = node "C:\Program Files (x86)\nodejs\node_modules\npm\node_modules\node-gyp\bin\node-gyp.js" 9 | 10 | PSRC = src 11 | HEADS_ = $(PSRC)/node_win32ole.h 12 | HEADS0 = $(HEADS_) $(PSRC)/ole32core.h 13 | HEADSA = $(HEADS0) $(PSRC)/v8variant.h $(PSRC)/client.h 14 | SRCS_ = $(PSRC)/force_gc_extension.cc $(PSRC)/force_gc_internal.cc 15 | SRCS0 = $(PSRC)/node_win32ole.cc $(PSRC)/win32ole_gettimeofday.cc 16 | SRCS1 = $(PSRC)/client.cc $(PSRC)/v8variant.cc $(PSRC)/ole32core.cpp 17 | SRCSA = $(SRCS_) $(SRCS0) $(SRCS1) 18 | POBJ = build/Release/obj/node_win32ole 19 | OBJS_ = $(POBJ)/force_gc_extension.obj $(POBJ)/force_gc_internal.obj 20 | OBJS0 = $(POBJ)/node_win32ole.obj $(POBJ)/win32ole_gettimeofday.obj 21 | OBJS1 = $(POBJ)/client.obj $(POBJ)/v8variant.obj $(POBJ)/ole32core.obj 22 | OBJSA = $(OBJS_) $(OBJS0) $(OBJS1) 23 | PTGT = build/Release 24 | PCNF = build 25 | TARGET = $(PTGT)/node_win32ole.node 26 | 27 | $(TARGET) : $(PCNF)/config.gypi # $(OBJSA) 28 | $(GYP) rebuild 29 | 30 | $(PCNF)/config.gypi : $(SRCSA) $(HEADSA) 31 | $(GYP) configure 32 | 33 | $(POBJ)/node_win32ole.obj : $(PSRC)/$(*B).cc $(PSRC)/$(*B).h $(PSRC)/client.h $(PSRC)/v8variant.h 34 | $(GYP) rebuild 35 | 36 | $(POBJ)/win32ole_gettimeofday.obj : $(PSRC)/$(*B).cc $(HEADS0) 37 | $(GYP) rebuild 38 | 39 | $(POBJ)/force_gc_extension.obj : $(PSRC)/$(*B).cc $(HEADS_) 40 | $(GYP) rebuild 41 | 42 | $(POBJ)/force_gc_internal.obj : $(PSRC)/$(*B).cc $(HEADS_) 43 | $(GYP) rebuild 44 | 45 | $(POBJ)/client.obj : $(PSRC)/$(*B).cc $(PSRC)/$(*B).h $(HEADS0) $(PSRC)/v8variant.h 46 | $(GYP) rebuild 47 | 48 | $(POBJ)/v8variant.obj : $(PSRC)/$(*B).cc $(PSRC)/$(*B).h $(HEADS0) 49 | $(GYP) rebuild 50 | 51 | $(POBJ)/ole32core.obj : $(PSRC)/$(*B).cpp $(PSRC)/$(*B).h 52 | $(GYP) rebuild 53 | 54 | build: # $(TARGET) 55 | $(GYP) configure 56 | $(GYP) build 57 | if exist test\tmp del /Q /S test\tmp\*.* 58 | if not exist test\tmp mkdir test\tmp 59 | 60 | clean: 61 | $(GYP) clean 62 | if exist test\tmp del /Q /S test\tmp\*.* 63 | if not exist test\tmp mkdir test\tmp 64 | 65 | test: build 66 | if exist test\tmp del /Q /S test\tmp\*.* 67 | if not exist test\tmp mkdir test\tmp 68 | set NODE_PATH=./lib;$(NODE_PATH) 69 | mocha -I lib test/init_win32ole.test 70 | mocha -I lib test/unicode.test 71 | node examples/maze_creator.js 72 | node examples/maze_solver.js 73 | node examples/word_sample.js 74 | node examples/access_mdb_sample.js 75 | node examples/outlook_sample.js 76 | node examples/ie_sample.js 77 | node examples/typelibrary_sample.js 78 | node examples/uncfinder_sample.js 79 | node examples/activex_filesystemobject_sample.js 80 | node examples/wmi_sample.js 81 | node examples/wsh_sample.js 82 | 83 | all: build test 84 | 85 | .PHONY: build test clean 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NAME 2 | 3 | node-win32ole - Asynchronous, non-blocking win32ole bindings for [node.js](https://github.com/joyent/node) powered by v8 engine . 4 | 5 | win32ole makes accessibility from node.js to Excel, Word, Access, Outlook, InternetExplorer, WSH ( ActiveXObject / COM ) and so on. It does not need TypeLibrary. 6 | 7 | 8 | # USAGE 9 | 10 | Install with `npm install win32ole`. 11 | 12 | It works as... (version 0.1.x) 13 | 14 | ``` js 15 | try{ 16 | var win32ole = require('win32ole'); 17 | // var xl = new ActiveXObject('Excel.Application'); // You may write it as: 18 | var xl = win32ole.client.Dispatch('Excel.Application'); 19 | xl.Visible = true; 20 | var book = xl.Workbooks.Add(); 21 | var sheet = book.Worksheets(1); 22 | try{ 23 | sheet.Name = 'sheetnameA utf8'; 24 | sheet.Cells(1, 2).Value = 'test utf8'; 25 | var rg = sheet.Range(sheet.Cells(2, 2), sheet.Cells(4, 4)); 26 | rg.RowHeight = 5.18; 27 | rg.ColumnWidth = 0.58; 28 | rg.Interior.ColorIndex = 6; // Yellow 29 | var result = book.SaveAs('testfileutf8.xls'); 30 | console.log(result); 31 | }catch(e){ 32 | console.log('(exception cached)\n' + e); 33 | } 34 | xl.ScreenUpdating = true; 35 | xl.Workbooks.Close(); 36 | xl.Quit(); 37 | }catch(e){ 38 | console.log('*** exception cached ***\n' + e); 39 | } 40 | ``` 41 | 42 | There are 3 ways to make force Garbage Collection for node.js / v8 . 43 | 44 | - 1. use huge memory to run GC automatically ( causes abnormal termination ) 45 | - 2. win32ole.force_gc_extension(1); 46 | - 3. win32ole.force_gc_internal(1); 47 | 48 | see also [examples/ole_args_test_client.js](https://github.com/idobatter/node-win32ole/blob/master/examples/ole_args_test_client.js) 49 | 50 | 51 | # Tutorial and Examples 52 | 53 | - [test/init_win32ole.test.js](https://github.com/idobatter/node-win32ole/blob/master/test/init_win32ole.test.js) 54 | - [test/unicode.test.js](https://github.com/idobatter/node-win32ole/blob/master/test/unicode.test.js) 55 | - [examples/maze_creator.js](https://github.com/idobatter/node-win32ole/blob/master/examples/maze_creator.js) 56 | - [examples/maze_solver.js](https://github.com/idobatter/node-win32ole/blob/master/examples/maze_solver.js) 57 | - [examples/word_sample.js](https://github.com/idobatter/node-win32ole/blob/master/examples/word_sample.js) 58 | - [examples/access_mdb_sample.js](https://github.com/idobatter/node-win32ole/blob/master/examples/access_mdb_sample.js) 59 | - [examples/outlook_sample.js](https://github.com/idobatter/node-win32ole/blob/master/examples/outlook_sample.js) 60 | - [examples/ie_sample.js](https://github.com/idobatter/node-win32ole/blob/master/examples/ie_sample.js) 61 | - [examples/typelibrary_sample.js](https://github.com/idobatter/node-win32ole/blob/master/examples/typelibrary_sample.js) 62 | - [examples/uncfinder_sample.js](https://github.com/idobatter/node-win32ole/blob/master/examples/uncfinder_sample.js) 63 | - [examples/activex_filesystemobject_sample.js](https://github.com/idobatter/node-win32ole/blob/master/examples/activex_filesystemobject_sample.js) 64 | - [examples/wmi_sample.js](https://github.com/idobatter/node-win32ole/blob/master/examples/wmi_sample.js) 65 | - [examples/wsh_sample.js](https://github.com/idobatter/node-win32ole/blob/master/examples/wsh_sample.js) 66 | - [examples/ole_args_test_client.js](https://github.com/idobatter/node-win32ole/blob/master/examples/ole_args_test_client.js) 67 | - [examples/ole_args_test_client_metamorphoses.js](https://github.com/idobatter/node-win32ole/blob/master/examples/ole_args_test_client_metamorphoses.js) 68 | 69 | 70 | # Other built in functions 71 | 72 | * win32ole.version(void) // returns version string 73 | * win32ole.printACP(utf8string) // Utf8 to .ACP 74 | * win32ole.print(utf8string) // ASCII 75 | * win32ole.gettimeofday(struct timeval &tv, null) // now arg2 is not used 76 | * win32ole.sleep(long milliseconds, bool withmessage=false, bool with\n=false) 77 | * win32ole.force_gc_extension(long flag) // now flag is dummy 78 | * win32ole.force_gc_internal(long flag, string) // now flag is dummy 79 | 80 | 81 | # FEATURES 82 | 83 | * fix BUG: date 84 | * BUG: A few samples in win32ole@0.1.0 needs '._' ideom. 85 | * When you use unary operator '!' at the place that needs boolean CONDITION (for example 'while(!obj.status){...}') , you must write 'while(!obj.status._){...}' to complete v8::Object::ToBoolean() conversion. (NamedPropertyHandler will not be called because v8::Object::ToBoolean() is called directly for unary operator '!' instead of v8::Object::valueOf() in ParseUnaryExpression() v8/src/parser.cc .) Do you know how to fake it? 86 | * V8Variant::OLEGetAttr returns a copy of object, so it uses much memory. I want to fix it. 87 | * Now '._' ideom is obsoleted. 88 | * Remove 'node-proxy' from dependencies list. 89 | * Change default branch to dev0.1.0 . 90 | * BUG: Some samples in between win32ole@0.0.25 and win32ole@0.0.28 ( examples/maze_creator.js examples/maze_solver.js ) uses huge memory and many disposers will run by v8 GC when maze size is 20*30. I think that each encapsulated V8Variant (by node-proxy) may be big object. So I will try to use v8 accessor handlers ( SetCallAsFunctionHandler / SetNamedPropertyHandler / SetIndexedPropertyHandler ) instead of ( '__noSuchMethod__' / '__noSuchGetter__' / '__noSuchSetter__' ) by node-proxy. 91 | * So much implements. (can not handle some COM VARIANT types, array etc.) 92 | * Bug fix. (throws exception when failed to Invoke(), and many test message.) 93 | * Implement accessors getter, setter and caller. (version 0.1.x) (Some V8Variants were advanced to 0.1.x .) 94 | 95 | 96 | # API 97 | 98 | See the [API documentation](https://github.com/idobatter/node-win32ole/wiki) in the wiki. 99 | 100 | 101 | # BUILDING 102 | 103 | This project uses VC++ 2008 Express (or later) and Python 2.6 (or later) . 104 | (When using Python 2.5, it needs [multiprocessing 2.5 back port](http://pypi.python.org/pypi/multiprocessing/) .) It needs neither ATL nor MFC. 105 | 106 | Bulding also requires node-gyp to be installed. You can do this with npm: 107 | 108 | npm install -g node-gyp 109 | 110 | To obtain and build the bindings: 111 | 112 | git clone git://github.com/idobatter/node-win32ole.git 113 | cd node-win32ole 114 | node-gyp configure 115 | node-gyp build 116 | 117 | You can also use [`npm`](https://github.com/isaacs/npm) to download and install them: 118 | 119 | npm install win32ole 120 | 121 | 122 | # TESTS 123 | 124 | [mocha](https://github.com/visionmedia/mocha) is required to run unit tests. 125 | 126 | npm install -g mocha 127 | nmake /a test 128 | 129 | 130 | # CONTRIBUTORS 131 | 132 | * [idobatter](https://github.com/idobatter) 133 | 134 | 135 | # ACKNOWLEDGEMENTS 136 | 137 | Inspired [Win32OLE](http://www.ruby-doc.org/stdlib/libdoc/win32ole/rdoc/) 138 | 139 | 140 | # LICENSE 141 | 142 | `node-win32ole` is [BSD licensed](https://github.com/idobatter/node-win32ole/raw/master/LICENSE). 143 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'targets': [ 3 | { 4 | 'target_name': 'node_win32ole', 5 | 'sources': [ 6 | 'src/node_win32ole.cc', 7 | 'src/win32ole_gettimeofday.cc', 8 | 'src/force_gc_extension.cc', 9 | 'src/force_gc_internal.cc', 10 | 'src/client.cc', 11 | 'src/v8variant.cc', 12 | 'src/ole32core.cpp' 13 | ], 14 | 'dependencies': [ 15 | ] 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /examples/access_mdb_sample.js: -------------------------------------------------------------------------------- 1 | var win32ole = require('win32ole'); 2 | win32ole.print('access_mdb_sample\n'); 3 | console.log(win32ole.version()); 4 | var path = require('path'); 5 | var cwd = path.join(win32ole.MODULEDIRNAME, '..'); 6 | 7 | var fs = require('fs'); 8 | var tmpdir = path.join(cwd, 'test/tmp'); 9 | if(!fs.existsSync(tmpdir)) fs.mkdirSync(tmpdir); 10 | var outfile = path.join(tmpdir, 'access_mdb_sample.mdb'); 11 | 12 | var display_or_edit_all = function(rs, ed){ 13 | var getRSvalue = function(rs, fieldname){ 14 | return rs.Fields(fieldname).Value; 15 | } 16 | rs.MoveFirst(); 17 | /* 18 | In ParseUnaryExpression() < v8/src/parser.cc > 19 | v8::Object::ToBoolean() is called directly for unary operator '!' 20 | instead of v8::Object::valueOf() 21 | so NamedPropertyHandler will not be called 22 | Local ToBoolean(); // How to fake ? override v8::Value::ToBoolean 23 | */ 24 | //while(rs.Eof != true){ // It works. (without unary operator !) 25 | //while(!rs.Eof){ // It does not work. 26 | while(!rs.Eof._){ // *** It works. oops! 27 | win32ole.print('id: '); 28 | win32ole.print(getRSvalue(rs, 'id')); 29 | win32ole.print(', c1: '); 30 | win32ole.print(getRSvalue(rs, 'c1')); 31 | win32ole.print(', c2: '); 32 | win32ole.print(getRSvalue(rs, 'c2')); 33 | win32ole.print(', c3: '); 34 | win32ole.print(getRSvalue(rs, 'c3')); 35 | win32ole.print('\n'); 36 | if(ed){ 37 | rs.Edit(); 38 | var id = getRSvalue(rs, 'id'); 39 | rs.Fields('c2').Value = id * 1000; 40 | rs.Update(); // rs.CancelUpdate(); 41 | } 42 | rs.MoveNext(); 43 | } 44 | }; 45 | 46 | var adox_sample = function(filename){ 47 | if(fs.existsSync(filename)) fs.unlinkSync(filename); 48 | console.log('creating mdb (by ADOX): "' + filename + '" ...'); 49 | var dsn = 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + filename + ';'; 50 | // dsn += ('Locale Identifier=' + CAT_LOCALE_(language)); 51 | var db = win32ole.client.Dispatch('ADOX.Catalog'); 52 | db.Create(dsn); 53 | var sql_create_table = 'create table testtbl (id autoincrement primary key,'; 54 | sql_create_table += ' c1 varchar(255), c2 integer, c3 varchar(255));'; 55 | var cn = db.ActiveConnection._; // *** 56 | cn.Execute(sql_create_table); 57 | for(var i = 11; i < 13; ++i){ 58 | var sql_insert = "insert into testtbl (c1, c2, c3) values"; 59 | sql_insert += " ('a(', " + i + ", ')z');"; 60 | cn.Execute(sql_insert); 61 | } 62 | console.log('open RS'); 63 | var rs = win32ole.client.Dispatch('ADODB.Recordset'); 64 | rs.ActiveConnection = cn; 65 | var sql_select = 'select * from testtbl;'; 66 | rs.Open(sql_select, cn, 1, 3); // adOpenKeyset, adLockOptimistic 67 | display_or_edit_all(rs, false); 68 | rs.Close(); 69 | rs = null; 70 | console.log('RS released'); 71 | cn.Close(); 72 | cn = null; 73 | // db.Finalize(); and db.Close() db.Disconnect() db.Release() is wrong 74 | db = null; 75 | console.log('disconnected (ADOX)'); 76 | }; 77 | 78 | var ole_automation_sample = function(filename){ 79 | console.log('open mdb (by OLE Automation): "' + filename + '" ...'); 80 | var mdb = win32ole.client.Dispatch('Access.Application'); 81 | mdb.Visible = true; 82 | // mdb.NewCurrentDatabase(filename); // to create new mdb 83 | mdb.OpenCurrentDatabase(filename); // to open exists mdb 84 | var cdb = mdb.CurrentDb(); 85 | for(var i = 101; i < 103; ++i){ 86 | var sql_insert = "insert into testtbl (c1, c2, c3) values"; 87 | sql_insert += " ('p(', " + i + ", ')q');"; 88 | cdb.Execute(sql_insert); 89 | } 90 | var sql_select = 'select * from testtbl;'; 91 | var rs = cdb.OpenRecordset(sql_select); 92 | display_or_edit_all(rs, true); 93 | display_or_edit_all(rs, false); 94 | rs.Close(); 95 | cdb.Close(); 96 | mdb.CloseCurrentDatabase(); 97 | mdb.Quit(1); // 1: acQuitSaveAll (default), 2: acQuitSaveNone 98 | cdb = null; 99 | mdb = null; 100 | console.log('disconnected (OLE Automation)'); 101 | }; 102 | 103 | try{ 104 | adox_sample(outfile); 105 | win32ole.sleep(2000, true, true); 106 | ole_automation_sample(outfile); 107 | }catch(e){ 108 | console.log('*** exception cached ***\n' + e); 109 | } 110 | -------------------------------------------------------------------------------- /examples/activex_filesystemobject_sample.js: -------------------------------------------------------------------------------- 1 | var win32ole = require('win32ole'); 2 | win32ole.print('activex_filesystemobject_sample\n'); 3 | 4 | var testfile = 'examples\\activex_filesystemobject_sample.js'; 5 | 6 | var activex_filesystemobject_sample = function(){ 7 | var withReadFile = function(filename, callback){ 8 | var fso = new ActiveXObject('Scripting.FileSystemObject'); 9 | var fullpath = fso.GetAbsolutePathName(filename); 10 | var file = fso.OpenTextFile(fullpath, 1, false); // open to read 11 | try{ 12 | callback(file); 13 | }finally{ 14 | file.Close(); 15 | } 16 | }; 17 | var withEachLine = function(filename, callback){ 18 | withReadFile(filename, function(file){ 19 | /* 20 | In ParseUnaryExpression() < v8/src/parser.cc > 21 | v8::Object::ToBoolean() is called directly for unary operator '!' 22 | instead of v8::Object::valueOf() 23 | so NamedPropertyHandler will not be called 24 | Local ToBoolean(); // How to fake ? override v8::Value::ToBoolean 25 | */ 26 | // while(file.AtEndOfStream != true) // It works. (without unary operator !) 27 | // while(!file.AtEndOfStream) // It does not work. 28 | while(!file.AtEndOfStream._) // *** It works. oops! 29 | callback(file.ReadLine()); 30 | }); 31 | }; 32 | withEachLine(testfile, function(line){ 33 | console.log(line); 34 | }); 35 | }; 36 | 37 | try{ 38 | activex_filesystemobject_sample(); 39 | }catch(e){ 40 | console.log('*** exception cached ***\n' + e); 41 | } 42 | -------------------------------------------------------------------------------- /examples/ie_sample.js: -------------------------------------------------------------------------------- 1 | var win32ole = require('win32ole'); 2 | win32ole.print('ie_sample\n'); 3 | 4 | var ie_sample = function(uris){ 5 | var ie = new ActiveXObject('InternetExplorer.Application'); 6 | ie.Visible = true; 7 | for(var i = 0; i < uris.length; ++i){ 8 | console.log(uris[i]); 9 | ie.Navigate(uris[i]); 10 | win32ole.sleep(15000, true, true); 11 | } 12 | ie.Quit(); 13 | }; 14 | 15 | try{ 16 | ie_sample([ 17 | 'http://www.google.com/', 18 | 'http://www.mozilla.org/', 19 | 'http://nodejs.org/']); 20 | }catch(e){ 21 | console.log('*** exception cached ***\n' + e); 22 | } 23 | -------------------------------------------------------------------------------- /examples/maze_creator.js: -------------------------------------------------------------------------------- 1 | // This is a test program to create so much objects. (Cells = V8Variant) 2 | // ( HEIGHT = 20, WIDTH = 30 ) 3 | var win32ole = require('win32ole'); 4 | win32ole.print('maze_creator\n'); 5 | console.log(win32ole.version()); 6 | var path = require('path'); 7 | var cwd = path.join(win32ole.MODULEDIRNAME, '..'); 8 | 9 | var fs = require('fs'); 10 | var tmpdir = path.join(cwd, 'test/tmp'); 11 | if(!fs.existsSync(tmpdir)) fs.mkdirSync(tmpdir); 12 | var mazefile = path.join(tmpdir, 'maze_sample.xls'); 13 | 14 | // These parameters must be same as maze_solver.js 15 | // colors 1: K 2: W 3: R 4: G 5: B 6: Y 7: M 8: C 16 | var HEIGHT = 20, WIDTH = 30, OFFSET_ROW = 2, OFFSET_COL = 2; 17 | var MAX_ROW = OFFSET_ROW + HEIGHT - 1, MAX_COL = OFFSET_COL + WIDTH - 1; 18 | var sheet = null; 19 | 20 | var mat = function(r, c){ 21 | return sheet.Cells(OFFSET_ROW + r, OFFSET_COL + c); 22 | }; 23 | 24 | var isPassed = function(r, c){ 25 | try{ 26 | return mat(r, c).Interior.ColorIndex != 6 // Y 27 | }catch(e){ 28 | return true; 29 | } 30 | }; 31 | 32 | var isDeadend = function(r, c){ 33 | for(var d = 0; d < 4; ++d){ 34 | var dr = d == 3 ? 1 : d == 2 ? -1 : 0; 35 | var dc = d == 1 ? 1 : d == 0 ? -1 : 0; 36 | if(!isPassed(r + dr, c + dc)) return false; 37 | } 38 | return true; 39 | }; 40 | 41 | var drawWall = function(r, c, dlist){ 42 | var e = mat(r, c); 43 | for(var d = 0; d < 4; ++d) 44 | if(dlist[d] == 0) e.Borders(1 + d).Weight = 2; 45 | }; 46 | 47 | var dig = function(r, c, direc, count){ 48 | var dlist = [0, 0, 0, 0]; 49 | if(direc >= 0) dlist[[1, 0, 3, 2][direc]] = 1; 50 | mat(r, c).Interior.ColorIndex = 4; // G 51 | if(--count == 0) return drawWall(r, c, dlist); 52 | while(true){ 53 | if(isDeadend(r, c)) return drawWall(r, c, dlist); 54 | var d = Math.floor(Math.random() * 4); 55 | var dr = d == 3 ? 1 : d == 2 ? -1 : 0; 56 | var dc = d == 1 ? 1 : d == 0 ? -1 : 0; 57 | if(!isPassed(r + dr, c + dc)){ 58 | dlist[d] = 1; 59 | dig(r + dr, c + dc, d, count); 60 | } 61 | } 62 | }; 63 | 64 | var maze_excel_ole = function(filename){ 65 | var xl = win32ole.client.Dispatch('Excel.Application'); 66 | xl.Visible = true; 67 | var book = xl.Workbooks.Add(); 68 | // This code uses variable sheet as global 69 | sheet = book.Worksheets(1); 70 | try{ 71 | sheet.Name = 'maze'; 72 | sheet.Cells(1, 2).Value = 'maze'; 73 | var rg = sheet.Range( 74 | sheet.Cells(OFFSET_ROW, OFFSET_COL), sheet.Cells(MAX_ROW, MAX_COL)); 75 | rg.RowHeight = 5.18; 76 | rg.ColumnWidth = 0.58; 77 | rg.Interior.ColorIndex = 6; // Yellow 78 | // Math.random() seed is automatically set 79 | dig(HEIGHT - 1, WIDTH - 1, -1, WIDTH * HEIGHT); 80 | console.log('saving to: "' + filename + '" ...'); 81 | var result = book.SaveAs(filename); 82 | console.log(result); 83 | }catch(e){ 84 | console.log('(exception cached)\n' + e); 85 | } 86 | xl.ScreenUpdating = true; 87 | xl.Workbooks.Close(); 88 | xl.Quit(); 89 | }; 90 | 91 | try{ 92 | maze_excel_ole(mazefile); 93 | }catch(e){ 94 | console.log('*** exception cached ***\n' + e); 95 | } 96 | -------------------------------------------------------------------------------- /examples/maze_solver.js: -------------------------------------------------------------------------------- 1 | // This is a test program to create so much objects. (Cells = V8Variant) 2 | // ( HEIGHT = 20, WIDTH = 30 ) 3 | var win32ole = require('win32ole'); 4 | win32ole.print('maze_solver\n'); 5 | console.log(win32ole.version()); 6 | var path = require('path'); 7 | var cwd = path.join(win32ole.MODULEDIRNAME, '..'); 8 | 9 | var fs = require('fs'); 10 | var tmpdir = path.join(cwd, 'test/tmp'); 11 | if(!fs.existsSync(tmpdir)) fs.mkdirSync(tmpdir); 12 | var mazefile = path.join(tmpdir, 'maze_sample.xls'); 13 | 14 | // These parameters must be same as maze_creator.js 15 | // colors 1: K 2: W 3: R 4: G 5: B 6: Y 7: M 8: C 16 | var HEIGHT = 20, WIDTH = 30, OFFSET_ROW = 2, OFFSET_COL = 2; 17 | var MAX_ROW = OFFSET_ROW + HEIGHT - 1, MAX_COL = OFFSET_COL + WIDTH - 1; 18 | var sheet = null; 19 | 20 | var mat = function(r, c){ 21 | return sheet.Cells(OFFSET_ROW + r, OFFSET_COL + c); 22 | }; 23 | 24 | var isExit = function(r, c){ 25 | return (r == HEIGHT - 1) && (c == WIDTH - 1); 26 | }; 27 | 28 | var isWall = function(r, c, d){ 29 | var linestyle = mat(r, c).Borders(1 + d).LineStyle; 30 | if(linestyle == 1) return true; 31 | var dr = d == 3 ? 1 : d == 2 ? -1 : 0; 32 | var dc = d == 1 ? 1 : d == 0 ? -1 : 0; 33 | var color = mat(r + dr, c + dc).Interior.ColorIndex; 34 | if(color == 7 || color == 8) return true; // M or C 35 | return false; 36 | }; 37 | 38 | var isDeadendWall = function(r, c, direc){ 39 | if(direc < 0) return false; 40 | for(var d = 0; d < 4; ++d){ 41 | if([1, 0, 3, 2][direc] == d) continue; 42 | if(!isWall(r, c, d)) return false; 43 | } 44 | return true; 45 | }; 46 | 47 | var drawPath = function(r, c, solved, branch){ 48 | var color = (solved && !branch) ? 8 : 7; // C or M 49 | mat(r, c).Interior.ColorIndex = color; 50 | return solved; 51 | }; 52 | 53 | var dug = function(r, c, direc, solved, branch){ 54 | var dlist = [0, 0, 0, 0]; 55 | if(direc >= 0) dlist[[1, 0, 3, 2][direc]] = 1; 56 | mat(r, c).Interior.ColorIndex = 6; // Y 57 | while(true){ 58 | if(isExit(r, c)) solved = true; 59 | if(isDeadendWall(r, c, direc)) return drawPath(r, c, solved, branch); 60 | var d = Math.floor(Math.random() * 4); 61 | if(dlist[d] == 1) continue; 62 | dlist[d] = 1; 63 | if(isWall(r, c, d)) continue; 64 | var dr = d == 3 ? 1 : d == 2 ? -1 : 0; 65 | var dc = d == 1 ? 1 : d == 0 ? -1 : 0; 66 | solved = dug(r + dr, c + dc, d, solved, solved); 67 | } 68 | }; 69 | 70 | var solver_excel_ole = function(filename){ 71 | var xl = win32ole.client.Dispatch('Excel.Application'); 72 | xl.Visible = true; 73 | var book = xl.Workbooks.Open(filename); 74 | // This code uses variable sheet as global 75 | sheet = book.Worksheets(1); 76 | try{ 77 | var rg = sheet.Range( 78 | sheet.Cells(OFFSET_ROW, OFFSET_COL), sheet.Cells(MAX_ROW, MAX_COL)); 79 | // Math.random() seed is automatically set 80 | dug(0, 0, 3, false, false); 81 | console.log('saving to: "' + filename + '" ...'); 82 | var result = book.SaveAs(filename); 83 | console.log(result); 84 | }catch(e){ 85 | console.log('(exception cached)\n' + e); 86 | } 87 | xl.ScreenUpdating = true; 88 | xl.Workbooks.Close(); 89 | xl.Quit(); 90 | }; 91 | 92 | try{ 93 | solver_excel_ole(mazefile); 94 | }catch(e){ 95 | console.log('*** exception cached ***\n' + e); 96 | } 97 | -------------------------------------------------------------------------------- /examples/ole_args_test_client.js: -------------------------------------------------------------------------------- 1 | /* 2 | How to use it on Windows 7/Vista: 3 | 1. register server 4 | 1-1. Enable your PC's Administrator account. 5 | 1-2. runas /user:administrator "python ole_args_tester_server.py" 6 | 2. node ole_args_test_client.js 7 | */ 8 | 9 | var win32ole = require('win32ole'); 10 | win32ole.print('ole_args_test_client\n'); 11 | 12 | var ole_args_test_client = function(){ 13 | console.log('create connection'); 14 | var cl = win32ole.client.Dispatch('OLEArgsTester.Server'); 15 | console.log('connected'); 16 | cl.call('Init'); 17 | console.log('do A'); 18 | console.log(cl.subname = 'YoY'); 19 | console.log('do B'); 20 | console.log(cl.subname); 21 | console.log('do 1'); 22 | console.log(cl.call('Test', ['a'])); 23 | console.log('do 2'); 24 | console.log(cl.call('Test', ['a1', 'b2'])); 25 | console.log('do 3'); 26 | console.log(cl.call('Test', ['aa1', 'bb2', 'cc3'])); 27 | console.log('do 4'); 28 | console.log(cl.call('Test', ['aaa1', 'bbb2', 'ccc3', 'ddd4'])); 29 | console.log('quit'); 30 | cl.call('Quit'); 31 | console.log('disconnected'); 32 | 33 | // process.on('exit'...) will *NOT* be called when there is not enough memory 34 | var force_gc = function(){ 35 | // cl = null; // V8Variant.Dispose() will be called when cl is *NOT* null 36 | // win32ole.client = null; // Client.Dispose() will be called only if null 37 | console.log('a'); 38 | for(var a = [], i = 0; i < 869461; i++){ a[i] = 'dummydata'; } // GC test 39 | console.log('b'); 40 | for(var b = [], j = 0; j < 2944; j++){ b[j] = 'bbbbbbbb'; } // GC test 41 | console.log('c'); 42 | for(var c = [], k = 0; k < 848; k++){ c[k] = 'cccccccc'; } // GC test 43 | console.log('d'); 44 | for(var d = [], l = 0; l < 358; l++){ d[l] = 'dddddddd'; } // GC test 45 | } 46 | 47 | // force GC (disposer will *NOT* be called if GC is not run) 48 | var forceGCmode = 0; // 0, 1, 2, 3 49 | switch(forceGCmode){ 50 | case 1: force_gc(); break; 51 | case 2: win32ole.force_gc_extension(1); break; 52 | case 3: win32ole.force_gc_internal(1); break; 53 | default: break; // do nothing 54 | } 55 | 56 | console.log('completed'); 57 | }; 58 | 59 | try{ 60 | ole_args_test_client(); 61 | }catch(e){ 62 | console.log('*** exception cached ***\n' + e); 63 | } 64 | -------------------------------------------------------------------------------- /examples/ole_args_test_client_metamorphoses.js: -------------------------------------------------------------------------------- 1 | /* 2 | How to use it on Windows 7/Vista: 3 | 1. register server 4 | 1-1. Enable your PC's Administrator account. 5 | 1-2. runas /user:administrator "python ole_args_tester_server.py" 6 | 2. node ole_args_test_client_metamorphoses.js 7 | ( win32ole.client.Dispatch must be overrided by metamorphoses proxy ) 8 | */ 9 | 10 | var win32ole = require('win32ole'); 11 | win32ole.print('ole_args_test_client_metamorphoses\n'); 12 | 13 | var ole_args_test_client_metamorphoses = function(){ 14 | console.log('test'); 15 | var cl = win32ole.client.Dispatch('OLEArgsTester.Server'); 16 | console.log('connected (and metamorphoses proxy when wrapped)'); 17 | console.log('test caller'); 18 | cl.Init(); // cl.call('Init'); 19 | console.log('test arguments (call)'); 20 | console.log(cl.call('Test', ['a', 'b', 'c', 'd'])); 21 | console.log('test arguments (__noSuchMethod__)'); 22 | console.log(cl.Test('a1')); 23 | console.log(cl.Test('a2', 'b2')); 24 | console.log(cl.Test('a3', 'b3', 'c3')); 25 | console.log(cl.Test('a4', 'b4', 'c4', 'd4')); 26 | console.log('test getter (call)'); 27 | console.log(cl.call('GetSubName')); 28 | console.log('test arguments (__noSuchMethod__) * this is not a setter *'); 29 | console.log(cl.SetSubName('cba')); 30 | console.log('test getter (*** __noSuchMethod__ ***)'); 31 | console.log(cl.GetSubName()); 32 | // console.log('test getter (*** __noSuchGetter__ ***)'); 33 | // console.log(cl.GetSubName._); // ERROR: method MUST NOT be called as getter 34 | console.log('test setter attr (__noSuchSetter__)'); 35 | console.log(cl.subname = 'zyx'); 36 | console.log('test getter attr (*** __noSuchGetter__ ***)'); 37 | console.log(cl.subname); // [object V8Variant] (called cl.subname.inspect) 38 | console.log(cl.subname.toUtf8()); // instance method (obsoleted) 39 | // discussed about __noSuchProperty__ 40 | // https://mail.mozilla.org/pipermail/es-discuss/2010-October/011930.html 41 | console.log(cl.subname._); // (obsoleted) 42 | console.log('test getter accessor (*** __noSuchMethod__ ***)'); 43 | console.log(cl.subname()); // getter may be called as method (obsoleted) 44 | console.log('test getter (*** __noSuchMethod__ ***)'); 45 | console.log(cl.GetSubName()); 46 | console.log('quit'); 47 | cl.Quit(); // cl.call('Quit'); 48 | console.log('completed'); 49 | }; 50 | 51 | try{ 52 | ole_args_test_client_metamorphoses(); 53 | }catch(e){ 54 | console.log('*** exception cached ***\n' + e); 55 | } 56 | -------------------------------------------------------------------------------- /examples/ole_args_tester_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # -*- coding: utf-8 -*- 3 | '''OLE_args_tester_client 4 | How to use it on Windows 7/Vista: 5 | 1. register server 6 | 1-1. Enable your PC's Administrator account. 7 | 1-2. runas /user:administrator "python ole_args_tester_server.py" 8 | 2. python ole_args_tester_client.py 9 | ''' 10 | 11 | import win32com.client 12 | 13 | def main(): 14 | cl = win32com.client.Dispatch('OLEArgsTester.Server') 15 | cl.Init() 16 | print cl.Test('a', 'b', 'c', 'd') 17 | print cl.GetSubName() 18 | print cl.SetSubName('xyz') 19 | print cl.GetSubName() 20 | print cl.subname 21 | cl.subname = 'ooo' 22 | print cl.GetSubName() 23 | cl.Quit() 24 | 25 | if __name__ == '__main__': 26 | main() 27 | -------------------------------------------------------------------------------- /examples/ole_args_tester_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # -*- coding: utf-8 -*- 3 | '''OLE_args_tester_server 4 | How to use it on Windows 7/Vista: 5 | 1. register server 6 | 1-1. Enable your PC's Administrator account. 7 | 1-2. runas /user:administrator "python ole_args_tester_server.py" 8 | 2. python ole_args_tester_client.py 9 | 10 | optional ( to unregister this server ) runas administrator 11 | 3. python ole_args_tester_server.py --unregister 12 | ''' 13 | 14 | class OLEArgsTesterServer: 15 | _public_methods_ = ['Init', 'Test', 'GetSubName', 'SetSubName', 'Quit'] 16 | _public_attrs_ = ['subname'] 17 | _reg_progid_ = 'OLEArgsTester.Server' 18 | # NEVER copy the ProgID / CLSID 19 | # Use "print pythoncom.CreateGuid()" to make a new one. 20 | _reg_clsid_ = '{4866809D-FCD5-498E-93D5-FA78949CC1DA}' 21 | 22 | def Init(self): 23 | self.name = OLEArgsTesterServer._reg_progid_ 24 | self.subname = unicode('%s(%s)' % ('subname', self.name)) 25 | 26 | def Test(self, a0, a1=None, a2=None, a3=None): 27 | s = [unicode(a0), unicode(a1), unicode(a2), unicode(a3)] 28 | return u'test: %s' % u', '.join(s) 29 | 30 | def GetSubName(self, a0=None): 31 | return self.subname 32 | 33 | def SetSubName(self, sn): 34 | self.subname = u'%s(%s)' % (unicode(sn), unicode(self.name)) 35 | return None 36 | 37 | def Quit(self): 38 | return None 39 | 40 | if __name__ == '__main__': 41 | print 'Registering ole_args_tester_server...' 42 | import win32com.server.register 43 | win32com.server.register.UseCommandLine(OLEArgsTesterServer) 44 | -------------------------------------------------------------------------------- /examples/outlook_sample.js: -------------------------------------------------------------------------------- 1 | var win32ole = require('win32ole'); 2 | win32ole.print('outlook_sample\n'); 3 | 4 | var outlook_sample = function(){ 5 | var ol = win32ole.client.Dispatch('Outlook.Application'); 6 | // ol.Visible = true; 7 | var ns = ol.GetNameSpace('MAPI'); 8 | win32ole.print('mail:\n'); 9 | var frcv = ns.GetDefaultFolder(6); // receive mail box tray 10 | var items = frcv.Items._; // *** 11 | var count = items.Count; 12 | for(var n = 1; n <= count; ++n){ 13 | win32ole.print(' ' + n + ' : '); 14 | var i = items.Item(n); 15 | win32ole.printACP(i.Subject); 16 | win32ole.print('\n'); 17 | } 18 | win32ole.print('schedule:\n'); 19 | var fcal = ns.GetDefaultFolder(9); // olFolderCalendar (schedule) 20 | if(true){ 21 | var apnt = ol.CreateItem(1); // olAppointmentItem 22 | var t = new Date(); 23 | apnt.Start = t; 24 | t.setTime(t.getTime() + 30 * 60 * 1000); // + 30 minutes 25 | apnt.End = t; 26 | apnt.Subject = 'TTEESSTT'; 27 | apnt.Body = 'bodybodybody'; 28 | apnt.Location = 'node'; 29 | apnt.Sensitivity = 0; // olNormal 30 | apnt.ReminderSet = true; 31 | apnt.ReminderMinutesBeforeStart = 120; // minutes 32 | apnt.Save(); 33 | } 34 | // var apnts = fcal.Items._; // *** 35 | var apnts = fcal.Items.restrict('[Start] >= "26/02/2013 09:30"'); 36 | var acnt = apnts.Count; 37 | for(var n = 1; n <= acnt; ++n){ 38 | win32ole.print(' ' + n + ' : '); 39 | /* 40 | var apnt = apnts.Item(n); 41 | var ptn = apnt.GetRecurrencePattern(); 42 | var i = ptn.GetOccurrence(new Date(2013, 2, 13, 13, 30, 0)); // month - 1 43 | */ 44 | var i = apnts.Item(n); 45 | win32ole.print('DateTime: ( from '); 46 | win32ole.printACP(i.Start._); 47 | win32ole.print(' to '); 48 | win32ole.printACP(i.End._); 49 | win32ole.print(' )\n'); 50 | win32ole.printACP(' Subject: ' + i.Subject); 51 | win32ole.print('\n'); 52 | win32ole.printACP(' Body: ' + i.Body); 53 | win32ole.print('\n'); 54 | win32ole.printACP(' Location: ' + i.Location); 55 | win32ole.print('\n'); 56 | } 57 | // ol.Quit(); 58 | }; 59 | 60 | try{ 61 | outlook_sample(); 62 | }catch(e){ 63 | console.log('*** exception cached ***\n' + e); 64 | } 65 | -------------------------------------------------------------------------------- /examples/typelibrary_sample.js: -------------------------------------------------------------------------------- 1 | var win32ole = require('win32ole'); 2 | win32ole.print('typelibrary_sample\n'); 3 | -------------------------------------------------------------------------------- /examples/uncfinder_sample.js: -------------------------------------------------------------------------------- 1 | var win32ole = require('win32ole'); 2 | win32ole.print('uncfinder_sample\n'); 3 | console.log(win32ole.version()); 4 | var path = require('path'); 5 | var cwd = path.join(win32ole.MODULEDIRNAME, '..'); 6 | 7 | var fs = require('fs'); 8 | var tmpdir = path.join(cwd, 'test/tmp'); 9 | if(!fs.existsSync(tmpdir)) fs.mkdirSync(tmpdir); 10 | var outfile = path.join(tmpdir, 'uncfinder_sample.txt'); 11 | 12 | var uncfinder_sample = function(filename){ 13 | var wnt = win32ole.client.Dispatch('WinNTSystemInfo'); 14 | console.log('ComputerName:'); 15 | console.log(wnt.ComputerName); 16 | console.log('DomainName:'); 17 | console.log(wnt.DomainName); 18 | console.log('PDC:'); 19 | //console.log(wnt.PDC); // *** IsUndefined() -> return NULL -> new OCVariant(?) 20 | //console.log(wnt.PDC._); // *** It does not work, too. 21 | console.log('UserName:'); 22 | console.log(wnt.UserName); 23 | }; 24 | 25 | try{ 26 | uncfinder_sample(outfile); 27 | }catch(e){ 28 | console.log('*** exception cached ***\n' + e); 29 | } 30 | -------------------------------------------------------------------------------- /examples/wmi_sample.js: -------------------------------------------------------------------------------- 1 | /* 2 | WMI Scripting Library Object Model 3 | http://technet.microsoft.com/en-us/library/ee198924.aspx 4 | Scripting API Objects 5 | http://msdn.microsoft.com/en-us/library/aa393259%28v=vs.85%29.aspx 6 | SWbemObjectSet object (Windows) 7 | http://msdn.microsoft.com/en-us/library/aa393762%28v=vs.85%29.aspx 8 | SWbemObjectSet::ItemIndex method (Windows) 9 | http://msdn.microsoft.com/en-us/library/aa826600%28v=vs.85%29.aspx 10 | Enumerating WMI 11 | http://msdn.microsoft.com/en-us/library/aa390386%28v=vs.85%29.aspx 12 | SWbemObjectSet is received from SWbemServices.ExecQuery 13 | COM API for WMI 14 | http://msdn.microsoft.com/en-us/library/aa389276%28v=vs.85%29.aspx 15 | (C++) IEnumWbemClassObject is received from IWbemServices::ExecQuery 16 | */ 17 | var win32ole = require('win32ole'); 18 | win32ole.print('wmi_sample\n'); 19 | console.log(win32ole.version()); 20 | var path = require('path'); 21 | var cwd = path.join(win32ole.MODULEDIRNAME, '..'); 22 | 23 | var fs = require('fs'); 24 | var tmpdir = path.join(cwd, 'test/tmp'); 25 | if(!fs.existsSync(tmpdir)) fs.mkdirSync(tmpdir); 26 | var outfile = path.join(tmpdir, 'wmi_sample.txt'); 27 | 28 | var safeutf8 = function(obj, propertyname){ 29 | var property = obj.get(propertyname); // *** 30 | // return property.isA() == 1 ? 'NULL' : property; 31 | // return property.vtName() == 'VT_NULL' ? 'NULL' : property; 32 | return property == null ? 'NULL' : property; 33 | }; 34 | 35 | var get_value_from_key = function(kv, key){ 36 | // search from kv where Item['Name'] == key, return found Item['Value'] 37 | try{ 38 | var item = kv.Item(key); 39 | try{ 40 | return safeutf8(item, 'Value'); 41 | }catch(e){ 42 | return key + ': *** BUG type missmatch (process int32 or array) ***'; 43 | } 44 | }catch(e){ 45 | return key + ': *** BUG no object (process OCVariant::AutoWrap) ***'; 46 | } 47 | }; 48 | 49 | var wmi_sample = function(filename){ 50 | var locator = win32ole.client.Dispatch('WbemScripting.SWbemLocator'); 51 | var svr = locator.ConnectServer('.', 'root/cimv2'); // . = self PC 52 | try{ 53 | if(fs.existsSync(filename)) fs.unlinkSync(filename); 54 | console.log('*** get processes (partial) ***'); 55 | var query = "select * from Win32_Process where Name like '%explore%'"; 56 | query += " or Name='rundll32.exe' or Name='winlogon.exe'"; 57 | var procset = svr.ExecQuery(query); 58 | console.log('procset is a ' + procset.vtName()); // ( SWbemObjectSet ) 59 | var count = procset.Count; 60 | console.log('count = ' + count); 61 | console.log(' ImageName, ProcessId, VirtualSize, Threads, Description,'); 62 | console.log(' [ImagePath]'); 63 | console.log(' [CommandLine],'); 64 | for(var i = 0; i < count; ++i){ 65 | var proc = procset.ItemIndex(i); 66 | var imgpath = safeutf8(proc, 'ExecutablePath'); 67 | var cmdline = safeutf8(proc, 'CommandLine'); 68 | var size = imgpath.length + 1; 69 | if(imgpath.match(/[\s]+/ig)) size += 2; 70 | win32ole.printACP( 71 | '-> ' + safeutf8(proc, 'Name') 72 | + ', ' + proc.ProcessId 73 | + ', ' + safeutf8(proc, 'VirtualSize') 74 | + ', ' + proc.ThreadCount 75 | + ', ' + safeutf8(proc, 'Description') 76 | + '\n [' + imgpath 77 | + ']\n [' + cmdline.substring(size) 78 | + ']\n'); 79 | } 80 | console.log('*** get services (first 10 items) ***'); 81 | var svcset = svr.ExecQuery('select * from Win32_Service'); 82 | count = svcset.Count; 83 | console.log('count = ' + count); 84 | for(var i = 0; i < 10; ++i){ 85 | var svc = svcset.ItemIndex(i); 86 | var q = svc.Qualifiers_._; // *** 87 | win32ole.printACP( 88 | '-> ' + get_value_from_key(q, 'provider') 89 | + '\n [' + get_value_from_key(q, 'UUID') 90 | + ']\n'); 91 | var p = svc.Properties_._; // *** 92 | win32ole.printACP( 93 | ' ' + get_value_from_key(p, 'Name') 94 | + '\n [' + get_value_from_key(p, 'PathName') 95 | + ']\n'); 96 | var np = function(m, na){ 97 | for(var j = 0; j < na.length; ++j){ 98 | console.log(' method Qualifiers_: ' + na[j]); 99 | var me = m.Item(na[j]); 100 | var mq = me.Qualifiers_._; // *** 101 | win32ole.printACP( 102 | ' [' + get_value_from_key(mq, 'Override') 103 | + ']\n [' + get_value_from_key(mq, 'Static') // Boolean 104 | + ']\n [' + get_value_from_key(mq, 'MappingStrings') // Array 105 | + ']\n [' + get_value_from_key(mq, 'ValueMap') // Array 106 | + ']\n'); 107 | } 108 | }; 109 | var m = svc.Methods_; 110 | console.log(' methods: ' + m.Count); 111 | if(true){ 112 | // do nothing here because there are too many bugs (get_value_from_key) 113 | // np(m, [me.Name for me in svc.Methods_]); // dummy code (as python) 114 | }else{ 115 | // for each me.Name is not taken from svc.Methods_ ... (version 0.0.x) 116 | np(m, ['StartService', 'StopService', 'PauseService', 'ResumeService', 117 | 'InterrogateService', 'UserControlService', 118 | 'Create', 'Change', 'ChangeStartMode', 'Delete', 119 | 'GetSecurityDescriptor', 'SetSecurityDescriptor']); 120 | } 121 | } 122 | }catch(e){ 123 | console.log('(exception catched)\n' + e); 124 | } 125 | 126 | console.log('completed'); 127 | }; 128 | 129 | try{ 130 | wmi_sample(outfile); 131 | }catch(e){ 132 | console.log('*** exception cached ***\n' + e); 133 | } 134 | -------------------------------------------------------------------------------- /examples/word_sample.js: -------------------------------------------------------------------------------- 1 | var win32ole = require('win32ole'); 2 | win32ole.print('word_sample\n'); 3 | console.log(win32ole.version()); 4 | var path = require('path'); 5 | var cwd = path.join(win32ole.MODULEDIRNAME, '..'); 6 | 7 | var fs = require('fs'); 8 | var tmpdir = path.join(cwd, 'test/tmp'); 9 | if(!fs.existsSync(tmpdir)) fs.mkdirSync(tmpdir); 10 | var outfile = path.join(tmpdir, 'word_sample.doc'); 11 | 12 | var word_sample = function(filename){ 13 | var wd = win32ole.client.Dispatch('Word.Application'); 14 | wd.Visible = true; 15 | var doc = wd.Documents.Add(); 16 | var para = doc.Content.Paragraphs.Add(); 17 | para.Range.Text = 'stringUTF8'; 18 | try{ 19 | console.log('saving to: "' + filename + '" ...'); 20 | var result = doc.SaveAs(filename); 21 | console.log(result); // *** undefined 22 | }catch(e){ 23 | console.log('(exception cached)\n' + e); 24 | } 25 | wd.Documents.Close(); 26 | wd.Quit(); 27 | }; 28 | 29 | try{ 30 | word_sample(outfile); 31 | }catch(e){ 32 | console.log('*** exception cached ***\n' + e); 33 | } 34 | -------------------------------------------------------------------------------- /examples/wsh_sample.js: -------------------------------------------------------------------------------- 1 | var win32ole = require('win32ole'); 2 | win32ole.print('wsh_sample\n'); 3 | console.log(win32ole.version()); 4 | var path = require('path'); 5 | var cwd = path.join(win32ole.MODULEDIRNAME, '..'); 6 | 7 | var fs = require('fs'); 8 | var tmpdir = path.join(cwd, 'test/tmp'); 9 | if(!fs.existsSync(tmpdir)) fs.mkdirSync(tmpdir); 10 | var outfile = path.join(tmpdir, 'wsh_sample.txt'); 11 | 12 | var wsh_sample = function(filename){ 13 | var sh = win32ole.client.Dispatch('WScript.Shell'); 14 | console.log('sh:'); 15 | // console.log(require('util').inspect(sh.__, true, null, true)); // {} 16 | //console.log(require('util').inspect(sh, true, null, true)); // *** error 17 | 18 | try{ 19 | 20 | if(fs.existsSync(filename)) fs.unlinkSync(filename); 21 | win32ole.print('notepad ...'); 22 | // arg1=1: movetop (default), 2: minimize, 3: maximize, 4: no movetop 23 | // 5: movetop, 6: minimize, 7: minimize 24 | // arg2=false: Async (default), true: Sync 25 | sh.Run('notepad.exe', 1, false); // must be Async (for SendKeys) 26 | win32ole.sleep(3000, true, false); 27 | sh.SendKeys('Congratulations!{ENTER}'); // 'Run' option must be 1 28 | win32ole.sleep(200); 29 | sh.SendKeys("*** DON'T TOUCH THIS WINDOW ***{ENTER}"); 30 | win32ole.sleep(3000); 31 | sh.SendKeys('Saving filename will be entered automatically.'); 32 | win32ole.sleep(3000); 33 | sh.SendKeys('%f'); // ALT-F (File) 34 | win32ole.sleep(500); 35 | sh.SendKeys('a'); // SaveAs 36 | win32ole.sleep(5000); 37 | sh.SendKeys(filename + '{ENTER}'); 38 | win32ole.sleep(1000); 39 | sh.SendKeys('%{F4}'); // ALT-F4 (Exit) 40 | win32ole.sleep(100); 41 | win32ole.print('ok\n'); 42 | 43 | win32ole.print('ping ...'); 44 | sh.Run('ping.exe 127.0.0.1', 4, true); // wait for close (Sync) 45 | win32ole.print('ok\n'); 46 | 47 | }catch(e){ 48 | console.log('(exception catched)' + e); 49 | } 50 | 51 | var shellexec = function(sh, cmd, callback){ 52 | console.log('sh.Exec(' + cmd + ')'); 53 | var stat = sh.Exec(cmd); 54 | // while(stat.Status == 0) win32ole.sleep(100, true, true); 55 | var so = stat.StdOut._; // *** 56 | /* 57 | In ParseUnaryExpression() < v8/src/parser.cc > 58 | v8::Object::ToBoolean() is called directly for unary operator '!' 59 | instead of v8::Object::valueOf() 60 | so NamedPropertyHandler will not be called 61 | Local ToBoolean(); // How to fake ? override v8::Value::ToBoolean 62 | */ 63 | // while(so.AtEndOfStream != true) // It works. (without unary operator !) 64 | // while(!so.AtEndOfStream) // It does not work. 65 | while(!so.AtEndOfStream._) // *** It works. oops! 66 | callback(so.ReadLine()); 67 | console.log('code = ' + stat.ExitCode); 68 | } 69 | 70 | var cmd = 'reg query "HKLM\\Software\\Microsoft\\Internet Explorer"'; 71 | shellexec(sh, cmd, function(line){ 72 | if(line.match(/([^\s]*version[^\s]*)[\s]+([^\s]+)[\s]+([^\s]+)/ig)) 73 | console.log(RegExp.$1 + ',' + RegExp.$2 + ',' + RegExp.$3); 74 | }); 75 | 76 | shellexec(sh, 'ipconfig.exe', function(line){ console.log(line); }); 77 | 78 | win32ole.print('writing to eventlog ...'); 79 | var name = 'node-win32ole (' + win32ole.VERSION + ') '; 80 | // the first argument value 81 | // 0: EVENTLOG_SUCCESS 82 | // 1: EVENTLOG_ERROR_TYPE 83 | // 2: EVENTLOG_WARNING_TYPE 84 | // 4: EVENTLOG_INFORMATION_TYPE 85 | // 8: EVENTLOG_AUDIT_SUCCESS 86 | // 16: EVENTLOG_AUDIT_FAILURE 87 | // the 3rd argument '.' means 'self computer name' to send LogEvent target 88 | sh.LogEvent(4, name + 'installed', '.'); 89 | sh.LogEvent(2, name + 'warning test', '.'); 90 | sh.LogEvent(1, name + 'error test', '.'); 91 | sh.LogEvent(0, name + 'success', '.'); 92 | win32ole.print('ok\n'); 93 | 94 | console.log('completed'); 95 | }; 96 | 97 | try{ 98 | wsh_sample(outfile); 99 | }catch(e){ 100 | console.log('*** exception cached ***\n' + e); 101 | } 102 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./win32ole'); -------------------------------------------------------------------------------- /lib/trace.js: -------------------------------------------------------------------------------- 1 | // Inspired by https://github.com/tlrobinson/long-stack-traces 2 | var EventEmitter = require('events').EventEmitter; 3 | var util = require('util'); 4 | 5 | function extendTrace(object, property, pos) { 6 | var old = object[property]; 7 | object[property] = function() { 8 | var error = new Error(); 9 | var name = object.constructor.name + '#' + property + '(' + 10 | Array.prototype.slice.call(arguments).map(function(el) { 11 | return util.inspect(el, false, 0); 12 | }).join(', ') + ')'; 13 | 14 | if (typeof pos === 'undefined') pos = -1; 15 | if (pos < 0) pos += arguments.length; 16 | var cb = arguments[pos]; 17 | if (typeof arguments[pos] === 'function') { 18 | arguments[pos] = function replacement() { 19 | try { 20 | return cb.apply(this, arguments); 21 | } catch (err) { 22 | if (err && err.stack && !err.__augmented) { 23 | err.stack = filter(err).join('\n'); 24 | err.stack += '\n--> in ' + name; 25 | err.stack += '\n' + filter(error).slice(1).join('\n'); 26 | err.__augmented = true; 27 | } 28 | throw err; 29 | } 30 | }; 31 | } 32 | return old.apply(this, arguments); 33 | }; 34 | } 35 | exports.extendTrace = extendTrace; 36 | 37 | 38 | function filter(error) { 39 | return error.stack.split('\n').filter(function(line) { 40 | return line.indexOf(__filename) < 0; 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /lib/win32ole.js: -------------------------------------------------------------------------------- 1 | // Inspired by https://github.com/TooTallNate/node-sqlite3 2 | var win32ole = module.exports = exports = 3 | require('../build/Release/node_win32ole.node'); 4 | win32ole.MODULEDIRNAME = __dirname; 5 | win32ole.get_package_version = function(){ 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var fn = path.join(win32ole.MODULEDIRNAME, '../package.json'); 9 | try{ 10 | win32ole.VERSION = JSON.parse(fs.readFileSync(fn, 'utf8'))['version']; 11 | }catch(e){ 12 | win32ole.VERSION = e; 13 | } 14 | }; 15 | win32ole.get_package_version(); 16 | 17 | /* 18 | exchange (VT type <-> v8 type) 19 | VT_ERROR -> *** ( Int32 ) *** 20 | VT_EMPTY -> *** ( Empty or Undefined ) *** 21 | VT_SAFEARRAY <-> VT_SAFEARRAY, (VT_BYREF | VT_SAFEARRAY) 22 | VT_VARIANT <-> VT_VARIANT, VT_USERDEFINED, VT_ARRAY, (VT_BYREF | VT_VARIANT) 23 | exchange (VT type <-> C/C++ type <-> v8 type) 24 | VT_DISPATCH, VT_UNKNOWN <-> OCVariant <-> V8Variant 25 | VT_BSTR (VT_CLSID, VT_FILETIME, VT_LPWSTR, VT_LPSTR, 26 | VT_DECIMAL, VT_ERROR, VT_BSTR) <-> string <-> Utf8Value 27 | VT_DATE <-> double <-> Date 28 | VT_I2 -> int16_t (short) -> Int32 29 | VT_UI2 -> uint16_t (ushort) -> Int32 30 | VT_I4 (VT_INT, VT_I4) <-> int32_t (long) <-> Int32 31 | VT_UI4 (VT_UINT, VT_UI4) -> uint32_t (ulong) -> Int32 32 | VT_I8 -> int64_t (long long) -> Number 33 | VT_UI8 -> uint64_t (ulonglong) -> Number 34 | VT_R4 -> float -> Number 35 | VT_R8 (VT_CY, VT_R8) <-> double <-> Number 36 | VT_I1 (VT_UI1, VT_I1) -> char (uchar) -> *** ( Int32 ) *** 37 | VT_BOOL <-> bool <-> Boolean 38 | VT_NULL <-> NULL <-> Null 39 | */ 40 | 41 | win32ole.vt_enum = { 42 | VT_EMPTY: 0, VT_NULL: 1, 43 | VT_I2: 2, VT_I4: 3, VT_R4: 4, VT_R8: 5, VT_CY: 6, VT_DATE: 7, VT_BSTR: 8, 44 | VT_DISPATCH: 9, VT_ERROR: 10, VT_BOOL: 11, VT_VARIANT: 12, VT_UNKNOWN: 13, 45 | VT_DECIMAL: 14, // 15 46 | VT_I1: 16, VT_UI1: 17, VT_UI2: 18, VT_UI4: 19, 47 | VT_I8: 20, VT_UI8: 21, VT_INT: 22, VT_UINT: 23, 48 | VT_VOID: 24, VT_HRESULT: 25, VT_PTR: 26, VT_SAFEARRAY: 27, VT_CARRAY: 28, 49 | VT_USERDEFINED: 29, VT_LPSTR: 30, VT_LPWSTR: 31, // 32-35 50 | VT_RECORD: 36, // 37-63 51 | VT_FILETIME: 64, VT_BLOB: 65, VT_STREAM: 66, VT_STORAGE: 67, 52 | VT_STREAM_OBJECT: 68, VT_STORED_OBJECT: 69, VT_BLOB_OBJECT: 70, 53 | VT_CF: 71, VT_CLSID: 72, // 73-4094 54 | VT_BSTR_BLOB: 4095, // 0x0fff 55 | VT_VECTOR: 4096, // flag 0x1000 56 | VT_ARRAY: 8192, // flag 0x2000 57 | VT_BYREF: 16384, // flag 0x4000 58 | VT_RESERVED: 32768, // flag 0x8000 59 | VT_ILLEGAL: 65535, // -1 0xffff 60 | VT_ILLEGALMASKED: 4095, // 0x0fff *** caution *** 61 | VT_TYPEMASK: 4095 // 0x0fff *** caution *** 62 | }; 63 | 64 | win32ole.vt_names = (function(){ 65 | var names = {}; 66 | var vte = win32ole.vt_enum; 67 | var xkey = 'VT_BSTR_BLOB'; 68 | var xnum = vte[xkey]; 69 | for(var k in vte) if(vte[k] != xnum) names[vte[k]] = k; // must use typemask 70 | names[xnum] = xkey; 71 | return names; 72 | })(); 73 | 74 | var util = require('util'); 75 | var EventEmitter = require('events').EventEmitter; 76 | 77 | function errorCallback(args){ 78 | if(typeof args[args.length - 1] === 'function'){ 79 | var callback = args[args.length - 1]; 80 | return function(err){ if(err) callback(err); } 81 | } 82 | } 83 | 84 | function inherits(target, source){ 85 | for(var k in source.prototype) target.prototype[k] = source.prototype[k]; 86 | } 87 | 88 | var isVerbose = false; 89 | var supportedEvents = ['trace', 'profile']; 90 | var V8Variant = win32ole.V8Variant; 91 | var Client = win32ole.Client; 92 | 93 | inherits(V8Variant, EventEmitter); 94 | inherits(Client, EventEmitter); 95 | 96 | V8Variant.prototype.map = function(){ 97 | var params = Array.prototype.slice.call(arguments); 98 | var callback = params.pop(); 99 | params.push(function(err, rows){ 100 | if(err) return callback(err); 101 | var result = {}; 102 | if(rows.length){ 103 | var keys = Object.keys(rows[0]), key = keys[0]; 104 | if(keys.length > 2){ // Value is an Object 105 | for(var i = 0; i < rows.length; i++) 106 | result[rows[i][key]] = rows[i]; 107 | }else{ // Value is a plain value 108 | var value = keys[i]; 109 | for(var i = 0; i < rows.length; i++) 110 | result[rows[i][key]] = rows[i][value]; 111 | } 112 | } 113 | callback(err, result); 114 | }); 115 | return this.all.apply(this, params); 116 | }; 117 | 118 | Client.prototype.map = function(){ 119 | var params = Array.prototype.slice.call(arguments); 120 | var callback = params.pop(); 121 | params.push(function(err, rows){ 122 | if(err) return callback(err); 123 | var result = {}; 124 | if(rows.length){ 125 | var keys = Object.keys(rows[0]), key = keys[0]; 126 | if(keys.length > 2){ // Value is an Object 127 | for(var i = 0; i < rows.length; i++) 128 | result[rows[i][key]] = rows[i]; 129 | }else{ // Value is a plain value 130 | var value = keys[i]; 131 | for(var i = 0; i < rows.length; i++) 132 | result[rows[i][key]] = rows[i][value]; 133 | } 134 | } 135 | callback(err, result); 136 | }); 137 | return this.all.apply(this, params); 138 | }; 139 | 140 | // Save the stack trace over EIO callbacks. 141 | win32ole.verbose = function(){ 142 | if(!isVerbose){ 143 | var trace = require('./trace'); 144 | trace.extendTrace(V8Variant.prototype, 'isA'); 145 | trace.extendTrace(V8Variant.prototype, 'vtName'); 146 | trace.extendTrace(V8Variant.prototype, 'toBoolean'); // *** p. 147 | trace.extendTrace(V8Variant.prototype, 'toInt32'); // *** p. 148 | trace.extendTrace(V8Variant.prototype, 'toInt64'); // *** p. 149 | trace.extendTrace(V8Variant.prototype, 'toNumber'); // *** p. 150 | trace.extendTrace(V8Variant.prototype, 'toDate'); // *** p. 151 | trace.extendTrace(V8Variant.prototype, 'toUtf8'); // *** p. 152 | trace.extendTrace(V8Variant.prototype, 'toValue'); 153 | trace.extendTrace(V8Variant.prototype, 'call'); 154 | trace.extendTrace(V8Variant.prototype, 'get'); 155 | trace.extendTrace(V8Variant.prototype, 'set'); 156 | trace.extendTrace(V8Variant.prototype, 'map'); 157 | trace.extendTrace(Client.prototype, 'Dispatch'); 158 | trace.extendTrace(Client.prototype, 'map'); 159 | isVerbose = true; 160 | } 161 | return this; 162 | }; 163 | 164 | win32ole.client = new win32ole.Client; 165 | process.on('exit', function(){ 166 | win32ole.client.Finalize(); 167 | // win32ole.print('EXIT\n'); 168 | }); 169 | 170 | global.ActiveXObject = function(args){ 171 | return win32ole.client.Dispatch(args); 172 | }; 173 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "win32ole", 3 | "version": "0.1.3", 4 | "description": "Asynchronous, non-blocking win32ole bindings", 5 | "homepage": "https://github.com/idobatter/node-win32ole", 6 | "keywords": [ 7 | "OLE", "COM", "ActiveX", "ActiveXObject", "CreateObject", "WSH", "WMI", 8 | "Outlook", "Access", "Word", "Excel", "IE", "InternetExplorer" 9 | ], 10 | "author": { 11 | "name": "idobatter", 12 | "url": "https://github.com/idobatter", 13 | "email": "idobatter@gmail.com" 14 | }, 15 | "contributors": [ 16 | "idobatter " 17 | ], 18 | "repository": { 19 | "type": "git", 20 | "url": "git://github.com/idobatter/node-win32ole.git" 21 | }, 22 | "dependencies": { 23 | "assert": ">= 0.4.9", 24 | "async": ">= 0.1.22", 25 | "ref-struct": ">= 0.0.5", 26 | "ref": ">= 0.1.3" 27 | }, 28 | "devDependencies": { 29 | "mocha": ">= 1.8.1", 30 | "assert": ">= 0.4.9", 31 | "async": ">= 0.1.22", 32 | "ref-struct": ">= 0.0.5", 33 | "ref": ">= 0.1.3" 34 | }, 35 | "engines": { 36 | "node": ">= 0.8.18 && < 0.9.0" 37 | }, 38 | "scripts": { 39 | "test": "nmake /a test" 40 | }, 41 | "licenses": [{ "type": "BSD" }], 42 | "main": "./lib/win32ole" 43 | } -------------------------------------------------------------------------------- /src/client.cc: -------------------------------------------------------------------------------- 1 | /* 2 | client.cc 3 | */ 4 | 5 | #include "client.h" 6 | #include "v8variant.h" 7 | 8 | using namespace v8; 9 | using namespace ole32core; 10 | 11 | namespace node_win32ole { 12 | 13 | Persistent Client::clazz; 14 | 15 | void Client::Init(Handle target) 16 | { 17 | HandleScope scope; 18 | Local t = FunctionTemplate::New(New); 19 | clazz = Persistent::New(t); 20 | clazz->InstanceTemplate()->SetInternalFieldCount(2); 21 | clazz->SetClassName(String::NewSymbol("Client")); 22 | // NODE_SET_PROTOTYPE_METHOD(clazz, "New", New); 23 | NODE_SET_PROTOTYPE_METHOD(clazz, "Dispatch", Dispatch); 24 | NODE_SET_PROTOTYPE_METHOD(clazz, "Finalize", Finalize); 25 | target->Set(String::NewSymbol("Client"), clazz->GetFunction()); 26 | } 27 | 28 | Handle Client::New(const Arguments& args) 29 | { 30 | HandleScope scope; 31 | DISPFUNCIN(); 32 | if(!args.IsConstructCall()) 33 | return ThrowException(Exception::TypeError( 34 | String::New("Use the new operator to create new Client objects"))); 35 | std::string cstr_locale(".ACP"); // default 36 | if(args.Length() >= 1){ 37 | if(!args[0]->IsString()) 38 | return ThrowException(Exception::TypeError( 39 | String::New("Argument 1 is not a String"))); 40 | String::Utf8Value u8s_locale(args[0]); 41 | cstr_locale = std::string(*u8s_locale); 42 | } 43 | OLE32core *oc = new OLE32core(); 44 | if(!oc) 45 | return ThrowException(Exception::TypeError( 46 | String::New("Can't create new Client object (null OLE32core)"))); 47 | bool cnresult = false; 48 | try{ 49 | cnresult = oc->connect(cstr_locale); 50 | }catch(OLE32coreException e){ 51 | std::cerr << e.errorMessage((char *)cstr_locale.c_str()); 52 | }catch(char *e){ 53 | std::cerr << e << cstr_locale.c_str() << std::endl; 54 | } 55 | if(!cnresult) 56 | return ThrowException(Exception::TypeError( 57 | String::New("May be CoInitialize() is failed."))); 58 | Local thisObject = args.This(); 59 | Client *cl = new Client(); // must catch exception 60 | cl->Wrap(thisObject); // InternalField[0] 61 | thisObject->SetInternalField(1, External::New(oc)); 62 | Persistent objectDisposer = Persistent::New(thisObject); 63 | objectDisposer.MakeWeak(oc, Dispose); 64 | DISPFUNCOUT(); 65 | return args.This(); 66 | } 67 | 68 | Handle Client::Dispatch(const Arguments& args) 69 | { 70 | HandleScope scope; 71 | DISPFUNCIN(); 72 | BEVERIFY(done, args.Length() >= 1); 73 | BEVERIFY(done, args[0]->IsString()); 74 | wchar_t *wcs; 75 | { 76 | String::Utf8Value u8s(args[0]); // must create here 77 | wcs = u8s2wcs(*u8s); 78 | } 79 | BEVERIFY(done, wcs); 80 | #ifdef DEBUG 81 | char *mbs = wcs2mbs(wcs); 82 | if(!mbs) free(wcs); 83 | BEVERIFY(done, mbs); 84 | fprintf(stderr, "ProgID: %s\n", mbs); 85 | free(mbs); 86 | #endif 87 | CLSID clsid; 88 | HRESULT hr = CLSIDFromProgID(wcs, &clsid); 89 | free(wcs); 90 | BEVERIFY(done, !FAILED(hr)); 91 | #ifdef DEBUG 92 | fprintf(stderr, "clsid:"); // 00024500-0000-0000-c000-000000000046 (Excel) ok 93 | for(int i = 0; i < sizeof(CLSID); ++i) 94 | fprintf(stderr, " %02x", ((unsigned char *)&clsid)[i]); 95 | fprintf(stderr, "\n"); 96 | #endif 97 | Handle vApp = V8Variant::CreateUndefined(); 98 | BEVERIFY(done, !vApp.IsEmpty()); 99 | BEVERIFY(done, !vApp->IsUndefined()); 100 | BEVERIFY(done, vApp->IsObject()); 101 | OCVariant *app = castedInternalField(vApp); 102 | CHECK_OCV(app); 103 | app->v.vt = VT_DISPATCH; 104 | // When 'CoInitialize(NULL)' is not called first (and on the same instance), 105 | // next functions will return many errors. 106 | // (old style) GetActiveObject() returns 0x000036b7 107 | // The requested lookup key was not found in any active activation context. 108 | // (OLE2) CoCreateInstance() returns 0x000003f0 109 | // An attempt was made to reference a token that does not exist. 110 | REFIID riid = IID_IDispatch; // can't connect to Excel etc with IID_IUnknown 111 | #ifdef DEBUG // obsolete (it needs that OLE target has been already executed) 112 | IUnknown *pUnk; 113 | hr = GetActiveObject(clsid, NULL, (IUnknown **)&pUnk); 114 | BEVERIFY(done, !FAILED(hr)); 115 | hr = pUnk->QueryInterface(riid, (void **)&app->v.pdispVal); 116 | pUnk->Release(); 117 | #else 118 | // C -> C++ changes types (&clsid -> clsid, &IID_IDispatch -> IID_IDispatch) 119 | // options (CLSCTX_INPROC_SERVER CLSCTX_INPROC_HANDLER CLSCTX_LOCAL_SERVER) 120 | DWORD ctx = CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER; 121 | hr = CoCreateInstance(clsid, NULL, ctx, riid, (void **)&app->v.pdispVal); 122 | if(FAILED(hr)){ 123 | // Retry with WOW6432 bridge option. 124 | // This may not be a right way, but better. 125 | BDISPFUNCDAT("FAILED CoCreateInstance: %d: 0x%08x\n", 0, hr); 126 | #if defined(_WIN64) 127 | ctx |= CLSCTX_ACTIVATE_32_BIT_SERVER; // 32bit COM server on 64bit OS 128 | #else 129 | ctx |= CLSCTX_ACTIVATE_64_BIT_SERVER; // 64bit COM server on 32bit OS 130 | #endif 131 | hr = CoCreateInstance(clsid, NULL, ctx, riid, (void **)&app->v.pdispVal); 132 | } 133 | #endif 134 | if(FAILED(hr)) BDISPFUNCDAT("FAILED CoCreateInstance: %d: 0x%08x\n", 1, hr); 135 | BEVERIFY(done, !FAILED(hr)); 136 | DISPFUNCOUT(); 137 | return scope.Close(vApp); 138 | done: 139 | DISPFUNCOUT(); 140 | return ThrowException(Exception::TypeError(String::New("Dispatch failed"))); 141 | } 142 | 143 | Handle Client::Finalize(const Arguments& args) 144 | { 145 | HandleScope scope; 146 | DISPFUNCIN(); 147 | #if(0) 148 | std::cerr << __FUNCTION__ << " Finalizer is called\a" << std::endl; 149 | std::cerr.flush(); 150 | #endif 151 | Local thisObject = args.This(); 152 | #if(0) 153 | Client *cl = ObjectWrap::Unwrap(thisObject); 154 | if(cl) delete cl; // it has been already deleted ? 155 | thisObject->SetInternalField(0, External::New(NULL)); 156 | #endif 157 | #if(1) // now GC will call Disposer automatically 158 | OLE32core *oc = castedInternalField(thisObject); 159 | if(oc){ 160 | try{ 161 | delete oc; // will call oc->disconnect(); 162 | }catch(OLE32coreException e){ std::cerr << e.errorMessage(__FUNCTION__); 163 | }catch(char *e){ std::cerr << e << __FUNCTION__ << std::endl; 164 | } 165 | } 166 | #endif 167 | thisObject->SetInternalField(1, External::New(NULL)); 168 | DISPFUNCOUT(); 169 | return args.This(); 170 | } 171 | 172 | void Client::Dispose(Persistent handle, void *param) 173 | { 174 | DISPFUNCIN(); 175 | #if(0) 176 | // std::cerr << __FUNCTION__ << " Disposer is called\a" << std::endl; 177 | std::cerr << __FUNCTION__ << " Disposer is called" << std::endl; 178 | std::cerr.flush(); 179 | #endif 180 | Local thisObject = handle->ToObject(); 181 | #if(0) // it has been already deleted ? 182 | Client *cl = ObjectWrap::Unwrap(thisObject); 183 | if(!cl){ 184 | std::cerr << __FUNCTION__; 185 | std::cerr << " InternalField[0] has been already deleted" << std::endl; 186 | std::cerr.flush(); 187 | }else delete cl; // it has been already deleted ? 188 | BEVERIFY(done, thisObject->InternalFieldCount() > 0); 189 | thisObject->SetInternalField(0, External::New(NULL)); 190 | #endif 191 | OLE32core *p = castedInternalField(thisObject); 192 | if(!p){ 193 | std::cerr << __FUNCTION__; 194 | std::cerr << " InternalField[1] has been already deleted" << std::endl; 195 | std::cerr.flush(); 196 | } 197 | // else{ 198 | OLE32core *oc = static_cast(param); // oc may be same as p 199 | if(oc){ 200 | try{ 201 | delete oc; // will call oc->disconnect(); 202 | }catch(OLE32coreException e){ std::cerr << e.errorMessage(__FUNCTION__); 203 | }catch(char *e){ std::cerr << e << __FUNCTION__ << std::endl; 204 | } 205 | } 206 | // } 207 | BEVERIFY(done, thisObject->InternalFieldCount() > 1); 208 | thisObject->SetInternalField(1, External::New(NULL)); 209 | done: 210 | handle.Dispose(); 211 | DISPFUNCOUT(); 212 | } 213 | 214 | void Client::Finalize() 215 | { 216 | assert(!finalized); 217 | finalized = true; 218 | } 219 | 220 | } // namespace node_win32ole 221 | -------------------------------------------------------------------------------- /src/client.h: -------------------------------------------------------------------------------- 1 | #ifndef __CLIENT_H__ 2 | #define __CLIENT_H__ 3 | 4 | #include "node_win32ole.h" 5 | 6 | using namespace v8; 7 | 8 | namespace node_win32ole { 9 | 10 | class Client : public node::ObjectWrap { 11 | public: 12 | static Persistent clazz; 13 | static void Init(Handle target); 14 | static Handle New(const Arguments& args); 15 | static Handle Dispatch(const Arguments& args); 16 | static Handle Finalize(const Arguments& args); 17 | public: 18 | Client() : node::ObjectWrap(), finalized(false) {} 19 | ~Client() { if(!finalized) Finalize(); } 20 | protected: 21 | static void Dispose(Persistent handle, void *param); 22 | void Finalize(); 23 | protected: 24 | bool finalized; 25 | }; 26 | 27 | } // namespace node_win32ole 28 | 29 | #endif // __CLIENT_H__ 30 | -------------------------------------------------------------------------------- /src/force_gc_extension.cc: -------------------------------------------------------------------------------- 1 | /* 2 | force_gc_extension.cc 3 | */ 4 | 5 | #include "node_win32ole.h" 6 | #include "ole32core.h" 7 | 8 | using namespace v8; 9 | using namespace ole32core; 10 | 11 | namespace node_win32ole { 12 | 13 | Handle Method_force_gc_extension(const Arguments& args) // v8/gc : gc() 14 | { 15 | BDISPFUNCDAT("context %s "__FUNCTION__" %s\n", "preset", "start"); 16 | // create context with extension(s) 17 | const char *extensionNames[] = {"v8/gc",}; 18 | ExtensionConfiguration extensions( 19 | sizeof(extensionNames) / sizeof(extensionNames[0]), extensionNames); 20 | Handle global = ObjectTemplate::New(); 21 | // another way get 'global' by ( global = context->Global() ) but no context 22 | // Persistent context = Context::New(NULL, global); 23 | Persistent context = Context::New(&extensions, global); 24 | Context::Scope context_scope(context); 25 | BDISPFUNCDAT("context %s "__FUNCTION__" %s\n", "preset", "end"); 26 | HandleScope scope; 27 | BDISPFUNCIN(); 28 | Local sourceObj = String::New("gc()"); 29 | TryCatch try_catch; 30 | Local