Best Regards,
Kostiantyn Kostiuk.

On Wed, Feb 11, 2026 at 11:05 AM Elizabeth Ashurov <[email protected]>
wrote:

> Problem:
> Two issues with COM initialization:
>
> Issue #1: Incorrect call order
> - requester_init() called CoInitializeSecurity first
> - Per Microsoft documentation, CoInitialize() must be called BEFORE
>   CoInitializeSecurity()
>
> Issue #2: Incorrect call location
> - CoInitializeSecurity was called from dll instead of the main process
> - Per Microsoft documentation, CoInitializeSecurity() must be called
> exactly once per process from
>   the main executable, not from a DLL
>
> Reference:
>
> https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializesecurity
>
> https://learn.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-coinitialize
>
> This caused incorrect COM initialization, preventing VSS Writers from
> calling back via IVssWriterCallback (hr = 0x80070005, Access denied,
> Event ID 8194).
>
> Fix:
> - Initialize COM in main.c for both service and CLI modes
> - Call CoInitialize() followed by CoInitializeSecurity() in correct order
>   in the main thread before any VSS operations
> - Add proper CoUninitialize() cleanup
>
> Result:
> VSS Writers can now successfully call back to the agent. Event ID 8194
> error is resolved.
>
> Signed-off-by: Elizabeth Ashurov <[email protected]>
> ---
>  qga/main.c                  | 43 +++++++++++++++++++++++++++++++++++++
>  qga/vss-win32/requester.cpp | 15 ++-----------
>  2 files changed, 45 insertions(+), 13 deletions(-)
>
> diff --git a/qga/main.c b/qga/main.c
> index dd1c216f9a..210d9983ab 100644
> --- a/qga/main.c
> +++ b/qga/main.c
> @@ -32,6 +32,8 @@
>  #include "qemu/systemd.h"
>  #include "qemu-version.h"
>  #ifdef _WIN32
> +#include <windows.h>
> +#include <objbase.h>
>  #include <dbt.h>
>  #include <pdh.h>
>  #include "qga/service-win32.h"
> @@ -842,6 +844,24 @@ VOID WINAPI service_main(DWORD argc, TCHAR *argv[])
>          return;
>      }
>
> +    /* Initialize COM for VSS operations in the service thread */
> +    HRESULT hr_com = CoInitialize(NULL);
> +    if (FAILED(hr_com)) {
> +        g_critical("Failed to initialize COM in service thread: 0x%lx",
> hr_com);
> +        return;
> +    }
> +
> +    hr_com = CoInitializeSecurity(
> +        NULL, -1, NULL, NULL,
> +        RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
> +        RPC_C_IMP_LEVEL_IDENTIFY,
> +        NULL, EOAC_NONE, NULL);
> +    if (FAILED(hr_com)) {
> +        g_critical("Failed to initialize COM security in service thread:
> 0x%lx", hr_com);
> +        CoUninitialize();
> +        return;
> +    }
> +
>

Lets preven code duplication and definitely for CoInitializeSecurity with a
huge amount of arguments,
so wrap this into a new function.


>      service->status.dwServiceType = SERVICE_WIN32;
>      service->status.dwCurrentState = SERVICE_RUNNING;
>      service->status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
> SERVICE_ACCEPT_SHUTDOWN;
> @@ -866,6 +886,8 @@ VOID WINAPI service_main(DWORD argc, TCHAR *argv[])
>
>      run_agent(ga_state);
>
> +    CoUninitialize();
> +
>      UnregisterDeviceNotification(service->device_notification_handle);
>      service->status.dwCurrentState = SERVICE_STOPPED;
>      SetServiceStatus(service->status_handle, &service->status);
> @@ -1714,12 +1736,33 @@ int main(int argc, char **argv)
>
>  #ifdef _WIN32
>      if (config->daemonize) {
> +        /* Service mode */
>          SERVICE_TABLE_ENTRY service_table[] = {
>              { (char *)QGA_SERVICE_NAME, service_main }, { NULL, NULL } };
>          StartServiceCtrlDispatcher(service_table);
>          ret = EXIT_SUCCESS;
>      } else {
> +        HRESULT hr_com = CoInitialize(NULL);
> +        if (FAILED(hr_com)) {
> +            g_critical("Failed to initialize COM: 0x%lx", hr_com);
> +            ret = EXIT_FAILURE;
> +            goto end;
> +        }
> +
> +        hr_com = CoInitializeSecurity(
> +            NULL, -1, NULL, NULL,
> +            RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
> +            RPC_C_IMP_LEVEL_IDENTIFY,
> +            NULL, EOAC_NONE, NULL);
> +        if (FAILED(hr_com)) {
> +            g_critical("Failed to initialize COM security: 0x%lx",
> hr_com);
> +            CoUninitialize();
> +            ret = EXIT_FAILURE;
> +            goto end;
> +        }
> +
>          ret = run_agent(s);
> +        CoUninitialize();
>      }
>  #else
>      ret = run_agent(s);
> diff --git a/qga/vss-win32/requester.cpp b/qga/vss-win32/requester.cpp
> index 74489fcd0a..9d978759f1 100644
> --- a/qga/vss-win32/requester.cpp
> +++ b/qga/vss-win32/requester.cpp
> @@ -60,15 +60,6 @@ STDAPI requester_init(void)
>  {
>      qga_debug_begin;
>
> -    COMInitializer initializer; /* to call CoInitializeSecurity */
> -    HRESULT hr = CoInitializeSecurity(
> -        NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
> -        RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);
> -    if (FAILED(hr)) {
> -        qga_debug("failed to CoInitializeSecurity (error %lx)", hr);
> -        return hr;
> -    }
> -
>      hLib = LoadLibraryA("VSSAPI.DLL");
>      if (!hLib) {
>          qga_debug("failed to load VSSAPI.DLL");
> @@ -320,8 +311,6 @@ void requester_freeze(int *num_vols, void
> *mountpoints, ErrorSet *errset)
>          return;
>      }
>
> -    CoInitialize(NULL);
> -
>      /* Allow unrestricted access to events */
>      InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
>      SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
> @@ -562,7 +551,7 @@ out:
>
>  out1:
>      requester_cleanup();
> -    CoUninitialize();
> +    /* COM is managed at process level in main.c - don't call
> CoUninitialize here */
>
>      qga_debug_end;
>  }
> @@ -643,7 +632,7 @@ void requester_thaw(int *num_vols, void *mountpints,
> ErrorSet *errset)
>      *num_vols = vss_ctx.cFrozenVols;
>      requester_cleanup();
>
> -    CoUninitialize();
> +    /* COM is managed at process level in main.c - don't call
> CoUninitialize here */
>      StopService();
>
>      qga_debug_end;
> --
> 2.51.0
>
>
>

Reply via email to