Files
SonicForgeStudio/native_bridge/debug/rd_out.txt
T

156 lines
7.6 KiB
Plaintext

==== ProbeWorker ====
34| for (HWND c = GetWindow(w, GW_CHILD); c; c = GetWindow(c, GW_HWNDNEXT))
35| ImmAssociateContext(c, nullptr);
36| }
37| }
38|
39| static void pump_for(int secs) {
40| #ifdef _WIN32
41| _set_invalid_parameter_handler(probe_invalid_param);
42| #endif
43| auto t0 = std::chrono::steady_clock::now();
44| while (std::chrono::duration_cast<std::chrono::seconds>(
45| std::chrono::steady_clock::now() - t0).count() < secs) {
46| MSG msg;
47| while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
48| printf("[pump] msg=0x%X hwnd=%p\n", (unsigned)msg.message, (void*)msg.hwnd);
49| fflush(stdout);
50| TranslateMessage(&msg);
51| DispatchMessageW(&msg);
52| }
53| Sleep(5);
54| }
55| }
56|
57| static void sleep_for(int secs) { Sleep((DWORD)(secs * 1000)); }
58|
59| // Per-channel persistent worker replicating the bridge (round-3 probe).
60| class ProbeWorker {
61| public:
62| void start() {
63| th = std::thread([this] {
64| #ifdef _WIN32
65| _set_invalid_parameter_handler(probe_invalid_param);
66| CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
67| ImmAssociateContextEx(nullptr, nullptr, IACE_DEFAULT);
68| #endif
69| std::unique_lock<std::mutex> lk(mu);
70| for (;;) {
71| if (stop && jobs.empty()) break;
72| if (!jobs.empty()) {
73| auto j = std::move(jobs.front());
74| jobs.pop_front();
75| lk.unlock();
76| try { j(); }
77| catch (const std::exception& e) { printf("[worker] JOB EXCEPTION: %s\n", e.what()); fflush(stdout); }
78| catch (...) { printf("[worker] JOB UNKNOWN EXCEPTION\n"); fflush(stdout); }
79| lk.lock();
80| continue;
81| }
82| cv.wait_for(lk, std::chrono::milliseconds(5));
83| lk.unlock();
84| try {
85| MSG msg;
86| while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
87| printf("[wpump] msg=0x%X hwnd=%p\n", (unsigned)msg.message, (void*)msg.hwnd);
88| fflush(stdout);
89| TranslateMessage(&msg);
90| DispatchMessageW(&msg);
91| }
92| }
93| catch (const std::exception& e) { printf("[worker] PUMP EXCEPTION: %s\n", e.what()); fflush(stdout); }
94| catch (...) { printf("[worker] PUMP UNKNOWN EXCEPTION\n"); fflush(stdout); }
95| lk.lock();
96| }
97| #ifdef _WIN32
98| CoUninitialize();
99| #endif
100| });
101| }
102| void post(std::function<void()> j) {
103| { std::lock_guard<std::mutex> lk(mu); jobs.push_back(std::move(j)); }
104| cv.notify_all();
105| }
106| std::thread th;
107| std::mutex mu;
108| std::condition_variable cv;
109| std::deque<std::function<void()>> jobs;
110| bool stop = false;
111| };
112|
113| int main(int argc, char* argv[]) {
114| if (argc < 2) {
115| printf("usage: gui_probe <plugin.vst3> [variant] [secs] [hwnd]\n"
==== shared_worker ====
220| } else if (variant == "shared_worker" || variant == "ui_thread") {
221| // Proposed round-3 fix: ALL VST3 instances live in ONE apartment —
222| // one persistent worker thread hosts load + openGUI for every channel.
223| ProbeWorker w;
224| w.start();
225| std::atomic<bool> done{false};
226| int aRes = 0, bRes = 0;
227| w.post([&]() {
228| bool r = inst.loadPlugin(path, 44100.0);
229| printf("[shared_worker] load inst1=%d\n", r ? 1 : 0);
230| fflush(stdout);
231| if (r) {
232| HWND h = CreateWindowEx(0, "GuiProbeClass", "ProbeA", WS_OVERLAPPEDWINDOW,
233| 0, 0, 800, 600, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
234| disable_ime_contexts(h);
235| r = inst.openGUI(h);
236| disable_ime_contexts(h);
237| printf("[shared_worker] attach inst1=%d hwnd=%p\n", r ? 1 : 0, (void*)h);
238| fflush(stdout);
239| aRes = r ? 1 : 0;
240| }
241| r = inst2.loadPlugin(path, 44100.0);
242| printf("[shared_worker] load inst2=%d\n", r ? 1 : 0);
243| fflush(stdout);
244| if (r) {
245| HWND h = CreateWindowEx(0, "GuiProbeClass", "ProbeB", WS_OVERLAPPEDWINDOW,
246| 0, 0, 800, 600, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
247| disable_ime_contexts(h);
248| r = inst2.openGUI(h);
249| disable_ime_contexts(h);
250| printf("[shared_worker] attach inst2=%d hwnd=%p\n", r ? 1 : 0, (void*)h);
251| fflush(stdout);
252| bRes = r ? 1 : 0;
253| }
254| done = true;
255| });
256| auto t0 = std::chrono::steady_clock::now();
257| try {
258| while (!done.load() && std::chrono::duration_cast<std::chrono::seconds>(
259| std::chrono::steady_clock::now() - t0).count() < secs) {
260| MSG msg;
261| while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
262| TranslateMessage(&msg);
263| DispatchMessageW(&msg);
264| }
265| Sleep(2);
266| }
267| } catch (const std::exception& e) { printf("[main] PUMP1 EXCEPTION: %s\n", e.what()); fflush(stdout); }
268| catch (...) { printf("[main] PUMP1 UNKNOWN EXCEPTION\n"); fflush(stdout); }
269| // Stay alive 5s with BOTH editors attached and the worker pumping,
270| // while MAIN KEEPS PUMPING like the bridge audio loop: distinguishes a
271| // live crash (bad) from a stop-pumping probe artifact.
272| auto t1 = std::chrono::steady_clock::now();
273| try {
274| while (std::chrono::duration_cast<std::chrono::seconds>(
275| std::chrono::steady_clock::now() - t1).count() < 5) {
276| MSG msg;
277| while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
278| TranslateMessage(&msg);
279| DispatchMessageW(&msg);
280| }
281| Sleep(2);
282| }
283| } catch (const std::exception& e) { printf("[main] PUMP2 EXCEPTION: %s\n", e.what()); fflush(stdout); }
284| catch (...) { printf("[main] PUMP2 UNKNOWN EXCEPTION\n"); fflush(stdout); }
285| printf("RESULT: done=%d aRes=%d bRes=%d\n", done.load() ? 1 : 0, aRes, bRes);
286| return (done.load() && aRes && bRes) ? 0 : 3;
287| } else if (variant == "bridge_two") {
288| // Exact bridge architecture: per-channel persistent worker threads with
289| // own COM STA apartments and idle message pumps; inst1 loaded+attached
290| // on worker A, then inst2 loaded+attached on worker B; main pumps.