{"record":{"id":"ed2973eb4c5e059f","repo":"iOfficeAI/OfficeCLI","slug":"invoke-name-hr-0x-hr-x8","errorCode":null,"errorMessage":"Invoke({name}) hr=0x{hr:X8}","messagePattern":"Invoke\\((.+?)\\) hr=0x(.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/WordPdfBackend.cs","lineNumber":228,"sourceCode":"    {\n        int dispId = DispId(d, name);\n        IntPtr argArr = args.Length > 0 ? Marshal.AllocHGlobal(VAR_SZ * args.Length) : IntPtr.Zero;\n        IntPtr namedArr = isPut ? Marshal.AllocHGlobal(4) : IntPtr.Zero;\n        IntPtr dp = Marshal.AllocHGlobal(IntPtr.Size * 2 + 8);\n        IntPtr result = Marshal.AllocHGlobal(VAR_SZ);\n        Marshal.WriteInt64(result, 0); Marshal.WriteInt64(result, 8, 0); Marshal.WriteInt64(result, 16, 0);\n        try\n        {\n            for (int i = 0; i < args.Length; i++) Wv(argArr + (args.Length - 1 - i) * VAR_SZ, args[i]);\n            if (isPut) Marshal.WriteInt32(namedArr, DISPID_PROPERTYPUT);\n            Marshal.WriteIntPtr(dp, argArr);\n            Marshal.WriteIntPtr(dp, IntPtr.Size, namedArr);\n            Marshal.WriteInt32(dp, IntPtr.Size * 2, args.Length);\n            Marshal.WriteInt32(dp, IntPtr.Size * 2 + 4, isPut ? 1 : 0);\n\n            var iid = Guid.Empty;\n            int hr = VT<F_Invoke>(d, 6)(d, dispId, ref iid, 0, flags, dp, result, IntPtr.Zero, IntPtr.Zero);\n            if (hr != 0) throw new InvalidOperationException($\"Invoke({name}) hr=0x{hr:X8}\");\n            return Rv(result);\n        }\n        finally\n        {\n            Cv(result); Marshal.FreeHGlobal(result);\n            Marshal.FreeHGlobal(dp);\n            for (int i = 0; i < args.Length; i++) Cv(argArr + i * VAR_SZ);\n            if (argArr != IntPtr.Zero) Marshal.FreeHGlobal(argArr);\n            if (namedArr != IntPtr.Zero) Marshal.FreeHGlobal(namedArr);\n        }\n    }\n\n    internal static void DispSet(IntPtr d, string name, object? v) => DispCall(d, name, 4, [v], true);\n    internal static object? DispGet(IntPtr d, string name) => DispCall(d, name, 2, []);\n    internal static object? DispMethod(IntPtr d, string name, params object?[] args) => DispCall(d, name, 1, args);\n\n    static byte[] RenderOne(IntPtr doc, uint i, IntPtr drFactory, int timeoutMs)\n    {","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/WordPdfBackend.cs#L210-L246","documentation":"Thrown when a raw COM IDispatch::Invoke call returns a non-zero HRESULT while driving Microsoft Word (or a WinRT PDF renderer) through hand-rolled P/Invoke delegates in WordPdfBackend. The backend marshals VARIANT arguments into native memory, calls the vtable slot at index 6 (IDispatch::Invoke) via a delegate fetched by VT<F_Invoke>, and surfaces any failure as an InvalidOperationException carrying the member name and the raw HRESULT. This is the lowest-level COM error path in the PDF conversion backend — every DispGet/DispSet/DispMethod call funnels through DispCall, so any Word Automation failure (locked document, bad argument, Word not installed, security dialog blocking) manifests here.","triggerScenarios":"Calling DocxToPdf or RenderOne when (a) the requested member does not exist or has a different signature on the installed Word version, (b) Word throws a COM error such as DISP_E_EXCEPTION (0x80020009) because the document is password-protected, read-only, corrupt, or contains macros blocked by AutomationSecurity, (c) the IDispatch pointer is stale because Word was killed externally, or (d) an argument VARIANT type does not match what the method expects (e.g. passing a string where an int is required). The 'name' placeholder is the late-bound member invoked (Name, Visible, DisplayAlerts, AutomationSecurity, Documents, Open, SaveAs2, Close, etc.).","commonSituations":"Running the docx-to-pdf conversion on a server or container where Word is not installed or is a click-to-run stub; converting a password-protected or DRM-locked document; a Windows update changing the Word COM type library; calling the backend on a non-Windows platform (the class is [SupportedOSPlatform(\"windows\")]); a document whose SaveAs2 with format 17 (wdFormatPDF) fails because the target temp path is unwritable or anti-malware blocks the write.","solutions":["Decode the HRESULT in the message: 0x80020009 = DISP_E_EXCEPTION (Word raised its own error — check the document state), 0x80070003 = path not found, 0x80004005 = E_FAIL (Word not properly installed or licensed), 0x80010108 = RPC_E_DISCONNECTED (Word process died).","Verify Microsoft Word is installed and licensed on the machine — the backend instantiates CLSID {000209FF-...} directly; a stub or viewer will fail.","If converting a specific document, open it manually in Word first to check for password prompts, protected view, or macro warnings that block automation.","Ensure the temp directory ($TMP / %TEMP%) is writable and has enough disk space for the intermediate PDF.","If running in a service/container, confirm Word can run in a non-interactive session (set Visible=false is already done; you may need to configure DCOM launch permissions via dcomcnfg for the Word application)."],"exampleFix":"// before: Convert with no pre-check, raw COM error surfaces\nvar pdf = WordPdfBackend.DocxToPdf(docxPath);\n\n// after: Pre-validate the document is not protected before invoking Word\nif (IsPasswordProtected(docxPath))\n    throw new CliException(\"Document is password-protected; remove protection before PDF conversion.\")\n        { Code = \"protected_document\" };\nvar pdf = WordPdfBackend.DocxToPdf(docxPath);","handlingStrategy":"try-catch","validationCode":"// Before calling DocxToPdf, verify Word is available\ntry\n{\n    var clsid = new Guid(\"000209FF-0000-0000-C000-000000000046\");\n    var iid = new Guid(\"00020400-0000-0000-C000-000000000046\");\n    WordPdfBackend.CoCreateInstance(ref clsid, IntPtr.Zero, 4, ref iid, out var word);\n    Marshal.Release(word);\n}\ncatch { /* Word not installed — PDF conversion unavailable */ }","typeGuard":null,"tryCatchPattern":"try\n{\n    var pdf = WordPdfBackend.DocxToPdf(docxPath);\n}\ncatch (InvalidOperationException ex) when (ex.Message.StartsWith(\"Invoke(\"))\n{\n    // Extract and decode the HRESULT from the message\n    var hrHex = System.Text.RegularExpressions.Regex.Match(ex.Message, \"hr=0x([0-9A-Fa-f]+)\");\n    if (hrHex.Success)\n    {\n        var hr = unchecked((int)Convert.ToUInt32(hrHex.Groups[1].Value, 16));\n        // DISP_E_EXCEPTION (0x80020009) = Word raised its own error\n        // RPC_E_DISCONNECTED (0x80010108) = Word process died\n        logger.LogError(\"Word COM Invoke failed: HRESULT 0x{HR:X8}\", hr);\n    }\n    throw new CliException($\"PDF conversion failed: Word Automation error.\") { Code = \"pdf_conversion_failed\" };\n}","preventionTips":["Ensure Microsoft Word (desktop, not viewer/online) is installed and activated on the machine before relying on PDF conversion.","Test the conversion path on a clean reference document to isolate environment issues from document-specific ones.","In server/service contexts, configure DCOM launch and identity permissions for Word via dcomcnfg.","Avoid converting password-protected or DRM-locked documents — strip protection first."],"tags":["com-interop","word-automation","pdf-conversion","windows-only","hresult"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}