115| bool stop = false; 116| }; 117| 118| int main(int argc, char* argv[]) { 119| if (argc < 2) { 120| printf("usage: gui_probe [variant] [secs] [hwnd]\n" 121| "variants: main_own | worker_own_nopump | worker_own_pump | worker_foreign_nopump | worker_foreign_pump | bridge_like | same_thread | two_instances | two_instances_close | close_reopen | bridge_two | shared_worker | ui_thread | two_workers_close\n"); 122| return 2; 123| } 124| std::string path = argv[1]; 125| std::string variant = argc > 2 ? argv[2] : "main_own"; 126| int secs = argc > 3 ? atoi(argv[3]) : 20; 127| 128| CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 129| 130| // Watchdog: never let a stuck plugin hang this probe forever. 131| std::thread([secs]() { 132| Sleep((DWORD)(secs + 10) * 1000); 133| printf("WATCHDOG-KILL\n"); 134| fflush(stdout); 135| TerminateProcess(GetCurrentProcess(), 0); 136| }).detach(); 137| 138| HWND ownHwnd = 0; 139| { 140| WNDCLASSEX wc = {}; 141| wc.cbSize = sizeof(wc); 142| wc.lpfnWndProc = DefWindowProc; 143| wc.hInstance = GetModuleHandle(nullptr); 144| wc.lpszClassName = "GuiProbeClass"; 145| RegisterClassEx(&wc); 146| ownHwnd = CreateWindowEx(0, "GuiProbeClass", "GuiProbe", WS_OVERLAPPEDWINDOW, 147| 0, 0, 800, 600, nullptr, nullptr, wc.hInstance, nullptr); 148| printf("ownHwnd=%p\n", (void*)ownHwnd); 149| } 150| 151| void* targetHwnd = (void*)ownHwnd; 152| if (argc > 4) targetHwnd = (void*)(uintptr_t)strtoull(argv[4], nullptr, 0); 153| 154| printf("loading %s\n", path.c_str()); 155| fflush(stdout); 156| Vst3Instrument inst; 157| Vst3Instrument inst2; 158| bool isDeferred = (variant == "bridge_like" || variant == "same_thread" || 159| variant == "two_instances" || variant == "two_instances_close" || 160| variant == "close_reopen" || variant == "bridge_two" || 161| variant == "shared_worker" || variant == "ui_thread"); 162| bool ok = true; 163| if (!isDeferred) { 164| ok = inst.loadPlugin(path, 44100.0); 165| printf("load=%d\n", ok ? 1 : 0); 166| fflush(stdout); 167| if (!ok) return 1; 168| } 169| 170| std::atomic done{false}; 171| std::atomic result{false}; 172| 173| auto attach_job = [&]() { 174| CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 175| printf("[%s] openGUI start hwnd=%p\n", variant.c_str(), targetHwnd); 176| fflush(stdout); 177| bool r = inst.openGUI(targetHwnd); 178| printf("[%s] openGUI returned=%d\n", variant.c_str(), r ? 1 : 0); 179| fflush(stdout); 180| result = r; 181| done = true; 182| }; 183| 184| if (variant == "main_own") { 185| attach_job(); // editorhost pattern: attached on main thread, pump after 186| pump_for(secs);