├── .gitignore ├── LICENSE ├── README.md ├── binding.gyp ├── lib ├── index.js └── processname.cc ├── package-lock.json ├── package.json └── test └── benchmark.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | *.pid.lock 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # nyc test coverage 19 | .nyc_output 20 | 21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 22 | .grunt 23 | 24 | # node-waf configuration 25 | .lock-wscript 26 | 27 | # Compiled binary addons (http://nodejs.org/api/addons.html) 28 | build/Release 29 | 30 | # Dependency directories 31 | node_modules 32 | jspm_packages 33 | 34 | # Optional npm cache directory 35 | .npm 36 | 37 | # Optional eslint cache 38 | .eslintcache 39 | 40 | # Optional REPL history 41 | .node_repl_history 42 | 43 | build 44 | node_modules/ 45 | npm-debug.log 46 | 47 | .vscode -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Felix Rieseberg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## windows-active-process 2 | Quickly check which app is currently in the foreground. Returns the full path. 3 | 4 | ``` 5 | npm install windows-active-process 6 | ``` 7 | 8 | ``` 9 | const { getActiveProcessName } = require('windows-active-process') 10 | const activeProcess = getActiveProcessName() 11 | 12 | // For instance 'C:\Users\felixr\AppData\Local\hyper\app-1.3.1\Hyper.exe' 13 | ``` 14 | 15 | #### License 16 | MIT, please see LICENSE for details. Copyright (c) 2017 Felix Rieseberg. 17 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "processname", 5 | "sources": [ "lib/processname.cc" ], 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | const addon = require('bindings')('processname') 2 | 3 | /** 4 | * Get's the active process in the foreground. If the native call 5 | * fails, it'll return an empty string. 6 | * 7 | * @returns {string} Path to the active process 8 | */ 9 | function getActiveProcessName() { 10 | if (process.platform !== 'win32') { 11 | throw new Error('windows-active-process only works on Windows') 12 | } 13 | 14 | return addon.getActiveProcessName() 15 | } 16 | 17 | module.exports = { 18 | getActiveProcessName: getActiveProcessName 19 | } 20 | -------------------------------------------------------------------------------- /lib/processname.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define NAPI_CALL(env, call) \ 4 | do { \ 5 | napi_status status = (call); \ 6 | if (status != napi_ok) { \ 7 | const napi_extended_error_info* error_info = NULL; \ 8 | napi_get_last_error_info((env), &error_info); \ 9 | bool is_pending; \ 10 | napi_is_exception_pending((env), &is_pending); \ 11 | if (!is_pending) { \ 12 | const char* message = (error_info->error_message == NULL) \ 13 | ? "empty error message" \ 14 | : error_info->error_message; \ 15 | napi_throw_error((env), NULL, message); \ 16 | return NULL; \ 17 | } \ 18 | } \ 19 | } while(0) 20 | 21 | 22 | #define _WIN32_WINNT 0x0601 23 | 24 | #ifdef _WIN32 25 | #include 26 | #include 27 | #include 28 | #include 29 | #else 30 | #include 31 | #endif 32 | 33 | #ifdef _WIN32 34 | bool GetActiveProcessName(WCHAR *buffer, DWORD *cchLen) 35 | { 36 | HWND fg = GetForegroundWindow(); 37 | if (fg) 38 | { 39 | DWORD pid; 40 | 41 | GetWindowThreadProcessId(fg, &pid); 42 | HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); 43 | 44 | if (hProcess) 45 | { 46 | BOOL ret = QueryFullProcessImageNameW(hProcess, 0, buffer, cchLen); 47 | CloseHandle(hProcess); 48 | return (ret != FALSE); 49 | } 50 | } 51 | return false; 52 | } 53 | #endif // _WIN32 54 | 55 | static napi_value Method(napi_env env, napi_callback_info info) { 56 | #ifdef _WIN32 57 | WCHAR buffer[1024]; 58 | DWORD len = 1024; 59 | if (GetActiveProcessName(buffer, &len)) 60 | { 61 | napi_value str = NULL; 62 | NAPI_CALL(env, napi_create_string_utf16(env, (char16_t*)buffer, len, &str)); 63 | return str; 64 | } 65 | #endif 66 | napi_value ret = NULL; 67 | NAPI_CALL(env, napi_get_undefined(env, &ret)); 68 | return ret; 69 | } 70 | 71 | NAPI_MODULE_INIT() { 72 | napi_value result = NULL; 73 | NAPI_CALL(env, napi_create_object(env, &result)); 74 | napi_value fn = NULL; 75 | NAPI_CALL(env, napi_create_function(env, "getActiveProcessName", 0, Method, NULL, &fn)); 76 | NAPI_CALL(env, napi_set_named_property(env, result, "getActiveProcessName", fn)); 77 | return result; 78 | } 79 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "windows-active-process", 3 | "version": "1.1.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "bindings": { 8 | "version": "1.5.0", 9 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", 10 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", 11 | "requires": { 12 | "file-uri-to-path": "1.0.0" 13 | } 14 | }, 15 | "file-uri-to-path": { 16 | "version": "1.0.0", 17 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", 18 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "windows-active-process", 3 | "version": "1.1.1", 4 | "description": "Checks which app or process is currently in the foreground (active)", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "test": "standard" 8 | }, 9 | "repository": "https://github.com/felixrieseberg/windows-active-process", 10 | "license": "MIT", 11 | "licenses": [ 12 | { 13 | "type": "MIT", 14 | "url": "http://github.com/felixrieseberg/windows-active-process/blob/master/LICENSE" 15 | } 16 | ], 17 | "dependencies": { 18 | "bindings": "^1.2.1" 19 | }, 20 | "author": { 21 | "email": "felix@felixrieseberg.com", 22 | "name": "Felix Rieseberg", 23 | "url": "http://www.felixrieseberg.com" 24 | }, 25 | "keywords": [ 26 | "windows", 27 | "process", 28 | "GetForegroundWindow" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /test/benchmark.js: -------------------------------------------------------------------------------- 1 | const perfy = require('perfy') 2 | const getActiveProcessName = require('../lib/index').getActiveProcessName 3 | 4 | const iterations = process.argv[2] || 100000 5 | 6 | function measureThisTime () { 7 | perfy.start('this') 8 | for (let i = 0; i < iterations; i++) { 9 | getActiveProcessName() 10 | } 11 | 12 | return perfy.end('this').time 13 | } 14 | 15 | 16 | // Fight! 17 | console.log(`Reading the active process ${iterations} times:`) 18 | 19 | const thisTime = measureThisTime() 20 | 21 | console.log(`It took: ${thisTime}`) 22 | --------------------------------------------------------------------------------