# Windows Message Loop ## The #1 Cause of "Callbacks Don't Fire" If your SDK callbacks aren't firing (onSessionJoin, onUserJoin, etc.), you're almost certainly missing the Windows message loop. ``` ┌─────────────────────────────────────────────────────────────────┐ │ SYMPTOM │ CAUSE │ ├─────────────────────────────────────────────────────────────────┤ │ joinSession() returns success │ │ │ but onSessionJoin() never │ Missing Windows message loop │ │ fires │ │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## Why It's Required The Zoom Video SDK uses **Windows messaging** to dispatch callbacks. When an event occurs (user joins, video starts, etc.), the SDK posts a message to your thread's message queue. If you never process those messages, the callbacks never fire. ``` SDK Event Occurs ↓ SDK posts message to your thread's queue ↓ Your message loop calls PeekMessage/GetMessage ↓ Message is dispatched ↓ Your callback fires ``` **Without the message loop, step 3 never happens.** --- ## The Fix ### Console Application (No GUI) ```cpp int main() { // Initialize SDK IZoomVideoSDK* sdk = CreateZoomVideoSDKObj(); sdk->initialize(params); sdk->addListener(new MyDelegate()); sdk->joinSession(context); // ═══════════════════════════════════════════════════════════════ // CRITICAL: Windows message loop // ═══════════════════════════════════════════════════════════════ bool running = true; while (running) { MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { running = false; break; } TranslateMessage(&msg); DispatchMessage(&msg); } // Small sleep to avoid 100% CPU Sleep(10); } // Cleanup sdk->leaveSession(false); sdk->cleanup(); return 0; } ``` ### GUI Application (WinMain) GUI applications using standard WinMain already have a message loop, but make sure it's running: ```cpp int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // Create window, initialize SDK, etc. // Standard message loop MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } ``` --- ## Common Mistakes ### Mistake 1: No Message Loop At All ```cpp // WRONG - callbacks will never fire int main() { sdk->joinSession(context); // Waiting forever, but callbacks never fire while (!g_joined) { Sleep(100); // No message processing! } } ``` ### Mistake 2: Message Loop in Wrong Thread ```cpp // WRONG - SDK callbacks are tied to the thread that called joinSession void WorkerThread() { sdk->joinSession(context); // Callbacks tied to this thread } int main() { std::thread worker(WorkerThread); // Message loop on main thread won't help worker thread's callbacks MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } ``` **Fix**: Run message loop on the same thread that calls SDK methods. ### Mistake 3: Blocking the Message Loop ```cpp // WRONG - blocking call prevents message processing void onSessionJoin() override { // This blocks the message loop! std::this_thread::sleep_for(std::chrono::seconds(10)); // Or this: while (waiting) { } // Infinite loop blocks everything } ``` **Fix**: Keep callbacks fast. Use async/threading for long operations. --- ## Diagnostic Checklist If callbacks aren't firing: 1. **Is there a message loop?** - Look for `PeekMessage` or `GetMessage` in your code - Must be on the same thread that calls `joinSession()` 2. **Is the message loop running?** - Add logging: `std::cout << "Processing messages..." << std::endl;` - Should print continuously 3. **Is the delegate registered?** - `sdk->addListener(delegate)` must be called BEFORE `joinSession()` 4. **Are all delegate methods implemented?** - Missing pure virtual methods = compile error - Wrong signature = callback not called 5. **Is the SDK initialized?** - Check return value of `initialize()` --- ## Minimal Working Example ```cpp #include #include #include "zoom_video_sdk_api.h" #include "zoom_video_sdk_interface.h" #include "zoom_video_sdk_delegate_interface.h" USING_ZOOM_VIDEO_SDK_NAMESPACE bool g_joined = false; class TestDelegate : public IZoomVideoSDKDelegate { public: void onSessionJoin() override { std::cout << "*** onSessionJoin fired! ***" << std::endl; g_joined = true; } void onError(ZoomVideoSDKErrors err, int detail) override { std::cout << "*** onError: " << err << " ***" << std::endl; } // ... implement all other methods as empty }; int main() { IZoomVideoSDK* sdk = CreateZoomVideoSDKObj(); ZoomVideoSDKInitParams params; params.domain = L"https://zoom.us"; sdk->initialize(params); sdk->addListener(new TestDelegate()); ZoomVideoSDKSessionContext ctx; ctx.sessionName = L"test"; ctx.userName = L"Bot"; ctx.token = L"your-jwt"; ctx.audioOption.connect = false; sdk->joinSession(ctx); std::cout << "Starting message loop..." << std::endl; // THE CRITICAL PART while (!g_joined) { MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } Sleep(10); } std::cout << "Joined! Exiting..." << std::endl; sdk->leaveSession(false); sdk->cleanup(); return 0; } ``` --- ## Related Documentation - [Session Join Pattern](../examples/session-join-pattern.md) - Complete working code - [Common Issues](common-issues.md) - Other troubleshooting - [SDK Architecture Pattern](../concepts/sdk-architecture-pattern.md) - Event-driven design --- **TL;DR**: Add `PeekMessage`/`TranslateMessage`/`DispatchMessage` loop on the same thread that calls `joinSession()`. This is NOT optional.