Skip to content

Commit ff6293d

Browse files
committed
feat: createProcess
1 parent 720446b commit ff6293d

File tree

4 files changed

+172
-95
lines changed

4 files changed

+172
-95
lines changed

.vscode/settings.json

Lines changed: 57 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,57 @@
1-
{
2-
"files.associations": {
3-
"xiosbase": "cpp",
4-
"iosfwd": "cpp",
5-
"*.rh": "cpp",
6-
"algorithm": "cpp",
7-
"cmath": "cpp",
8-
"cstddef": "cpp",
9-
"cstdint": "cpp",
10-
"cstdio": "cpp",
11-
"cstdlib": "cpp",
12-
"cstring": "cpp",
13-
"cwchar": "cpp",
14-
"deque": "cpp",
15-
"exception": "cpp",
16-
"fstream": "cpp",
17-
"initializer_list": "cpp",
18-
"ios": "cpp",
19-
"iostream": "cpp",
20-
"istream": "cpp",
21-
"limits": "cpp",
22-
"memory": "cpp",
23-
"new": "cpp",
24-
"ostream": "cpp",
25-
"queue": "cpp",
26-
"stdexcept": "cpp",
27-
"streambuf": "cpp",
28-
"string": "cpp",
29-
"system_error": "cpp",
30-
"tuple": "cpp",
31-
"type_traits": "cpp",
32-
"typeinfo": "cpp",
33-
"utility": "cpp",
34-
"vector": "cpp",
35-
"xfacet": "cpp",
36-
"xlocale": "cpp",
37-
"xlocinfo": "cpp",
38-
"xlocnum": "cpp",
39-
"xmemory": "cpp",
40-
"xmemory0": "cpp",
41-
"xstddef": "cpp",
42-
"xstring": "cpp",
43-
"xtr1common": "cpp",
44-
"xutility": "cpp",
45-
"functional": "cpp",
46-
"list": "cpp",
47-
"unordered_map": "cpp",
48-
"xhash": "cpp",
49-
"map": "cpp",
50-
"xtree": "cpp"
51-
}
52-
}
1+
{
2+
"files.associations": {
3+
"xiosbase": "cpp",
4+
"iosfwd": "cpp",
5+
"*.rh": "cpp",
6+
"algorithm": "cpp",
7+
"cmath": "cpp",
8+
"cstddef": "cpp",
9+
"cstdint": "cpp",
10+
"cstdio": "cpp",
11+
"cstdlib": "cpp",
12+
"cstring": "cpp",
13+
"cwchar": "cpp",
14+
"deque": "cpp",
15+
"exception": "cpp",
16+
"fstream": "cpp",
17+
"initializer_list": "cpp",
18+
"ios": "cpp",
19+
"iostream": "cpp",
20+
"istream": "cpp",
21+
"limits": "cpp",
22+
"memory": "cpp",
23+
"new": "cpp",
24+
"ostream": "cpp",
25+
"queue": "cpp",
26+
"stdexcept": "cpp",
27+
"streambuf": "cpp",
28+
"string": "cpp",
29+
"system_error": "cpp",
30+
"tuple": "cpp",
31+
"type_traits": "cpp",
32+
"typeinfo": "cpp",
33+
"utility": "cpp",
34+
"vector": "cpp",
35+
"xfacet": "cpp",
36+
"xlocale": "cpp",
37+
"xlocinfo": "cpp",
38+
"xlocnum": "cpp",
39+
"xmemory": "cpp",
40+
"xmemory0": "cpp",
41+
"xstddef": "cpp",
42+
"xstring": "cpp",
43+
"xtr1common": "cpp",
44+
"xutility": "cpp",
45+
"functional": "cpp",
46+
"list": "cpp",
47+
"unordered_map": "cpp",
48+
"xhash": "cpp",
49+
"map": "cpp",
50+
"xtree": "cpp",
51+
"chrono": "cpp",
52+
"cstdarg": "cpp",
53+
"mutex": "cpp",
54+
"ratio": "cpp",
55+
"thread": "cpp"
56+
}
57+
}

example.js

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,39 @@
1-
const { windowManager } = require("./dist/index");
2-
3-
console.log(windowManager.requestAccessibility()); // required on macOS
4-
5-
const window = windowManager.getActiveWindow();
6-
console.log(window.getTitle());
7-
8-
const bounds = window.getBounds();
9-
console.log(bounds);
10-
11-
window.setBounds({ x: 0, y: 0 });
12-
window.maximize();
13-
14-
setTimeout(() => {
15-
window.setBounds(bounds);
16-
}, 1000);
17-
18-
console.log("Windows list");
19-
windowManager.getWindows().forEach(window => {
20-
if (window.isVisible()) {
21-
console.log(window.path);
22-
}
23-
});
24-
25-
windowManager.on('window-activated', (window) => {
26-
console.log(window.path);
27-
});
28-
29-
console.log("Monitors list");
30-
windowManager.getMonitors().forEach(monitor => {
31-
console.log(monitor.getWorkArea());
32-
});
1+
const { windowManager } = require("./dist/index");
2+
3+
console.log(windowManager.requestAccessibility()); // required on macOS
4+
5+
/*
6+
const window = windowManager.getActiveWindow();
7+
console.log(window.getTitle());
8+
9+
const bounds = window.getBounds();
10+
console.log(bounds);
11+
12+
window.setBounds({ x: 0, y: 0 });
13+
window.maximize();
14+
15+
setTimeout(() => {
16+
window.setBounds(bounds);
17+
}, 1000);
18+
19+
console.log("Windows list");
20+
windowManager.getWindows().forEach(window => {
21+
if (window.isVisible()) {
22+
console.log(window.path);
23+
}
24+
});
25+
26+
windowManager.on('window-activated', (window) => {
27+
console.log(window.path);
28+
});
29+
30+
console.log("Monitors list");
31+
windowManager.getMonitors().forEach(monitor => {
32+
console.log(monitor.getWorkArea());
33+
});
34+
*/
35+
36+
37+
38+
const pid = windowManager.createProcess('C:\\Windows\\explorer.exe');
39+

lib/windows.cc

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include <string>
77
#include <windows.h>
88

9-
typedef int(__stdcall* lp_GetScaleFactorForMonitor) (HMONITOR, DEVICE_SCALE_FACTOR*);
9+
typedef int (__stdcall* lp_GetScaleFactorForMonitor) (HMONITOR, DEVICE_SCALE_FACTOR*);
1010

1111
struct Process {
1212
int pid;
@@ -18,6 +18,10 @@ T getValueFromCallbackData (const Napi::CallbackInfo& info, unsigned handleIndex
1818
return reinterpret_cast<T> (info[handleIndex].As<Napi::Number> ().Int64Value ());
1919
}
2020

21+
std::wstring get_wstring (const std::string str) {
22+
return std::wstring (str.begin (), str.end ());
23+
}
24+
2125
std::string toUtf8 (const std::wstring& str) {
2226
std::string ret;
2327
int len = WideCharToMultiByte (CP_UTF8, 0, str.c_str (), str.length (), NULL, 0, NULL, NULL);
@@ -45,6 +49,60 @@ Process getWindowProcess (HWND handle) {
4549
return { static_cast<int> (pid), path };
4650
}
4751

52+
HWND find_top_window (DWORD pid) {
53+
std::pair<HWND, DWORD> params = { 0, pid };
54+
55+
BOOL bResult = EnumWindows (
56+
[] (HWND hwnd, LPARAM lParam) -> BOOL {
57+
auto pParams = (std::pair<HWND, DWORD>*)(lParam);
58+
59+
DWORD processId;
60+
if (GetWindowThreadProcessId (hwnd, &processId) && processId == pParams->second) {
61+
SetLastError (-1);
62+
pParams->first = hwnd;
63+
return FALSE;
64+
}
65+
66+
return TRUE;
67+
},
68+
(LPARAM)&params);
69+
70+
if (!bResult && GetLastError () == -1 && params.first) {
71+
return params.first;
72+
}
73+
74+
return 0;
75+
}
76+
77+
Napi::Number getProcessMainWindow (const Napi::CallbackInfo& info) {
78+
Napi::Env env{ info.Env () };
79+
80+
unsigned long process_id = info[0].ToNumber ().Uint32Value ();
81+
82+
auto handle = find_top_window (process_id);
83+
84+
return Napi::Number::New (env, reinterpret_cast<int64_t> (handle));
85+
}
86+
87+
Napi::Number createProcess (const Napi::CallbackInfo& info) {
88+
Napi::Env env{ info.Env () };
89+
90+
auto path = info[0].ToString ().Utf8Value ();
91+
92+
std::string cmd = "";
93+
94+
if (info[1].IsString ()) {
95+
cmd = info[1].ToString ().Utf8Value ();
96+
}
97+
98+
STARTUPINFOA sInfo = { sizeof (sInfo) };
99+
PROCESS_INFORMATION processInfo;
100+
CreateProcessA (path.c_str (), &cmd[0], NULL, NULL, FALSE,
101+
CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, NULL, NULL, &sInfo, &processInfo);
102+
103+
return Napi::Number::New (env, processInfo.dwProcessId);
104+
}
105+
48106
Napi::Number getActiveWindow (const Napi::CallbackInfo& info) {
49107
Napi::Env env{ info.Env () };
50108

@@ -261,16 +319,16 @@ Napi::Boolean bringWindowToTop (const Napi::CallbackInfo& info) {
261319
auto handle{ getValueFromCallbackData<HWND> (info, 0) };
262320
BOOL b{ SetForegroundWindow (handle) };
263321

264-
HWND hCurWnd = ::GetForegroundWindow();
265-
DWORD dwMyID = ::GetCurrentThreadId();
266-
DWORD dwCurID = ::GetWindowThreadProcessId(hCurWnd, NULL);
267-
::AttachThreadInput(dwCurID, dwMyID, TRUE);
268-
::SetWindowPos(handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
269-
::SetWindowPos(handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
270-
::SetForegroundWindow(handle);
271-
::AttachThreadInput(dwCurID, dwMyID, FALSE);
272-
::SetFocus(handle);
273-
::SetActiveWindow(handle);
322+
HWND hCurWnd = ::GetForegroundWindow ();
323+
DWORD dwMyID = ::GetCurrentThreadId ();
324+
DWORD dwCurID = ::GetWindowThreadProcessId (hCurWnd, NULL);
325+
::AttachThreadInput (dwCurID, dwMyID, TRUE);
326+
::SetWindowPos (handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
327+
::SetWindowPos (handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
328+
::SetForegroundWindow (handle);
329+
::AttachThreadInput (dwCurID, dwMyID, FALSE);
330+
::SetFocus (handle);
331+
::SetActiveWindow (handle);
274332

275333
return Napi::Boolean::New (env, b);
276334
}
@@ -357,6 +415,8 @@ Napi::Object Init (Napi::Env env, Napi::Object exports) {
357415
exports.Set (Napi::String::New (env, "getMonitorInfo"), Napi::Function::New (env, getMonitorInfo));
358416
exports.Set (Napi::String::New (env, "getWindows"), Napi::Function::New (env, getWindows));
359417
exports.Set (Napi::String::New (env, "getMonitors"), Napi::Function::New (env, getMonitors));
418+
exports.Set (Napi::String::New (env, "createProcess"), Napi::Function::New (env, createProcess));
419+
exports.Set (Napi::String::New (env, "getProcessMainWindow"), Napi::Function::New (env, getProcessMainWindow));
360420

361421
return exports;
362422
}

src/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ class WindowManager extends EventEmitter {
8181
return new EmptyMonitor();
8282
}
8383
}
84+
85+
createProcess = (path: string, cmd = ""): number => {
86+
if (!addon || !addon.createProcess) return;
87+
return addon.createProcess(path, cmd);
88+
};
8489
}
8590

8691
const windowManager = new WindowManager();

0 commit comments

Comments
 (0)