Chandra

 view release on metacpan or  search on metacpan

include/webview-edge.c  view on Meta::CPAN

    static HMODULE dll = NULL;
    static int tried = 0;
    
    if (tried) return dll;
    tried = 1;
    
    /* Try loading WebView2Loader.dll from various locations */
    dll = LoadLibraryA("WebView2Loader.dll");
    if (dll) return dll;
    
    /* Try application directory */
    char path[MAX_PATH];
    if (GetModuleFileNameA(NULL, path, MAX_PATH)) {
        char *slash = strrchr(path, '\\');
        if (slash) {
            strcpy(slash + 1, "WebView2Loader.dll");
            dll = LoadLibraryA(path);
            if (dll) return dll;
        }
    }
    
    /* Try System32 */
    if (GetSystemDirectoryA(path, MAX_PATH)) {
        strcat(path, "\\WebView2Loader.dll");
        dll = LoadLibraryA(path);
    }
    
    return dll;
}

static int webview2_available(void) {
    HMODULE dll = webview2_load_dll();
    if (!dll) return 0;
    
    GetAvailableCoreWebView2BrowserVersionStringFunc getVersion = 
        (GetAvailableCoreWebView2BrowserVersionStringFunc)GetProcAddress(dll, "GetAvailableCoreWebView2BrowserVersionString");
    if (!getVersion) return 0;
    
    LPWSTR version = NULL;
    HRESULT hr = getVersion(NULL, &version);
    if (SUCCEEDED(hr) && version) {
        CoTaskMemFree(version);
        return 1;
    }
    
    return 0;
}

/* ---- Handler vtables and implementations ---- */

/* WebMessageHandler */
static HRESULT STDMETHODCALLTYPE wmh_QueryInterface(ICoreWebView2WebMessageReceivedEventHandler *This, REFIID riid, void **ppv) {
    (void)riid;
    *ppv = This;
    This->lpVtbl->AddRef(This);
    return S_OK;
}

static ULONG STDMETHODCALLTYPE wmh_AddRef(ICoreWebView2WebMessageReceivedEventHandler *This) {
    WebMessageHandler *h = (WebMessageHandler *)This;
    return InterlockedIncrement(&h->ref);
}

static ULONG STDMETHODCALLTYPE wmh_Release(ICoreWebView2WebMessageReceivedEventHandler *This) {
    WebMessageHandler *h = (WebMessageHandler *)This;
    LONG ref = InterlockedDecrement(&h->ref);
    if (ref == 0) {
        GlobalFree(h);
    }
    return ref;
}

static HRESULT STDMETHODCALLTYPE wmh_Invoke(
    ICoreWebView2WebMessageReceivedEventHandler *This,
    ICoreWebView2 *sender,
    ICoreWebView2WebMessageReceivedEventArgs *args) {
    
    (void)sender;
    WebMessageHandler *h = (WebMessageHandler *)This;
    
    LPWSTR message = NULL;
    HRESULT hr = args->lpVtbl->TryGetWebMessageAsString(args, &message);
    
    if (SUCCEEDED(hr) && message && h->w && h->w->external_invoke_cb) {
        /* Convert wide string to UTF-8 */
        int len = WideCharToMultiByte(CP_UTF8, 0, message, -1, NULL, 0, NULL, NULL);
        char *utf8 = (char *)GlobalAlloc(GPTR, len);
        if (utf8) {
            WideCharToMultiByte(CP_UTF8, 0, message, -1, utf8, len, NULL, NULL);
            h->w->external_invoke_cb(h->w, utf8);
            GlobalFree(utf8);
        }
        CoTaskMemFree(message);
    }
    
    return S_OK;
}

static ICoreWebView2WebMessageReceivedEventHandlerVtbl wmh_vtbl = {
    wmh_QueryInterface, wmh_AddRef, wmh_Release, wmh_Invoke
};

/* EnvironmentHandler */
static HRESULT STDMETHODCALLTYPE eh_QueryInterface(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler *This, REFIID riid, void **ppv) {
    (void)riid;
    *ppv = This;
    This->lpVtbl->AddRef(This);
    return S_OK;
}

static ULONG STDMETHODCALLTYPE eh_AddRef(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler *This) {
    EnvironmentHandler *h = (EnvironmentHandler *)This;
    return InterlockedIncrement(&h->ref);
}

static ULONG STDMETHODCALLTYPE eh_Release(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler *This) {
    EnvironmentHandler *h = (EnvironmentHandler *)This;
    LONG ref = InterlockedDecrement(&h->ref);
    if (ref == 0) {
        GlobalFree(h);
    }
    return ref;
}

/* Forward declaration for controller creation */
static void webview2_create_controller(struct webview *w);

static HRESULT STDMETHODCALLTYPE eh_Invoke(
    ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler *This,
    HRESULT result,
    ICoreWebView2Environment *environment) {
    
    EnvironmentHandler *h = (EnvironmentHandler *)This;
    
    if (FAILED(result) || !environment) {
        return S_OK;
    }
    
    if (h->w && h->w->priv.webview2) {
        h->w->priv.webview2->environment = environment;
        environment->lpVtbl->AddRef(environment);
        webview2_create_controller(h->w);
    }
    
    return S_OK;
}

static ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandlerVtbl eh_vtbl = {
    eh_QueryInterface, eh_AddRef, eh_Release, eh_Invoke
};

/* ControllerHandler */
static HRESULT STDMETHODCALLTYPE ch_QueryInterface(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler *This, REFIID riid, void **ppv) {
    (void)riid;
    *ppv = This;
    This->lpVtbl->AddRef(This);
    return S_OK;
}

static ULONG STDMETHODCALLTYPE ch_AddRef(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler *This) {
    ControllerHandler *h = (ControllerHandler *)This;
    return InterlockedIncrement(&h->ref);
}

static ULONG STDMETHODCALLTYPE ch_Release(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler *This) {
    ControllerHandler *h = (ControllerHandler *)This;
    LONG ref = InterlockedDecrement(&h->ref);
    if (ref == 0) {
        GlobalFree(h);
    }
    return ref;
}

static HRESULT STDMETHODCALLTYPE ch_Invoke(
    ICoreWebView2CreateCoreWebView2ControllerCompletedHandler *This,
    HRESULT result,
    ICoreWebView2Controller *controller) {
    
    ControllerHandler *h = (ControllerHandler *)This;
    
    if (FAILED(result) || !controller) {
        return S_OK;
    }
    
    if (!h->w || !h->w->priv.webview2) {
        return S_OK;
    }
    
    webview2 *wv2 = h->w->priv.webview2;
    wv2->controller = controller;
    controller->lpVtbl->AddRef(controller);
    
    /* Get the CoreWebView2 */
    ICoreWebView2 *webview = NULL;
    controller->lpVtbl->get_CoreWebView2(controller, &webview);
    if (!webview) {
        return S_OK;
    }
    
    wv2->webview = webview;
    
    /* Configure settings */
    ICoreWebView2Settings *settings = NULL;
    webview->lpVtbl->get_Settings(webview, &settings);
    if (settings) {
        settings->lpVtbl->put_IsScriptEnabled(settings, TRUE);
        settings->lpVtbl->put_IsWebMessageEnabled(settings, TRUE);
        settings->lpVtbl->put_AreDefaultContextMenusEnabled(settings, h->w->debug ? TRUE : FALSE);
        settings->lpVtbl->put_AreDevToolsEnabled(settings, h->w->debug ? TRUE : FALSE);
        settings->lpVtbl->Release(settings);
    }
    
    /* Add web message handler */
    WebMessageHandler *wmh = (WebMessageHandler *)GlobalAlloc(GPTR, sizeof(WebMessageHandler));
    if (wmh) {
        wmh->lpVtbl = &wmh_vtbl;
        wmh->ref = 1;
        wmh->w = h->w;
        webview->lpVtbl->add_WebMessageReceived(webview, (ICoreWebView2WebMessageReceivedEventHandler *)wmh, &wv2->message_token);
        wmh->lpVtbl->Release((ICoreWebView2WebMessageReceivedEventHandler *)wmh);
    }
    
    /* Inject bridge script */
    static const wchar_t bridge_js[] = 
        L"window.external = window.external || {};"
        L"window.external.invoke = function(s) {"
        L"  window.chrome.webview.postMessage(s);"



( run in 2.192 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )