基本Win32 WebView2示例无法在纯C中工作 一个新的问题最近引起了我的注意:一个非常简单的代码使用微软的WebVIEW2库,如果编译成C++,而不是C。什么会引起这个问题?我尝试了各种各样的修复,比如使用旧版本的WebView2库,使用Edge Canary或beta版,或者不同版本的WebView2运行时,它根本不起作用

基本Win32 WebView2示例无法在纯C中工作 一个新的问题最近引起了我的注意:一个非常简单的代码使用微软的WebVIEW2库,如果编译成C++,而不是C。什么会引起这个问题?我尝试了各种各样的修复,比如使用旧版本的WebView2库,使用Edge Canary或beta版,或者不同版本的WebView2运行时,它根本不起作用,c++,c,winapi,webview2,C++,C,Winapi,Webview2,以下是C语言中的示例代码: #include <initguid.h> #include <Windows.h> #include <stdio.h> #include <conio.h> #include <shlwapi.h> #pragma comment(lib, "Shlwapi.lib") #include <Shlobj_core.h> #include "WebView2.h&q

以下是C语言中的示例代码:

#include <initguid.h>
#include <Windows.h>
#include <stdio.h>
#include <conio.h>
#include <shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
#include <Shlobj_core.h>
#include "WebView2.h"

#define APPLICATION_NAME TEXT("WebView2")

#define error_printf printf

ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler* envHandler;
ICoreWebView2CreateCoreWebView2ControllerCompletedHandler* completedHandler;
HWND hWnd = NULL;
ICoreWebView2Controller* webviewController = NULL;
ICoreWebView2* webviewWindow = NULL;
BOOL bEnvCreated = FALSE;

ULONG HandlerRefCount = 0;
ULONG HandlerAddRef(IUnknown* This)
{
    return ++HandlerRefCount;
}
ULONG HandlerRelease(IUnknown* This)
{
    --HandlerRefCount;
    if (HandlerRefCount == 0)
    {
        if (completedHandler)
        {
            free(completedHandler->lpVtbl);
            free(completedHandler);
        }
        if (envHandler)
        {
            free(envHandler->lpVtbl);
            free(envHandler);
        }
    }
    return HandlerRefCount;
}
HRESULT HandlerQueryInterface(
    IUnknown* This,
    IID* riid,
    void** ppvObject
)
{
    *ppvObject = This;
    HandlerAddRef(This);
    return S_OK;
}
HRESULT HandlerInvoke(
    IUnknown* This,
    HRESULT errorCode,
    void* arg
)
{
    if (!bEnvCreated)
    {
        bEnvCreated = TRUE;
        char ch;
        completedHandler = malloc(sizeof(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler));
        if (!completedHandler)
        {
            error_printf(
                "%s:%d: %s (0x%x).\n",
                __FILE__,
                __LINE__,
                "Cannot allocate ICoreWebView2CreateCoreWebView2ControllerCompletedHandler",
                GetLastError()
            );
            ch = _getch();
            return GetLastError();
        }
        completedHandler->lpVtbl = malloc(sizeof(ICoreWebView2CreateCoreWebView2ControllerCompletedHandlerVtbl));
        if (!completedHandler->lpVtbl)
        {
            error_printf(
                "%s:%d: %s (0x%x).\n",
                __FILE__,
                __LINE__,
                "Cannot allocate ICoreWebView2CreateCoreWebView2ControllerCompletedHandlerVtbl",
                GetLastError()
            );
            ch = _getch();
            return GetLastError();
        }
        completedHandler->lpVtbl->AddRef = HandlerAddRef;
        completedHandler->lpVtbl->Release = HandlerRelease;
        completedHandler->lpVtbl->QueryInterface = HandlerQueryInterface;
        completedHandler->lpVtbl->Invoke = HandlerInvoke;

        ICoreWebView2Environment* env = arg;
        env->lpVtbl->CreateCoreWebView2Controller(
            env,
            hWnd,
            completedHandler
        );
    }
    else
    {
        ICoreWebView2Controller* controller = arg;

        if (controller != NULL) {
            webviewController = controller;
            webviewController->lpVtbl->get_CoreWebView2(
                webviewController,
                &webviewWindow
            );
        }

        ICoreWebView2Settings* Settings;
        webviewWindow->lpVtbl->get_Settings(
            webviewWindow,
            &Settings
        );
        Settings->lpVtbl->put_IsScriptEnabled(
            Settings,
            TRUE
        );
        Settings->lpVtbl->put_AreDefaultScriptDialogsEnabled(
            Settings,
            TRUE
        );
        Settings->lpVtbl->put_IsWebMessageEnabled(
            Settings,
            TRUE
        );
        Settings->lpVtbl->put_AreDevToolsEnabled(
            Settings,
            FALSE
        );
        Settings->lpVtbl->put_AreDefaultContextMenusEnabled(
            Settings,
            TRUE
        );
        Settings->lpVtbl->put_IsStatusBarEnabled(
            Settings,
            TRUE
        );

        RECT bounds;
        GetClientRect(hWnd, &bounds);
        webviewController->lpVtbl->put_Bounds(
            webviewController,
            bounds
        );

        webviewWindow->lpVtbl->Navigate(
            webviewWindow,
            L"https://google.com/"
        );
    }

    return S_OK;
}

LRESULT CALLBACK WindowProc(
    _In_ HWND   hWnd,
    _In_ UINT   uMsg,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam
)
{
    switch (uMsg)
    {
    /*case WM_NCCALCSIZE:
    {
        return 0;
    }*/
    case WM_DPICHANGED:
    {
        RECT* const newWindowSize = (RECT*)(lParam);
        SetWindowPos(
            hWnd,
            NULL,
            newWindowSize->left,
            newWindowSize->top,
            newWindowSize->right - newWindowSize->left,
            newWindowSize->bottom - newWindowSize->top,
            SWP_NOZORDER | SWP_NOACTIVATE);
        return TRUE;
    }
    case WM_SIZE:
    {
        if (webviewController != NULL) {
            RECT bounds;
            GetClientRect(hWnd, &bounds);
            webviewController->lpVtbl->put_Bounds(
                webviewController,
                bounds
            );
        };
        break;
    }
    default:
    {
        return DefWindowProc(
            hWnd,
            uMsg,
            wParam,
            lParam
        );
    }
    }
    return 0;
}

int WINAPI wWinMain(
    _In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR lpCmdLine,
    _In_ int nShowCmd
)
{
    int ch;

    FILE* conout;
    AllocConsole();
    freopen_s(
        &conout,
        "CONOUT$",
        "w",
        stdout
    );

    HRESULT hr;

    if (!SetProcessDpiAwarenessContext(
        DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
    ))
    {
        error_printf(
            "%s:%d: %s (0x%x).\n",
            __FILE__,
            __LINE__,
            "SetProcessDpiAwarenessContext",
            GetLastError()
        );
        ch = _getch();
        return GetLastError();
    }

    hr = CoInitialize(NULL);
    if (FAILED(hr))
    {
        error_printf(
            "%s:%d: %s (0x%x).\n",
            __FILE__,
            __LINE__,
            "CoInitialize",
            hr
        );
        ch = _getch();
        return hr;
    }

    WNDCLASS wndClass = { 0 };
    wndClass.style = CS_HREDRAW | CS_VREDRAW;
    wndClass.lpfnWndProc = WindowProc;
    wndClass.cbClsExtra = 0;
    wndClass.cbWndExtra = 0;
    wndClass.hInstance = hInstance;
    wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wndClass.lpszMenuName = NULL;
    wndClass.lpszClassName = APPLICATION_NAME;

    hWnd = CreateWindowEx(
        0,
        (LPCWSTR)(
            MAKEINTATOM(
                RegisterClass(&wndClass)
            )
            ),
        APPLICATION_NAME,
        WS_OVERLAPPEDWINDOW,
        100, 100, 800, 800,
        NULL,
        NULL,
        hInstance,
        NULL
    );
    if (!hWnd)
    {
        error_printf(
            "%s:%d: %s (0x%x).\n",
            __FILE__,
            __LINE__,
            "CreateWindowEx",
            GetLastError()
        );
        ch = _getch();
        return GetLastError();
    }

    ShowWindow(hWnd, nShowCmd);

    envHandler = malloc(sizeof(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler));
    if (!envHandler)
    {
        error_printf(
            "%s:%d: %s (0x%x).\n",
            __FILE__,
            __LINE__,
            "Cannot allocate ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler",
            GetLastError()
        );
        ch = _getch();
        return GetLastError();
    }
    envHandler->lpVtbl = malloc(sizeof(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandlerVtbl));
    if (!envHandler->lpVtbl)
    {
        error_printf(
            "%s:%d: %s (0x%x).\n",
            __FILE__,
            __LINE__,
            "Cannot allocate ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandlerVtbl",
            GetLastError()
        );
        ch = _getch();
        return GetLastError();
    }
    envHandler->lpVtbl->AddRef = HandlerAddRef;
    envHandler->lpVtbl->Release = HandlerRelease;
    envHandler->lpVtbl->QueryInterface = HandlerQueryInterface;
    envHandler->lpVtbl->Invoke = HandlerInvoke;
    
    UpdateWindow(hWnd);

    CreateCoreWebView2EnvironmentWithOptions(
        NULL,
        NULL,
        NULL,
        envHandler
    );

    MSG msg;
    BOOL bRet;
    while ((bRet = GetMessage(
        &msg,
        NULL,
        0,
        0)) != 0)
    {
        // An error occured
        if (bRet == -1)
        {
            break;
        }
        else
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return 0;
}
既然我现在偶然发现了这一点,我真的很好奇这可能是什么原因造成的。这到底有什么关系?谢谢你的指点

它不工作意味着网页不显示。窗户是空的。WebView2实际上不显示在窗口上

编辑:

实际上什么是
wil::com\u ptr
s?如果我改变这一点:

static wil::com_ptr<ICoreWebView2Controller> webviewController;
static wil::com_ptr<ICoreWebView2> webviewWindow;

在C++中,我打破了它。为什么?为什么?(我用独立类替换了回调
Microsoft::WRL::Callback
,当然,它仍然有效,但是去掉COM指针和使用常规指针会使它失效。为什么…?

如果你真的花一分钟的时间看看代码的正确性和逻辑,而不是建议使用泛型,那么解决方案很简单cs和注释只是为了让配线电缆有一些字节可以携带。这一部分必须做一些修改:因为我在函数返回后使用
controller
,并且没有使用智能指针,所以我必须增加它的引用计数,以便库知道我在使用它,并且在调用
函数后不会释放它在body上执行。当然,当您在使用智能指针的版本中执行赋值时,这是在后台自动完成的。不幸的是,我忽略了这一点,没有意识到这会发生。这就是我用C编写这些端口的原因,以便我深入了解并更好地理解这些端口是如何自上而下工作的对我来说,没有实际理由的“不可能”不是一个有效的答案

无论如何,以下是固定版本:

if (controller != NULL) {
    webviewController = controller;
    webviewController->lpVtbl->get_CoreWebView2(
        webviewController,
         &webviewWindow
    );
    webviewController->lpVtbl->AddRef(webviewController); // <-- here, increase the reference count for the webviewController
}
if(控制器!=NULL){
webviewController=控制器;
webviewController->lpVtbl->get_CoreWebView2(
webviewController,
&webviewWindow
);

webviewController->lpVtbl->AddRef(webviewController);//解决方案很简单,如果你真的需要花一分钟的时间来检查代码的正确性和逻辑性,而不是建议泛型和注释,只是为了让插线有一些字节可以携带。这一部分必须修改一下:因为我在函数返回后使用
控制器
,而不使用智能指针,我必须增加其引用计数,以便库知道我在使用它,并且在执行
Invoke
函数体后不会释放它。当然,当您在使用智能指针的版本中执行赋值时,这会在后台自动完成。不幸的是,我忽略了这一点,没有意识到这一点这就是我用C语言编写这些端口的原因,这样我就可以从上到下更深入地了解这些东西是如何工作的。没有实际的原因,“这是不可能做到的”对我来说不是一个有效的答案

无论如何,以下是固定版本:

if (controller != NULL) {
    webviewController = controller;
    webviewController->lpVtbl->get_CoreWebView2(
        webviewController,
         &webviewWindow
    );
    webviewController->lpVtbl->AddRef(webviewController); // <-- here, increase the reference count for the webviewController
}
if(控制器!=NULL){
webviewController=控制器;
webviewController->lpVtbl->get_CoreWebView2(
webviewController,
&webviewWindow
);

webviewController->lpVtbl->AddRef(webviewController)WebVIEW2实际上没有显示在窗口上。这是Bux.com的ABI有两种语言要求:<代码> 1代码>创建指针结构。<代码> 2代码>代码。指针通过指针。C满足COM接口,可以使用C++。C也是如此。这有什么实际的技术原因呢?MIDL编译器也生成了一个带有C接口的头文件。代码编译得很好。从C调用COM是完全可能的。从C调用Windows运行时API是完全可能的,尽管很多人认为不是。两者之间的技术差异这两个,当然,我很好奇在这个特殊的情况下有什么不同。一般来说,当C中的东西不能工作,但C++中或其他语言工作时,我感到惊讶。@ iStCurtTe:这也是我所相信的;而且,调用确实很好…我的回调工作,它们被调用。我进入主循环,但没有WebVi。EW被添加到窗口中……在我看来,这是他们库中的东西,但是我不知道。我可以检查一下我关于COM指针的编辑吗?你知道吗?如果我用C++中的正则指针代替代码> WIL:COMYPPTR/代码>,我也会把它分解。为什么?网页没有显示。W是空白的。WebVIEW2实际上不显示在窗口上。这是Bux.com的ABI有两个语言级别的要求:<代码> 1代码>创建指针结构。<代码> 2代码>代码>指针。C满足这些要求。如果COM接口可以被C++消耗,那么它也可以被C所消耗。所有的技术原因都是这样的?MIDL编译器生成了一个带有C接口的头文件。代码编译得很好。从C调用COM是完全可能的。从C调用Windows运行时API是完全可能的,尽管很多人认为不是。当然,两者之间存在技术差异,我很好奇不同的是在这个特殊的情况下。通常,是的,当C中的东西不能工作,但C++中或其他语言工作时,我感到惊讶。@ iStCuTeTI,这也是我所相信的;而且,调用确实很好…我的回调函数,它们被调用。我进入主循环,但是没有WebView被添加到窗口……我觉得T这是他们图书馆里的东西,但我不知道是什么。@I不可检测你能检查编辑吗
if (controller != NULL) {
    webviewController = controller;
    webviewController->lpVtbl->get_CoreWebView2(
        webviewController,
         &webviewWindow
    );
    webviewController->lpVtbl->AddRef(webviewController); // <-- here, increase the reference count for the webviewController
}