question

StevenWendling-9584 avatar image
0 Votes"
StevenWendling-9584 asked Castorix31 commented

Embedding Office in a child window, problems with .dtox files

Hello, I'm maintaining an application that uses OLE to embed Office objects in a child window of an MFC/C++ application. This has been working fine as of Office 2016, but with Office 2019 .dotx files are now opening in a separate Word client. I haven't seen this problem with .doc, .docx, or .dot files.

The clearest difference I see so far is that when we call DoVerb with OLEIVERB_SHOW the .dotx file immediately opens in a new Word application outside of the child window of my application. It might be that IOleClientSite setup has already gone wrong, but I'm currently fighting with my remote debugger to dig deeper on my VM with Office 2019.

I'm aware that OLE and embedded Office aren't supported(https://social.msdn.microsoft.com/Forums/en-US/127bd801-525d-41c3-8516-cac7c68ec43b/location-of-dsoframer-download?forum=csharpgeneral) so this could be written off as expected undefined behavior, but I'm hoping this rings a bell with someone since whatever is happening seems to only effect a single file type.

Thanks in advance, and apologies if my tags are not wholly appropriate.

windows-apic++
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

Castorix31 avatar image
3 Votes"
Castorix31 answered Castorix31 commented

This works for me on Windows 10, but with Office 2016 (as Admin to write into registry)
It should work with Office 2019 if .dotx are managed by Word.Template.12 too...
=>

 #include <windows.h>
 #include <tchar.h>
 #include <exdisp.h> // IWebBrowser2
    
 HINSTANCE hInst;
 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 int nWidth = 800, nHeight = 600;
 #define IDC_HTML 10
    
 HINSTANCE hATLDLL;
 typedef BOOL(__stdcall *PAAWI)(void);
 PAAWI pAtlAxWinInit;
 typedef HRESULT(__stdcall *PAAGC) (HWND hWnd, IUnknown** pUnknown);
 PAAGC pAtlAxGetControl;
    
 int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
 {
     hInst = hInstance;
     hATLDLL = LoadLibrary(_T("atl.dll"));
     pAtlAxWinInit = (PAAWI)GetProcAddress(hATLDLL, "AtlAxWinInit");
     if (pAtlAxWinInit)
         pAtlAxWinInit();
     pAtlAxGetControl = (PAAGC)GetProcAddress(hATLDLL, "AtlAxGetControl");
     WNDCLASSEX wcex =
     {
         sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInst, LoadIcon(NULL, IDI_APPLICATION),
         LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1), NULL, TEXT("WindowClass"), NULL,
     };
     if (!RegisterClassEx(&wcex))
         return MessageBox(NULL, TEXT("Cannot register class !"), TEXT("Error"), MB_ICONERROR | MB_OK);
     int nX = (GetSystemMetrics(SM_CXSCREEN) - nWidth) / 2, nY = (GetSystemMetrics(SM_CYSCREEN) - nHeight) / 2;
     HWND hWnd = CreateWindowEx(0, wcex.lpszClassName, TEXT("Test"), WS_OVERLAPPEDWINDOW, nX, nY, nWidth, nHeight, NULL, NULL, hInst, NULL);
     if (!hWnd)
         return MessageBox(NULL, TEXT("Cannot create window !"), TEXT("Error"), MB_ICONERROR | MB_OK);
     ShowWindow(hWnd, SW_SHOWNORMAL);
     UpdateWindow(hWnd);
     MSG msg;
     while (GetMessage(&msg, NULL, 0, 0))
     {
         TranslateMessage(&msg);
         DispatchMessage(&msg);
     }
     return (int)msg.wParam;
 }
    
 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     static HWND hHTMLWindow = NULL;
     switch (message)
     {
     case WM_CREATE:
     {
         // .doc
         HKEY hKey;
         DWORD dwResult = 0;
         LONG nResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Classes\\Word.Document.8"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwResult);
         if (nResult == ERROR_SUCCESS)
         {
             DWORD nValue = 0x80000024;
             RegSetValueEx(hKey, TEXT("BrowserFlags"), 0, REG_DWORD, (LPBYTE)&nValue, sizeof(nValue));    
             nValue = 0x10000;
             RegSetValueEx(hKey, TEXT("EditFlags"), 0, REG_DWORD, (LPBYTE)&nValue, sizeof(nValue));
         }
         else
         {
             WCHAR wsMessage[255];
             wsprintf(wsMessage, TEXT("Unable to open registry key : Error = %d"), nResult);
             MessageBox(hWnd, wsMessage, TEXT("Error"), MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
             return 0;
         }
         if (hKey)
             RegCloseKey(hKey);
    
         // .dotx
         dwResult = 0;
         nResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Classes\\Word.Template.12"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwResult);
         if (nResult == ERROR_SUCCESS)
         {
             DWORD nValue = 0x80000024;
             RegSetValueEx(hKey, TEXT("BrowserFlags"), 0, REG_DWORD, (LPBYTE)&nValue, sizeof(nValue));
             nValue = 0x10000;
             RegSetValueEx(hKey, TEXT("EditFlags"), 0, REG_DWORD, (LPBYTE)&nValue, sizeof(nValue));
         }
         else
         {
             WCHAR wsMessage[255];
             wsprintf(wsMessage, TEXT("Unable to open registry key : Error = %d"), nResult);
             MessageBox(hWnd, wsMessage, TEXT("Error"), MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
             return 0;
         }
         if (hKey)
             RegCloseKey(hKey);
    
         hHTMLWindow = CreateWindow(_T("AtlAxWin"), _T("about:blank"), WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_HSCROLL, 10, 10, 600, 400, hWnd, (HMENU)IDC_HTML, hInst, 0);
         if (hHTMLWindow)
         {
             HRESULT hr = E_FAIL;
             IUnknown* pUnknown = NULL;
             IWebBrowser2 *pWebBrowser = NULL;
             hr = pAtlAxGetControl(hHTMLWindow, &pUnknown);
             if (SUCCEEDED(hr))
             {
                 hr = pUnknown->QueryInterface(__uuidof(IWebBrowser2), (void**)&pWebBrowser);
                 if (SUCCEEDED(hr))
                 {
                     BSTR bstrURL;
                     VARIANT_BOOL vb;
                     //bstrURL = SysAllocString(_T("www.google.com"));
                     //bstrURL = SysAllocString(L"e:\\youtube_test.htm");
                     //bstrURL = SysAllocString(L"e:\\test.doc");
                     bstrURL = SysAllocString(L"e:\\test1.dotx");
                     VARIANT var;
                     var.vt = VT_EMPTY;
                     pWebBrowser->Navigate(bstrURL, &var, &var, &var, &var);
                     SysFreeString(bstrURL);
                     pWebBrowser->Release();
                 }
             }
         }
         return 0;
     }
     break;
     case WM_SIZE:
         MoveWindow(hHTMLWindow, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
         break;
     case WM_DESTROY:
     {
         PostQuitMessage(0);
         return 0;
     }
     break;
     default:
         return DefWindowProc(hWnd, message, wParam, lParam);
     }
     return 0;
 }



· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I ran this on my test VM and it works as I'd expect. I can explore swapping from bare OLE to ATL and see how feasible it is with our code base.

I do see some improvement in behavior even with just those 2 registry values set. The .dotx file opened in both the embedded window and the standalone Word app. The child window of my app was missing some pieces of Word like the Ribbon menu, and the standalone app opening tells me I'd still have some code to change, but this feels like progress worth exploring. Is there documentation available about the options in BrowserFlags and EditFlags? I'd love to poke around that documentation if it exists.

0 Votes 0 ·
Castorix31 avatar image Castorix31 StevenWendling-9584 ·

Is there documentation available about the options in BrowserFlags and EditFlags?

There was just an old KB : https://mskb.pkisolutions.com/kb/982995
and for EditFlags, some pages like : https://www.axelr.com/demos/reprodoc/open.htm
0 Votes 0 ·