/* packager.c - OLE object wrapping application * * Created by Microsoft Corporation. */ #include "packager.h" #include #include "dialogs.h" #include #define MenuFlag(b) ((b) ? MF_ENABLED : MF_GRAYED) /* 4-Oct-93 #2695 v-katsuy */ // win31#2174: 12/26/92 : fixing frame window initial position /* The width of the Packager Frame window is nearly equal to 640. This value must be changed, when the design will be changed. */ #define JPFRAMEWIDTH 640 // Pointer to function RegisterPenApp() VOID (CALLBACK *RegPen)(WORD, BOOL) = NULL; static BOOL gfDirty = FALSE; // TRUE if file needs to be written static CHAR szEmbedding[] = "-Embedding"; // Not NLS specific static CHAR szEmbedding2[] = "/Embedding"; // Not NLS specific static CHAR szFrameClass[] = "AppClass"; // Not NLS specific static CHAR szObjectMenu[CBSHORTSTRING]; // "&Object" menu string static CHAR szEdit[CBSHORTSTRING]; // "Edit" string static CHAR szHelpFile[] = "PACKAGER.CHM"; // packager.chm static BOOL InitApplication(VOID); static BOOL InitInstance(VOID); static VOID EndInstance(VOID); static VOID SaveAsNeeded(VOID); static BOOL WriteToFile(VOID); static BOOL ReadFromFile(LPSTR lpstrFile); static OLESTATUS ProcessCmdLine(LPSTR lpCmdLine, INT nCmdShow); static VOID WaitForAllObjects(VOID); static VOID UpdateMenu(HMENU hmenu); static VOID UpdateObjectMenuItem(HMENU hMenu); static VOID ExecuteVerb(INT iVerb); INT_PTR CALLBACK fnFailedUpdate(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); static VOID SendOleClosed(VOID); static VOID CreateUntitled(VOID); static VOID MakePenAware(VOID); static VOID MakePenUnaware(VOID); static VOID MakeMenuString(CHAR *szCtrl, CHAR *szMenuStr, CHAR *szVerb, CHAR *szClass, CHAR *szObject); BOOL gbDBCS = FALSE; // TRUE if we're running in DBCS mode /* WinMain() - Main Windows routine */ INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow ) { MSG msg; LCID lcid; //DebugBreak(); // Store the application instance number ghInst = hInstance; // Check DBCSness lcid = GetThreadLocale(); gbDBCS = ( (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_JAPANESE) || (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_KOREAN) || (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_CHINESE) ); // Initialize application global information (window classes) if (!hPrevInstance) { if (!InitApplication()) return FALSE; } // Initialize instance-specific information if (!InitInstance() || !InitClient()) goto errRtn; if (!(gfServer = InitServer())) goto errRtn; MakePenAware(); if (ProcessCmdLine(lpCmdLine, nCmdShow) != OLE_OK) { DeleteServer(glpsrvr); goto errRtn; } // if blocking happened in SrvrOpen(), then wait for object to be created if (gfBlocked) WaitForObject(((LPPICT)(glpobj[CONTENT]))->lpObject); // Main message loop while (TRUE) { if (gfBlocked && glpsrvr) { BOOL bMore = TRUE; LHSERVER lhsrvr = glpsrvr->lhsrvr; gfBlocked = FALSE; while (bMore) { if (OleUnblockServer (lhsrvr, &bMore) != OLE_OK) break; if (gfBlocked) break; } } if (!GetMessage(&msg, NULL, 0, 0)) break; if (!TranslateAccelerator(ghwndFrame, ghAccTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } // // to support activation of file based object though Ole mechanism // we create a linked object out of file and then activate it. But // we don't get any notification when server closes the document. // Using the following mechanism we find it out and then grab the // contents from file // if (gfEmbObjectOpen) { LPEMBED lpembed = (LPEMBED)(glpobj[CONTENT]); if (lpembed != NULL && OleQueryOpen(lpembed->lpLinkObj) != OLE_OK) { gfEmbObjectOpen = FALSE; EmbRead(lpembed); EmbDeleteLinkObject(lpembed); if (gfInvisible) PostMessage(ghwndFrame, WM_SYSCOMMAND, SC_CLOSE, 0L); } } } goto cleanup; errRtn: if (ghwndFrame) DestroyWindow(ghwndFrame); cleanup: EndClient(); MakePenUnaware(); EndInstance(); return FALSE; } /* InitApplication() - Do application "global" initialization. * * This function registers the window classes used by the application. * Returns: TRUE iff successful. */ static BOOL InitApplication( VOID ) { WNDCLASS wc; wc.style = 0; wc.lpfnWndProc = FrameWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = ghInst; wc.hIcon = LoadIcon(ghInst, MAKEINTRESOURCE(ID_APPLICATION)); wc.hCursor = LoadCursor(ghInst, MAKEINTRESOURCE(SPLIT)); wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1); wc.lpszMenuName = MAKEINTRESOURCE(ID_APPLICATION); wc.lpszClassName = szFrameClass; if (!RegisterClass(&wc)) return FALSE; return InitPaneClasses(); } /* InitInstance() - Handles the instance-specific initialization. * * This function creates the main application window. * Returns: TRUE iff successful. */ static BOOL InitInstance( VOID ) { HDC hDC; ghAccTable = LoadAccelerators(ghInst, MAKEINTRESOURCE(ID_APPLICATION)); ghbrBackground = GetSysColorBrush(COLOR_APPWORKSPACE); ghcurWait = LoadCursor(NULL, IDC_WAIT); // Load the string resources LoadString(ghInst, IDS_APPNAME, szAppName, CBMESSAGEMAX); LoadString(ghInst, IDS_UNTITLED, szUntitled, CBMESSAGEMAX); // Create the Main Window if (gbDBCS) { /* 4-Oct-93 #2695 v-katsuy */ // win31#2174: 12/26/92 : fixing frame window initial position if (!(ghwndError = ghwndFrame = CreateWindow(szFrameClass, szAppName, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, // Following values are calculated when the window size is changed. // Default posiotion of a window is desided here, so dumy values // must be set here. JPFRAMEWIDTH, JPFRAMEWIDTH * 7 / 18, NULL, NULL, ghInst, NULL))) return FALSE; } else { if (!(ghwndError = ghwndFrame = CreateWindow(szFrameClass, szAppName, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, ghInst, NULL))) return FALSE; } // Initialize the registration database RegInit(); // Set the correct caption string OfnInit(); glpobj[CONTENT] = glpobj[APPEARANCE] = NULL; glpobjUndo[CONTENT] = glpobjUndo[APPEARANCE] = NULL; LoadString(ghInst, IDS_EDIT, szEdit, CBSHORTSTRING); LoadString(ghInst, IDS_OBJECT_MENU, szObjectMenu, CBSHORTSTRING); LoadString(ghInst, IDS_UNDO_MENU, szUndo, CBSHORTSTRING); LoadString(ghInst, IDS_GENERIC, szDummy, CBSHORTSTRING); LoadString(ghInst, IDS_CONTENT_OBJECT, szContent, CBMESSAGEMAX); LoadString(ghInst, IDS_APPEARANCE_OBJECT, szAppearance, CBMESSAGEMAX); // Initialize global variables with LOGPIXELSX and LOGPIXELSY if (hDC = GetDC (NULL)) { giXppli = GetDeviceCaps(hDC, LOGPIXELSX); giYppli = GetDeviceCaps(hDC, LOGPIXELSY); ReleaseDC(NULL, hDC); } return InitPanes(); } /* EndInstance() - Instance-specific termination code. */ static VOID EndInstance( VOID ) { EndPanes(); } /* FrameWndProc() - Frame window procedure. * * This function is the message handler for the application frame window. */ LRESULT CALLBACK FrameWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { BOOL fSuccess = FALSE; if (SplitterFrame(hwnd, msg, wParam, lParam)) return DefWindowProc(hwnd, msg, wParam, lParam); switch (msg) { case WM_READEMBEDDED: if (gpty[CONTENT] == PEMBED) { EmbRead(glpobj[CONTENT]); if (gfInvisible) PostMessage(ghwndFrame, WM_SYSCOMMAND, SC_CLOSE, 0L); } break; case WM_INITMENU: UpdateMenu((HMENU)wParam); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_NEXTWINDOW: // Special trickery works because APP = 0 & CONTENT = 1 Raise(GetTopWindow(hwnd) != ghwndPane[CONTENT]); break; case IDM_NEW: // Save the current file (if needed) SaveAsNeeded(); // delete the current doc, and create untitled document CreateUntitled(); break; case IDM_IMPORT: if (!OfnGetName(hwnd, IDM_IMPORT)) break; Hourglass(TRUE); DeletePane(CONTENT, TRUE); if (ReadFromFile(gszFileName)) { InvalidateRect(ghwndPane[CONTENT], NULL, TRUE); Dirty(); if (!gpty[APPEARANCE]) { if (glpobj[APPEARANCE] = IconCreateFromFile(gszFileName)) { gpty[APPEARANCE] = ICON; InvalidateRect(ghwndPane[APPEARANCE], NULL, TRUE); } } } Hourglass(FALSE); break; case IDM_EXPORT: if (!OfnGetName(hwnd, IDM_EXPORT)) return 0L; /* Operation cancelled */ Hourglass(TRUE); if (!WriteToFile()) ErrorMessage(E_FAILED_TO_SAVE_FILE); Hourglass(FALSE); break; case IDM_UPDATE: { OLESTATUS retval; if (Error(OleSavedClientDoc(glhcdoc))) ErrorMessage(W_FAILED_TO_NOTIFY); if ((retval = OleSavedServerDoc (glpdoc->lhdoc)) == OLE_OK) { gfDirty = FALSE; } else if (retval == OLE_ERROR_CANT_UPDATE_CLIENT) { // // The client doesn't take updates on Save. Let the // user explicitly update and exit, or continue with // the editing. // if (!MyDialogBox(DTFAILEDUPDATE, ghwndFrame, fnFailedUpdate)) { // update the object and exit gfOleClosed = TRUE; DeregisterDoc(); DeleteServer(glpsrvr); } } else { Error(retval); } break; } case IDM_EXIT: SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L); return 0L; break; case IDM_COMMAND: Raise(CONTENT); DeletePane(CONTENT, FALSE); if (gptyUndo[CONTENT] != CMDLINK) glpobj[CONTENT] = CmlCreate("", FALSE); else glpobj[CONTENT] = CmlClone(glpobjUndo[CONTENT]); if (glpobj[CONTENT]) gpty[CONTENT] = CMDLINK; if (glpobj[CONTENT] && ChangeCmdLine(glpobj[CONTENT])) { InvalidateRect(ghwndPane[CONTENT], NULL, TRUE); Dirty(); } else { CmlDelete(glpobj[CONTENT]); gpty[CONTENT] = NOTHING; glpobj[CONTENT] = NULL; SendMessage(ghwndPane[CONTENT], WM_COMMAND, IDM_UNDO, 0L); } break; case IDM_INSERTICON: PostMessage (ghwndBar[APPEARANCE], WM_COMMAND, IDM_INSERTICON, 0L); break; case IDM_DESC: case IDM_PICT: PostMessage(ghwndBar[CONTENT], WM_COMMAND, wParam, 0L); break; case IDM_LABEL: Raise(APPEARANCE); if (gpty[APPEARANCE] != ICON) break; ChangeLabel(glpobj[APPEARANCE]); InvalidateRect(ghwndPane[APPEARANCE], NULL, TRUE); Dirty(); break; case IDM_COPYPACKAGE: if (!CopyObjects()) ErrorMessage(E_CLIPBOARD_COPY_FAILED); break; case IDM_PASTE: // Check to see if we are pasting a packaged object if (IsClipboardFormatAvailable(gcfNative) && IsClipboardFormatAvailable(gcfOwnerLink)) { HANDLE hData; HANDLE hData2; LPSTR lpData; OpenClipboard(ghwndFrame); hData = GetClipboardData(gcfOwnerLink); if (lpData = GlobalLock(hData)) { // If it's the packager, get the native data if (!lstrcmpi(lpData, gszAppClassName) && (hData2 = GetClipboardData(gcfNative))) fSuccess = PutNative(hData2); // Unlock the clipboard Owner Link data GlobalUnlock(hData); } CloseClipboard(); } // Did we successfully read the native data? if (fSuccess) break; // ... guess not (maybe not Package!) PostMessage(GetTopWindow(hwnd), msg, wParam, lParam); break; case IDM_OBJECT: ExecuteVerb(0); // Execute the ONLY verb break; case IDM_INDEX: HtmlHelp(ghwndFrame, szHelpFile, HH_DISPLAY_TOPIC, 0L); break; case IDM_ABOUT: ShellAbout(hwnd, szAppName, "", LoadIcon(ghInst, MAKEINTRESOURCE(ID_APPLICATION))); break; default: if ((LOWORD(wParam) >= IDM_VERBMIN) && (LOWORD(wParam) <= IDM_VERBMAX)) { // An object verb has been selected // (Hmm. Did you know that an 'object verb' was a noun?) ExecuteVerb(LOWORD(wParam) - IDM_VERBMIN); } else { PostMessage(GetTopWindow(hwnd), msg, wParam, lParam); } break; } break; case WM_CLOSE: // // Update if necessary by notifying the server that we are closing // down, and revoke the server. // SaveAsNeeded(); SendOleClosed(); DeleteServer(glpsrvr); return 0L; case WM_DESTROY: PostQuitMessage(0); return 0L; default: return DefWindowProc(hwnd, msg, wParam, lParam); } return 0L; } /* SetTitle() - Sets the window caption to the current filename. * * If gszFileName is NULL, the caption will be set to "(Untitled)". * If DocSetHostNames() is called with a client app name, that name * will be prepended. * * For the Embedded case, the "Embedded #n" string is stored in * "Untitled", and is always displayed regardless of the file name. */ VOID SetTitle( BOOL fRegistering ) { CHAR szTitle[CBMESSAGEMAX + CBPATHMAX]; if (!gfEmbedded) { StringCchPrintf(szTitle, ARRAYSIZE(szTitle), "%s%s%s - %s", gszClientName, (*gszClientName) ? " " : "", szAppName, szUntitled); } else { CHAR szEmbnameContent[CBSHORTSTRING]; LoadString(ghInst, IDS_EMBNAME_CONTENT, szEmbnameContent, CBSHORTSTRING); if (gbDBCS) { //#3997: 2/19/93: changed Window title StringCchPrintf(szTitle, ARRAYSIZE(szTitle), "%s - %s %s", szAppName, szUntitled, szEmbnameContent); } else { StringCchPrintf(szTitle, ARRAYSIZE(szTitle), "%s - %s %s", szAppName, szEmbnameContent, szUntitled); } } // Perform the client document registration if (glhcdoc) { if (Error(OleRenameClientDoc(glhcdoc, szUntitled))) ErrorMessage(W_FAILED_TO_NOTIFY); if (!fRegistering) ChangeDocName(&glpdoc, szUntitled); } else { if (Error(OleRegisterClientDoc(gszAppClassName, szUntitled, 0L, &glhcdoc))) { ErrorMessage(W_FAILED_TO_NOTIFY); glhcdoc = 0; } // New file, so re-register it if (!fRegistering) glpdoc = InitDoc(glpsrvr, 0, szUntitled); } if (IsWindow(ghwndFrame)) SetWindowText(ghwndFrame, szTitle); } /* InitFile() - Reinitializes the title bar, etc... when editing a New file. */ VOID InitFile( VOID ) { gfDirty = FALSE; // Deregister the edited document, and wipe out the objects. DeregisterDoc(); // Reset the title bar, and register the OLE client document SetTitle(FALSE); } /* SaveAsNeeded() - Saves the file if it has been modified. It's assumed that * after this routine is called this document is going to be * closed. If that's not true, then this routine may have to * be rewritten. */ static VOID SaveAsNeeded( VOID ) { gfOleClosed = FALSE; if (gfDirty && gfEmbedded && (glpobj[APPEARANCE] || glpobj[CONTENT])) { CHAR sz[CBMESSAGEMAX]; CHAR sz2[CBMESSAGEMAX + CBPATHMAX]; if (gfInvisible) { SendDocChangeMsg(glpdoc, OLE_CLOSED); return; } LoadString(ghInst, gfEmbedded ? IDS_MAYBEUPDATE : IDS_MAYBESAVE, sz, CBMESSAGEMAX); StringCchPrintf(sz2, ARRAYSIZE(sz2), sz, (LPSTR)szUntitled); // Ask "Do you wish to save your changes?" if (MessageBoxAfterBlock(ghwndFrame, sz2, szAppName, MB_YESNO | MB_ICONQUESTION) == IDYES) { gfOleClosed = TRUE; return; } // If not saving changes, revert the document else if (OleRevertClientDoc(glhcdoc)) { ErrorMessage(W_FAILED_TO_NOTIFY); } } } /* WriteToFile() - Writes the current document to a file. * * Returns: TRUE iff successful. */ static BOOL WriteToFile( VOID ) { BOOL fSuccess = FALSE; OFSTRUCT reopenbuf; INT fh; CHAR szDesc[CBSTRINGMAX]; CHAR szMessage[CBSTRINGMAX + CBPATHMAX]; if (OpenFile(gszFileName, &reopenbuf, OF_EXIST) != -1) { // File exists, query for overwrite! LoadString(ghInst, IDS_OVERWRITE, szDesc, CharCountOf(szDesc)); StringCchPrintf(szMessage, ARRAYSIZE(szMessage), szDesc, gszFileName); if (MessageBoxAfterBlock(ghwndFrame, szMessage, szAppName, MB_YESNO | MB_ICONEXCLAMATION) == IDNO) return TRUE; } // Take care of this earlier? if ((fh = _lcreat((LPSTR)gszFileName, 0)) <= 0) { LoadString(ghInst, IDS_INVALID_FILENAME, szDesc, CharCountOf(szDesc)); StringCchPrintf(szMessage, ARRAYSIZE(szMessage), szDesc, gszFileName); MessageBoxAfterBlock(ghwndFrame, szMessage, szAppName, MB_OK); return FALSE; } Hourglass(TRUE); // Go to the top of the file _llseek(fh, 0L, 0); EmbWriteToFile(glpobj[CONTENT], fh); fSuccess = TRUE; // Close the file, and return _lclose(fh); gfDirty = FALSE; Hourglass(FALSE); return fSuccess; } /* ReadFromFile() - Reads OLE objects from a file. * * Reads as many objects as it can, in upwards order (better error recovery). * Returns: TRUE iff successful. */ static BOOL ReadFromFile( LPSTR lpstrFile ) { BOOL fSuccess = FALSE; Hourglass(TRUE); // Read in each object and get them in the right order if (!(glpobj[CONTENT] = EmbCreate(lpstrFile))) { goto Error; } gpty[CONTENT] = PEMBED; fSuccess = TRUE; Error: gfDirty = FALSE; Hourglass(FALSE); return fSuccess; } /* ErrorMessage() - Pops up a message box containing a string table message. * * Pre: Assigns "ghwndError" to be its parent, so focus will return properly. */ VOID ErrorMessage( UINT id ) { CHAR sz[300]; if (IsWindow(ghwndError)) { LoadString(ghInst, id, sz, 300); MessageBoxAfterBlock(ghwndError, sz, szAppName, MB_OK | MB_ICONEXCLAMATION); } } /* ProcessMessage() - Spin in a message dispatch loop. */ BOOL ProcessMessage( VOID ) { BOOL fReturn; MSG msg; if (fReturn = GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(ghwndFrame, ghAccTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return fReturn; } /* Contains() - Determines whether a string matches a pattern. * This could be more intelligent, but it is scarcely executed. * * Returns: Non-NULL iff lpPattern is a substring of lpString. */ LPSTR Contains( LPSTR lpString, LPSTR lpPattern ) { LPSTR lpSubstr; LPSTR lpPat; for (;;) { // Match the first character while (*lpString && *lpString != *lpPattern) lpString++; // We are at the end of the string, fail... if (!(*lpString)) return NULL; // If we have a match, try to match the entire pattern string lpPat = lpPattern; lpSubstr = lpString; while (*lpPat && *lpSubstr && *lpPat == *lpSubstr) { lpPat++; lpSubstr++; } // We are at the end of the pattern, success! Wipe out the pattern if (!(*lpPat)) return lpString; // We are at the end of the string, failure... if (!(*lpSubstr)) return NULL; lpString++; } } /* ProcessCmdLine() - Processes the command line options. */ static OLESTATUS ProcessCmdLine( LPSTR lpCmdLine, INT nCmdShow ) { OLESTATUS retval = OLE_OK; // Does the command line contain "/Embedding"? if (gfEmbeddedFlag = gfInvisible = (Contains(lpCmdLine, szEmbedding) || Contains(lpCmdLine, szEmbedding2))) { // If we have a file name, register it NOW! lpCmdLine += lstrlen(szEmbedding); while (*lpCmdLine && *lpCmdLine == ' ') lpCmdLine++; if (*lpCmdLine) { retval = (glpsrvr->olesrvr.lpvtbl->Open) ((LPOLESERVER)glpsrvr, 0, lpCmdLine, (LPOLESERVERDOC *)&glpdoc); if (retval != OLE_OK) return retval; } gfDirty = FALSE; gnCmdShowSave = nCmdShow; } else { ShowWindow(ghwndFrame, nCmdShow); SendMessage(ghwndFrame, WM_COMMAND, IDM_NEW, 0L); } return retval; } /* Dirty() - This function is called each time the document is soiled. */ VOID Dirty( VOID ) { gfDirty = TRUE; SendDocChangeMsg(glpdoc, OLE_CHANGED); } /* WaitForAllObjects() - Wait for asynchronous operations to complete. * * We don't use ProcessMessage() because we want to terminate as quickly * as possible, and we don't want to allow any structured user input. */ static VOID WaitForAllObjects( VOID ) { MSG msgWait; if (gcOleWait) { while (gcOleWait) { if (GetMessage(&msgWait, NULL, 0, 0)) DispatchMessage(&msgWait); } } } /* DeregisterDoc() - Deregisters the currently edited document. */ VOID DeregisterDoc( VOID ) { gfDocCleared = TRUE; SendOleClosed(); // Destroy all the objects DeletePane(APPEARANCE, TRUE); DeletePane(CONTENT, TRUE); // Wait for the objects to be deleted WaitForAllObjects(); if (glpdoc) { LHSERVERDOC lhdoc = glpdoc->lhdoc; glpdoc = NULL; OleRevokeServerDoc(lhdoc); } // Release the document if (glhcdoc) { if (Error(OleRevokeClientDoc(glhcdoc))) ErrorMessage(W_FAILED_TO_NOTIFY); glhcdoc = 0; } } static VOID UpdateMenu( HMENU hmenu ) { INT iPane; INT mf; iPane = (GetTopWindow(ghwndFrame) == ghwndPane[CONTENT]); EnableMenuItem(hmenu, IDM_EXPORT, MenuFlag(gpty[CONTENT] == PEMBED)); EnableMenuItem(hmenu, IDM_CLEAR, MenuFlag(gpty[iPane])); EnableMenuItem(hmenu, IDM_UNDO, MenuFlag(gptyUndo[iPane])); EnableMenuItem(hmenu, IDM_UPDATE, (gfEmbedded ? MF_ENABLED : MF_GRAYED)); if (((iPane == APPEARANCE) && gpty[iPane]) || (gpty[iPane] == PICTURE)) { EnableMenuItem(hmenu, IDM_CUT, MF_ENABLED); EnableMenuItem(hmenu, IDM_COPY, MF_ENABLED); } else { EnableMenuItem(hmenu, IDM_CUT, MF_GRAYED); EnableMenuItem(hmenu, IDM_COPY, MF_GRAYED); } if (gpty[iPane] == PICTURE) { LPPICT lppict = glpobj[iPane]; DWORD ot; mf = MF_GRAYED; if (lppict->lpObject) { OleQueryType(lppict->lpObject, &ot); // Enable Links... only if we have a linked object mf = MenuFlag(ot == OT_LINK); } EnableMenuItem(hmenu, IDM_LINKS, mf); EnableMenuItem(hmenu, IDM_LABEL, MF_GRAYED); } else { EnableMenuItem(hmenu, IDM_LINKS, MF_GRAYED); EnableMenuItem(hmenu, IDM_LABEL, MenuFlag(gpty[APPEARANCE] == ICON)); } UpdateObjectMenuItem(GetSubMenu(hmenu, POS_EDITMENU)); mf = MenuFlag(OleQueryCreateFromClip(gszProtocol, olerender_draw, 0) == OLE_OK || OleQueryCreateFromClip(gszSProtocol, olerender_draw, 0) == OLE_OK); EnableMenuItem(hmenu, IDM_PASTE, mf); if (iPane == CONTENT) { if (IsClipboardFormatAvailable(gcfFileName)) { EnableMenuItem(hmenu, IDM_PASTELINK, MF_ENABLED); } else { mf = MenuFlag(OleQueryLinkFromClip(gszProtocol, olerender_draw, 0) == OLE_OK); EnableMenuItem(hmenu, IDM_PASTELINK, mf); } } else { EnableMenuItem(hmenu, IDM_PASTELINK, MF_GRAYED); } mf = MenuFlag(gpty[CONTENT] && gpty[APPEARANCE]); EnableMenuItem(hmenu, IDM_COPYPACKAGE, mf); } /* UpdateObjectMenuItem - If there are items in the selection, add the * menu, with a possible popup depending on the * number of verbs. */ static VOID UpdateObjectMenuItem( HMENU hMenu ) { INT cVerbs = 0; /* how many verbs in list */ HWND hwndItem = NULL; INT iPane; LONG objtype; LPPICT lpPict; CHAR szWordOrder2[10]; CHAR szWordOrder3[10]; if (!hMenu) return; DeleteMenu(hMenu, POS_OBJECT, MF_BYPOSITION); LoadString(ghInst, IDS_POPUPVERBS, szWordOrder2, sizeof(szWordOrder2)); LoadString(ghInst, IDS_SINGLEVERB, szWordOrder3, sizeof(szWordOrder3)); // // CASES: // object supports 0 verbs " Object" // object supports 1 verb == edit " Object" // object supports 1 verb != edit " Object" // object supports more than 1 verb " Object" => verbs // iPane = ((hwndItem = GetTopWindow(ghwndFrame)) == ghwndPane[CONTENT]); lpPict = glpobj[iPane]; if (lpPict && OleQueryType(lpPict->lpObject, &objtype) == OLE_OK && hwndItem && gpty[iPane] == PICTURE && objtype != OT_STATIC) { HANDLE hData = NULL; LPSTR lpstrData; if (OleGetData(lpPict->lpObject, (OLECLIPFORMAT) (objtype == OT_LINK ? gcfLink : gcfOwnerLink), &hData) == OLE_OK) { // Both link formats are: "szClass0szDocument0szItem00" if (lpstrData = GlobalLock(hData)) { DWORD dwSize = KEYNAMESIZE; CHAR szClass[KEYNAMESIZE], szBuffer[200]; CHAR szVerb[KEYNAMESIZE]; HANDLE hPopupNew = NULL; // get real language class of object in szClass for menu if (RegQueryValue(HKEY_CLASSES_ROOT, lpstrData, szClass, &dwSize)) StringCchCopy(szClass, ARRAYSIZE(szClass), lpstrData); /* if above call failed */ GlobalUnlock(hData); // append class key for (cVerbs = 0; ; ++cVerbs) { dwSize = KEYNAMESIZE; StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), "%s\\protocol\\StdFileEditing\\verb\\%d", lpstrData, cVerbs); if (RegQueryValue(HKEY_CLASSES_ROOT, szBuffer, szVerb, &dwSize)) break; if (hPopupNew == NULL) hPopupNew = CreatePopupMenu(); InsertMenu(hPopupNew, (UINT)-1, MF_BYPOSITION, IDM_VERBMIN + cVerbs, szVerb); } if (cVerbs == 0) { MakeMenuString(szWordOrder3, szBuffer, szEdit, szClass, szObjectMenu); InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION, IDM_VERBMIN, szBuffer); } else if (cVerbs == 1) { MakeMenuString(szWordOrder3, szBuffer, szVerb, szClass, szObjectMenu); InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION, IDM_VERBMIN, szBuffer); DestroyMenu(hPopupNew); } else { // > 1 verbs MakeMenuString(szWordOrder2, szBuffer, NULL, szClass, szObjectMenu); InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION | MF_POPUP, (UINT_PTR)hPopupNew, szBuffer); } EnableMenuItem(hMenu, POS_OBJECT, MF_ENABLED | MF_BYPOSITION); return; } } } // error if got to here InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION, 0, szObjectMenu); EnableMenuItem(hMenu, POS_OBJECT, MF_GRAYED | MF_BYPOSITION); } /* ExecuteVerb() - Find the proper verb to execute for each selected item */ static VOID ExecuteVerb( INT iVerb ) { HWND hwndItem; INT iPane; RECT rc; iPane = ((hwndItem = GetTopWindow(ghwndFrame)) == ghwndPane[CONTENT]); GetClientRect(hwndItem, (LPRECT) & rc); // Execute the correct verb for this object if (Error(OleActivate(((LPPICT)(glpobj[iPane]))->lpObject, iVerb, TRUE, TRUE, hwndItem, &rc))) { if (OleQueryReleaseError(((LPPICT)(glpobj[iPane]))->lpObject) == OLE_ERROR_LAUNCH ) ErrorMessage(E_FAILED_TO_LAUNCH_SERVER); } else { LONG ot; WaitForObject(((LPPICT)(glpobj[iPane]))->lpObject); if (!glpobj[iPane]) return; OleQueryType(((LPPICT)(glpobj[iPane]))->lpObject, &ot); if (ot == OT_EMBEDDED) Error(OleSetHostNames(((LPPICT)(glpobj[iPane]))->lpObject, gszAppClassName, (iPane == CONTENT) ? szContent : szAppearance)); } } VOID Raise( INT iPane ) { if (GetTopWindow(ghwndFrame) != ghwndPane[iPane]) SendMessage(ghwndPane[iPane], WM_LBUTTONDOWN, 0, 0L); } INT_PTR CALLBACK fnFailedUpdate( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam ) { switch (msg) { case WM_INITDIALOG: { CHAR szMsg[200]; CHAR szStr[100]; LoadString(ghInst, IDS_FAILEDUPDATE, szStr, sizeof(szStr)); StringCchPrintf((LPSTR)szMsg, ARRAYSIZE(szMsg), szStr, gszClientName, szAppName); SetDlgItemText(hDlg, IDD_TEXT, szMsg); return TRUE; // default Push button gets the focus } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDCANCEL: case IDD_CONTINUEEDIT: EndDialog(hDlg, TRUE); break; case IDD_UPDATEEXIT: EndDialog(hDlg, FALSE); break; default: break; } break; default: break; } return FALSE; } static VOID SendOleClosed( VOID ) { // Do this first, so the data can be updated as needed if (glpdoc) { if (gfOleClosed) { SendDocChangeMsg(glpdoc, OLE_CLOSED); gfOleClosed = FALSE; } } } static VOID CreateUntitled( VOID ) { if (gfEmbedded) /* Unembed if embedded */ EndEmbedding(); if (gvlptempdoc = InitDoc(glpsrvr, 0, szUntitled)) { InitFile(); /* Reset the file */ glpdoc = gvlptempdoc; SetTitle(TRUE); gvlptempdoc = NULL; gfDocExists = TRUE; gfDocCleared = FALSE; } else { ErrorMessage(E_FAILED_TO_REGISTER_DOCUMENT); } } static VOID MakePenAware( VOID ) { HANDLE hPenWin = NULL; if ((hPenWin = LongToHandle(GetSystemMetrics(SM_PENWINDOWS))) != NULL) { // We do this fancy GetProcAddress simply because we don't // know if we're running Pen Windows. if ((RegPen = (VOID (CALLBACK *)(WORD, BOOL))GetProcAddress(hPenWin, "RegisterPenApp")) != NULL) (*RegPen)(1, TRUE); } } static VOID MakePenUnaware( VOID ) { if (RegPen != NULL) (*RegPen)(1, FALSE); } INT_PTR MessageBoxAfterBlock( HWND hwndParent, LPSTR lpText, LPSTR lpCaption, UINT fuStyle ) { if (glpsrvr && !gfBlocked && (OleBlockServer(glpsrvr->lhsrvr) == OLE_OK)) gfBlocked = TRUE; return MessageBox((gfInvisible ? NULL : hwndParent), lpText, lpCaption, fuStyle | MB_TOPMOST); } INT_PTR DialogBoxAfterBlock( LPCSTR lpTemplate, HWND hwndParent, DLGPROC lpDialogFunc ) { if (glpsrvr && !gfBlocked && (OleBlockServer(glpsrvr->lhsrvr) == OLE_OK)) gfBlocked = TRUE; return DialogBox(ghInst, lpTemplate, (gfInvisible ? NULL : hwndParent), lpDialogFunc); } static VOID MakeMenuString( CHAR *szCtrl, CHAR *szMenuStr, CHAR *szVerb, CHAR *szClass, CHAR *szObject ) { register CHAR c; CHAR *pStr; while (c = *szCtrl++) { switch (c) { case 'c': // class case 'C': // class pStr = szClass; break; case 'v': // class case 'V': // class pStr = szVerb; break; case 'o': // object case 'O': // object pStr = szObject; break; default: *szMenuStr++ = c; *szMenuStr = '\0'; // just in case continue; } if (pStr) // should always be true { StringCchCopy(szMenuStr, ARRAYSIZE(szMenuStr), pStr); szMenuStr += lstrlen(pStr); // point to '\0' } } }