|
|
/* packager.c - OLE object wrapping application
* * Created by Microsoft Corporation. */
#include "packager.h"
#include <shellapi.h>
#include "dialogs.h"
#include <htmlhelp.h>
#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 Class> Object"
// object supports 1 verb == edit "<Object Class> Object"
// object supports 1 verb != edit "<verb> <Object Class> Object"
// object supports more than 1 verb "<Object Class> 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'
} } }
|