1336 lines
34 KiB
C
1336 lines
34 KiB
C
/*
|
||
OLE SERVER DEMO
|
||
SrvrDemo.c
|
||
|
||
This file contains the window handlers, and various initialization and
|
||
utility functions.
|
||
|
||
(c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
|
||
*/
|
||
|
||
|
||
#define SERVERONLY
|
||
#include <windows.h>
|
||
#include <ole.h>
|
||
|
||
#include "srvrdemo.h"
|
||
|
||
/* Global variable definitions */
|
||
|
||
HWND hwndMain = 0;
|
||
|
||
// Used in converting units from pixels to Himetric and vice-versa
|
||
int giXppli = 0; // pixels per logical inch along width
|
||
int giYppli = 0; // pixels per logical inch along height
|
||
|
||
|
||
|
||
// Since this is a not an MDI app, there can be only one server and one doc.
|
||
SRVR srvrMain;
|
||
DOC docMain;
|
||
CHAR szClient[cchFilenameMax];
|
||
CHAR szClientDoc[cchFilenameMax];
|
||
|
||
// Has the user made changes to the document?
|
||
BOOL fDocChanged = FALSE;
|
||
|
||
// Is this the first instance of this application currently running?
|
||
BOOL fFirstInstance = TRUE;
|
||
|
||
// This flag is used when OleRevokeServerDoc returns OLE_WAIT_FOR_RELEASE,
|
||
// and we must wait until DocRelease is called.
|
||
BOOL fWaitingForDocRelease = FALSE;
|
||
|
||
// This flag is used when OleRevokeServer returns OLE_WAIT_FOR_RELEASE,
|
||
// and we must wait until SrvrRelease is called.
|
||
BOOL fWaitingForSrvrRelease = FALSE;
|
||
|
||
// This flag is set to TRUE after an application has called OleBlockServer
|
||
// and now wishes to unblock the queued messages. See WinMain.
|
||
// Server Demo never sets fUnblock to TRUE because it never calls
|
||
// OleBlockServer.
|
||
BOOL fUnblock = FALSE;
|
||
|
||
// Set this to FALSE if you want to guarantee that the server will not revoke
|
||
// itself when SrvrRelease is called. This is used in the IDM_NEW case and
|
||
// the IDM_OPEN case (in OpenDoc).
|
||
BOOL fRevokeSrvrOnSrvrRelease = TRUE;
|
||
|
||
// Version number, which is stored in the native data.
|
||
VERSION version = 1;
|
||
|
||
HBRUSH hbrColor[chbrMax];
|
||
|
||
// Clipboard formats
|
||
OLECLIPFORMAT cfObjectLink;
|
||
OLECLIPFORMAT cfOwnerLink;
|
||
OLECLIPFORMAT cfNative;
|
||
|
||
// Method tables.
|
||
OLESERVERDOCVTBL docvtbl;
|
||
OLEOBJECTVTBL objvtbl;
|
||
OLESERVERVTBL srvrvtbl;
|
||
|
||
HANDLE hInst;
|
||
HANDLE hAccelTable;
|
||
HMENU hMainMenu = NULL;
|
||
|
||
// Window dimensions saved in private profile.
|
||
static struct
|
||
{
|
||
INT nX;
|
||
INT nY;
|
||
INT nWidth;
|
||
INT nHeight;
|
||
} dimsSaved, dimsCurrent;
|
||
|
||
|
||
static enum
|
||
{
|
||
// Corresponds to the order of the menus in the .rc file.
|
||
menuposFile,
|
||
menuposEdit,
|
||
menuposColor,
|
||
menuposObject
|
||
};
|
||
|
||
|
||
// Static functions.
|
||
static VOID DeleteInstance (VOID);
|
||
static BOOL ExitApplication (BOOL);
|
||
static VOID GetWord (LPSTR *plpszSrc, LPSTR lpszDst);
|
||
static BOOL InitApplication( HANDLE hInstance);
|
||
static BOOL InitInstance (HANDLE hInstance);
|
||
static BOOL ProcessCmdLine (LPSTR,HWND);
|
||
static VOID SaveDimensions (VOID);
|
||
static VOID SkipBlanks (LPSTR *plpsz);
|
||
static VOID UpdateObjMenus (VOID);
|
||
static BOOL FailedUpdate(HWND);
|
||
|
||
/* WinMain
|
||
* -------
|
||
*
|
||
* Standard windows entry point
|
||
*
|
||
* CUSTOMIZATION: None
|
||
*
|
||
*/
|
||
int APIENTRY WinMain(
|
||
HINSTANCE hInstance,
|
||
HINSTANCE hPrevInstance,
|
||
LPSTR lpCmdLine,
|
||
INT nCmdShow
|
||
){
|
||
MSG msg;
|
||
|
||
if (!InitApplication(hInstance))
|
||
return FALSE;
|
||
|
||
msg.wParam = FALSE;
|
||
|
||
if (!InitInstance(hInstance))
|
||
goto errRtn;
|
||
|
||
if (!InitServer (hwndMain, hInstance))
|
||
goto errRtn;
|
||
|
||
if (!ProcessCmdLine(lpCmdLine,hwndMain))
|
||
{
|
||
ExitApplication(FALSE);
|
||
goto errRtn;
|
||
}
|
||
|
||
for (;;)
|
||
{
|
||
// Your application should set fUnblock to TRUE when it decides
|
||
// to unblock.
|
||
if (fUnblock)
|
||
{
|
||
BOOL fMoreMsgs = TRUE;
|
||
while (fMoreMsgs)
|
||
{
|
||
if (srvrMain.lhsrvr == 0)
|
||
OleUnblockServer (srvrMain.lhsrvr, &fMoreMsgs);
|
||
}
|
||
// We have taken care of all the messages in the OLE queue
|
||
fUnblock = FALSE;
|
||
}
|
||
|
||
if (!GetMessage(&msg, NULL, 0, 0))
|
||
break;
|
||
if( !TranslateAccelerator(hwndMain, hAccelTable, &msg))
|
||
{
|
||
TranslateMessage(&msg);
|
||
DispatchMessage(&msg);
|
||
}
|
||
}
|
||
|
||
|
||
errRtn:
|
||
|
||
DeleteInstance ();
|
||
return (msg.wParam);
|
||
}
|
||
|
||
|
||
|
||
/* InitApplication
|
||
* ---------------
|
||
*
|
||
* Initialize the application - register the window classes
|
||
*
|
||
* HANDLE hInstance
|
||
*
|
||
* RETURNS: TRUE if classes are properly registered.
|
||
* FALSE otherwise
|
||
*
|
||
* CUSTOMIZATION: Re-implement
|
||
*
|
||
*/
|
||
static BOOL InitApplication( HANDLE hInstance )
|
||
{
|
||
WNDCLASS wc;
|
||
|
||
wc.lpszClassName = "MainClass";
|
||
wc.lpfnWndProc = (WNDPROC)MainWndProc;
|
||
wc.style = 0;
|
||
wc.cbClsExtra = 4;
|
||
wc.cbWndExtra = 0;
|
||
wc.hInstance = hInstance;
|
||
wc.hIcon = LoadIcon(hInstance, "DocIcon");
|
||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
|
||
wc.lpszMenuName = "MainMenu";
|
||
|
||
if (!RegisterClass(&wc))
|
||
return FALSE;
|
||
|
||
wc.lpszClassName = "ObjClass";
|
||
wc.lpfnWndProc = (WNDPROC)ObjWndProc;
|
||
wc.hIcon = NULL;
|
||
wc.cbWndExtra = cbWindExtra;
|
||
wc.lpszMenuName = NULL;
|
||
wc.hCursor = LoadCursor(NULL, IDC_CROSS);
|
||
|
||
if (!RegisterClass(&wc))
|
||
return FALSE;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
/* InitInstance
|
||
* ------------
|
||
*
|
||
* Create brushes used by the program, the main window, and
|
||
* do any other per-instance initialization.
|
||
*
|
||
* HANDLE hInstance
|
||
*
|
||
* RETURNS: TRUE if successful
|
||
* FALSE otherwise.
|
||
*
|
||
* CUSTOMIZATION: Re-implement
|
||
*
|
||
*/
|
||
static BOOL InitInstance (HANDLE hInstance)
|
||
{
|
||
LONG rglColor [chbrMax] =
|
||
{
|
||
0x000000ff, // Red
|
||
0x0000ff00, // Green
|
||
0x00ff0000, // Blue
|
||
0x00ffffff, // White
|
||
0x00808080, // Gray
|
||
0x00ffff00, // Cyan
|
||
0x00ff00ff, // Magenta
|
||
0x0000ffff // Yellow
|
||
};
|
||
|
||
|
||
INT iColor;
|
||
HDC hDC ;
|
||
|
||
hInst = hInstance;
|
||
|
||
// Initialize the method tables.
|
||
InitVTbls ();
|
||
|
||
// Initialize the brushes used.
|
||
for (iColor = 0; iColor < chbrMax; iColor++)
|
||
hbrColor[iColor] = CreateSolidBrush (rglColor[iColor]);
|
||
|
||
// Register clipboard formats.
|
||
cfObjectLink= RegisterClipboardFormat ("ObjectLink");
|
||
cfOwnerLink = RegisterClipboardFormat ("OwnerLink");
|
||
cfNative = RegisterClipboardFormat ("Native");
|
||
|
||
hAccelTable = LoadAccelerators(hInst, "Accelerators");
|
||
// hMainMenu = LoadMenu(hInst, "MainMenu");
|
||
|
||
|
||
hwndMain = CreateWindow(
|
||
"MainClass",
|
||
szAppName,
|
||
WS_OVERLAPPEDWINDOW,
|
||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||
3*OBJECT_WIDTH, 3*OBJECT_HEIGHT,
|
||
NULL,
|
||
NULL,
|
||
hInstance,
|
||
NULL
|
||
);
|
||
|
||
|
||
if (!hwndMain)
|
||
return FALSE;
|
||
|
||
szClient[0] = '\0';
|
||
lstrcpy (szClientDoc, "Client Document");
|
||
|
||
// Initialize global variables with LOGPIXELSX and LOGPIXELSY
|
||
|
||
hDC = GetDC (NULL); // Get the hDC of the desktop window
|
||
giXppli = GetDeviceCaps (hDC, LOGPIXELSX);
|
||
giYppli = GetDeviceCaps (hDC, LOGPIXELSY);
|
||
ReleaseDC (NULL, hDC);
|
||
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
|
||
|
||
/* DeleteInstance
|
||
* --------------
|
||
*
|
||
* Deallocate the VTables, and the brushes created for this instance
|
||
*
|
||
*
|
||
* CUSTOMIZATION: The call to FreeVTbls must remain.
|
||
*
|
||
*/
|
||
static VOID DeleteInstance (VOID)
|
||
{
|
||
INT i;
|
||
|
||
for (i = 0; i < chbrMax; i++)
|
||
DeleteObject (hbrColor[i]);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* ExitApplication
|
||
* ---------------
|
||
*
|
||
* Handles the WM_CLOSE and WM_COMMAND/IDM_EXIT messages.
|
||
*
|
||
* RETURNS: TRUE if application should really terminate
|
||
* FALSE if not
|
||
*
|
||
*
|
||
* CUSTOMIZATION: None
|
||
*
|
||
*/
|
||
static BOOL ExitApplication (BOOL fUpdateLater)
|
||
{
|
||
|
||
if (fUpdateLater)
|
||
{
|
||
// The non-standard OLE client did not accept the update
|
||
// when we requested it, so we are sending the client
|
||
// OLE_CLOSED now that we are closing the document.
|
||
SendDocMsg (OLE_CLOSED);
|
||
}
|
||
|
||
if (StartRevokingServer() == OLE_WAIT_FOR_RELEASE)
|
||
Wait (&fWaitingForSrvrRelease);
|
||
/* SrvrRelease will not necessarily post a WM_QUIT message.
|
||
If the document is not embedded, SrvrRelease by itself does
|
||
not cause the application to terminate. But now we want it to.
|
||
*/
|
||
if (docMain.doctype != doctypeEmbedded)
|
||
PostQuitMessage(0);
|
||
SaveDimensions();
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
/* MainWndProc
|
||
* -----------
|
||
*
|
||
* Main window message handler.
|
||
*
|
||
*
|
||
* CUSTOMIZATION: Remove the color menu and the object menu entirely.
|
||
* Add handlers for your application's menu items and any
|
||
* Windows messages your application needs to handle.
|
||
* The handlers for the menu items that involve OLE
|
||
* can be added to, but no logic should be removed.
|
||
*
|
||
*
|
||
*/
|
||
LONG APIENTRY MainWndProc
|
||
(HWND hwnd, UINT message, WPARAM wParam, LONG lParam )
|
||
{
|
||
LPOBJ lpobj;
|
||
|
||
switch (message)
|
||
{
|
||
case WM_COMMAND:
|
||
{
|
||
WORD wID = LOWORD(wParam);
|
||
|
||
if (fWaitingForDocRelease)
|
||
{
|
||
ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait.");
|
||
return 0;
|
||
}
|
||
|
||
switch (wID)
|
||
{
|
||
case IDM_EXIT:
|
||
SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
|
||
break;
|
||
|
||
case IDM_ABOUT:
|
||
DialogBox(hInst, "AboutBox", hwnd, (DLGPROC)About);
|
||
break;
|
||
|
||
case IDM_NEW:
|
||
{
|
||
BOOL fUpdateLater;
|
||
OLESTATUS olestatus;
|
||
|
||
if (SaveChangesOption (&fUpdateLater) == IDCANCEL)
|
||
break;
|
||
else if (fUpdateLater)
|
||
SendDocMsg (OLE_CLOSED);
|
||
|
||
// We want to revoke the doc but not the server, so if
|
||
// SrvrRelease is called, do not revoke server.
|
||
fRevokeSrvrOnSrvrRelease = FALSE;
|
||
|
||
if ((olestatus = RevokeDoc()) > OLE_WAIT_FOR_RELEASE)
|
||
{
|
||
ErrorBox ("Serious Error: Cannot revoke document.");
|
||
break;
|
||
}
|
||
else if (olestatus == OLE_WAIT_FOR_RELEASE)
|
||
Wait (&fWaitingForDocRelease);
|
||
|
||
fRevokeSrvrOnSrvrRelease = TRUE;
|
||
|
||
if (!CreateNewDoc (0, "(Untitled)", doctypeNew))
|
||
{
|
||
ErrorBox ("Serious Error: Cannot create new document.");
|
||
break;
|
||
}
|
||
// Your application need not create a default object.
|
||
CreateNewObj (FALSE);
|
||
EmbeddingModeOff();
|
||
break;
|
||
}
|
||
case IDM_OPEN:
|
||
OpenDoc();
|
||
UpdateObjMenus();
|
||
break;
|
||
|
||
case IDM_SAVE:
|
||
SaveDoc();
|
||
break;
|
||
|
||
case IDM_SAVEAS:
|
||
if (!SaveDocAs ())
|
||
break;
|
||
if (docMain.doctype != doctypeEmbedded)
|
||
EmbeddingModeOff();
|
||
break;
|
||
|
||
case IDM_UPDATE:
|
||
switch (OleSavedServerDoc (docMain.lhdoc))
|
||
{
|
||
case OLE_ERROR_CANT_UPDATE_CLIENT:
|
||
if (!FailedUpdate(hwnd))
|
||
ExitApplication(TRUE);
|
||
break;
|
||
case OLE_OK:
|
||
break;
|
||
default:
|
||
ErrorBox ("Serious Error: Cannot update.");
|
||
}
|
||
break;
|
||
|
||
/* Color menu */
|
||
|
||
case IDM_RED:
|
||
case IDM_GREEN:
|
||
case IDM_BLUE:
|
||
case IDM_WHITE:
|
||
case IDM_GRAY:
|
||
case IDM_CYAN:
|
||
case IDM_MAGENTA:
|
||
case IDM_YELLOW:
|
||
lpobj = SelectedObject();
|
||
lpobj->native.idmColor = wID;
|
||
// Recolor the object on the screen.
|
||
InvalidateRect (lpobj->hwnd, (LPRECT)NULL, TRUE);
|
||
UpdateWindow (lpobj->hwnd);
|
||
fDocChanged = TRUE;
|
||
if (docMain.doctype == doctypeFromFile)
|
||
// If object is linked, update it in client now.
|
||
SendObjMsg (lpobj, OLE_CHANGED);
|
||
break;
|
||
|
||
/* Edit menu */
|
||
|
||
case IDM_COPY:
|
||
CutOrCopyObj (TRUE);
|
||
break;
|
||
|
||
case IDM_CUT:
|
||
CutOrCopyObj (FALSE);
|
||
// Fall through.
|
||
|
||
case IDM_DELETE:
|
||
RevokeObj (SelectedObject());
|
||
DestroyWindow (SelectedObjectWindow());
|
||
UpdateObjMenus();
|
||
break;
|
||
|
||
/* Object menu */
|
||
|
||
case IDM_NEXTOBJ:
|
||
lpobj = SelectedObject();
|
||
/* The 1 in the second parameter puts the current window
|
||
at the bottom of the current window list. */
|
||
SetWindowPos(lpobj->hwnd, (HANDLE)1, 0,0,0,0,
|
||
SWP_NOMOVE | SWP_NOSIZE);
|
||
break;
|
||
|
||
case IDM_NEWOBJ:
|
||
lpobj = CreateNewObj (TRUE);
|
||
BringWindowToTop(lpobj->hwnd);
|
||
break;
|
||
|
||
default:
|
||
ErrorBox ("Unknown Command.");
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
|
||
case WM_NCCALCSIZE:
|
||
if (!IsIconic(hwnd) && !IsZoomed(hwnd))
|
||
{
|
||
dimsCurrent.nX = ((LPRECT)lParam)->left;
|
||
dimsCurrent.nWidth = ((LPRECT)lParam)->right - dimsCurrent.nX;
|
||
dimsCurrent.nY = ((LPRECT)lParam)->top;
|
||
dimsCurrent.nHeight = ((LPRECT)lParam)->bottom - dimsCurrent.nY;
|
||
}
|
||
return DefWindowProc(hwnd, message, wParam, lParam);
|
||
break;
|
||
|
||
case WM_QUERYENDSESSION:
|
||
{
|
||
BOOL fUpdateLater;
|
||
|
||
if (SaveChangesOption(&fUpdateLater) == IDCANCEL)
|
||
return FALSE;
|
||
|
||
if (fUpdateLater)
|
||
{
|
||
// The non-standard OLE client did not accept the update
|
||
// when we requested it, so we are sending the client
|
||
// OLE_CLOSED now that we are closing the document.
|
||
SendDocMsg (OLE_CLOSED);
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
case WM_CLOSE:
|
||
{
|
||
BOOL fUpdateLater;
|
||
|
||
if (SaveChangesOption(&fUpdateLater) != IDCANCEL)
|
||
ExitApplication(fUpdateLater);
|
||
break;
|
||
}
|
||
|
||
default:
|
||
return DefWindowProc(hwnd, message, wParam, lParam);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
|
||
/* About
|
||
* -----
|
||
*
|
||
* "About Box" dialog handler.
|
||
*
|
||
* CUSTOMIZATION: None
|
||
*
|
||
*/
|
||
BOOL APIENTRY About (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||
{
|
||
switch (message)
|
||
{
|
||
case WM_INITDIALOG:
|
||
return TRUE;
|
||
|
||
case WM_COMMAND:
|
||
{
|
||
WORD wID = LOWORD(wParam);
|
||
|
||
if (wID == IDOK || wID == IDCANCEL)
|
||
{
|
||
EndDialog(hDlg, TRUE);
|
||
return TRUE;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
|
||
/* ObjWndProc
|
||
* ----------
|
||
*
|
||
* Message handler for the object windows.
|
||
*
|
||
*
|
||
* CUSTOMIZATION: Server Demo specific
|
||
*
|
||
*/
|
||
LONG APIENTRY ObjWndProc
|
||
(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||
{
|
||
static BOOL fCapture = FALSE;
|
||
static struct {RECT rect; POINT pt;} drag;
|
||
static RECT rectMain;
|
||
|
||
switch (message)
|
||
{
|
||
case WM_CREATE:
|
||
{
|
||
LPOBJ lpobj;
|
||
LPCREATESTRUCT lpcs;
|
||
// The call to CreateWindow puts lpobj into lpCreateParams
|
||
lpcs = (LPCREATESTRUCT) lParam;
|
||
lpobj = (LPOBJ) lpcs->lpCreateParams;
|
||
// Associate the window just created with the object.
|
||
lpobj->hwnd = hwnd;
|
||
/* Store pointer to object in the window structure. */
|
||
SetWindowLong(hwnd, ibLpobj, (LONG) lpobj);
|
||
UpdateObjMenus ();
|
||
break;
|
||
}
|
||
case WM_SIZE:
|
||
{
|
||
RECT rect;
|
||
if (fWaitingForDocRelease)
|
||
{
|
||
ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait.");
|
||
return 0;
|
||
}
|
||
// Get coordinates of object relative to main window's client area.
|
||
GetWindowRect (hwnd, (LPRECT)&rect);
|
||
ScreenToClient (hwndMain, (LPPOINT)&rect);
|
||
ScreenToClient (hwndMain, (LPPOINT)&rect.right);
|
||
SizeObj (hwnd, rect, TRUE);
|
||
// Fall through.
|
||
}
|
||
case WM_PAINT:
|
||
PaintObj (hwnd);
|
||
break;
|
||
|
||
case WM_LBUTTONDOWN:
|
||
if (fWaitingForDocRelease)
|
||
{
|
||
ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait.");
|
||
return 0;
|
||
}
|
||
BringWindowToTop (hwnd);
|
||
|
||
GetWindowRect (hwnd, (LPRECT) &drag.rect);
|
||
ScreenToClient (hwndMain, (LPPOINT)&drag.rect.left);
|
||
ScreenToClient (hwndMain, (LPPOINT)&drag.rect.right);
|
||
|
||
drag.pt.x = LOWORD(lParam);
|
||
drag.pt.y = HIWORD(lParam);
|
||
|
||
// Convert drag.pt to the main window's client coordinates.
|
||
ClientToScreen (hwnd, (LPPOINT)&drag.pt);
|
||
ScreenToClient (hwndMain, (LPPOINT)&drag.pt);
|
||
|
||
// Remember the coordinates of the main window so we do not drag
|
||
// an object outside the main window.
|
||
GetClientRect (hwndMain, (LPRECT) &rectMain);
|
||
|
||
SetCapture (hwnd);
|
||
fCapture = TRUE;
|
||
break;
|
||
|
||
case WM_MOUSEMOVE:
|
||
{
|
||
HDC hdc;
|
||
POINT pt;
|
||
|
||
if (!fCapture)
|
||
break;
|
||
|
||
fDocChanged = TRUE;
|
||
pt.x = LOWORD(lParam);
|
||
pt.y = HIWORD(lParam);
|
||
|
||
// Convert pt to the main window's client coordinates.
|
||
ClientToScreen (hwnd, (LPPOINT)&pt);
|
||
ScreenToClient (hwndMain, (LPPOINT)&pt);
|
||
|
||
if (!PtInRect (&rectMain, pt))
|
||
break;
|
||
|
||
hdc = GetDC(hwndMain);
|
||
|
||
// Erase old drag rectangle
|
||
InvertRect (hdc, (LPRECT)&drag.rect);
|
||
|
||
// Update drag.rect
|
||
OffsetRect (&drag.rect, pt.x - drag.pt.x, pt.y - drag.pt.y);
|
||
|
||
// Update drag.pt
|
||
drag.pt.x = pt.x;
|
||
drag.pt.y = pt.y;
|
||
|
||
// Show new drag rectangle
|
||
InvertRect (hdc, (LPRECT)&drag.rect);
|
||
ReleaseDC (hwndMain, hdc);
|
||
break;
|
||
}
|
||
|
||
case WM_LBUTTONUP:
|
||
{
|
||
LPOBJ lpobj;
|
||
if (!fCapture)
|
||
return TRUE;
|
||
|
||
fCapture = FALSE;
|
||
ReleaseCapture ();
|
||
|
||
MoveWindow (hwnd, drag.rect.left, drag.rect.top,
|
||
drag.rect.right - drag.rect.left,
|
||
drag.rect.bottom - drag.rect.top, TRUE);
|
||
InvalidateRect (hwnd, (LPRECT)NULL, TRUE);
|
||
lpobj = HwndToLpobj (hwnd);
|
||
lpobj->native.nX = drag.rect.left;
|
||
lpobj->native.nY = drag.rect.top;
|
||
break;
|
||
}
|
||
case WM_DESTROY:
|
||
DestroyObj (hwnd);
|
||
return DefWindowProc(hwnd, message, wParam, lParam);
|
||
|
||
default:
|
||
return DefWindowProc(hwnd, message, wParam, lParam);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
|
||
/* DeviceToHiMetric
|
||
* ----------------
|
||
*
|
||
* Converts a point from device units to HiMetric units.
|
||
* This function is designed to be generic enough to be reused.
|
||
*
|
||
* HWND hwnd - The window whose display context is to be used
|
||
* LPPOINT lppt - The point to be converted.
|
||
*
|
||
* CUSTOMIZATION: None
|
||
*
|
||
*/
|
||
void DeviceToHiMetric ( LPPOINT lppt)
|
||
{
|
||
lppt->x = MulDiv (lppt->x, HIMETRIC_PER_INCH, giXppli);
|
||
lppt->y = MulDiv (lppt->y, HIMETRIC_PER_INCH, giYppli);
|
||
}
|
||
|
||
|
||
/* UpdateFileMenu
|
||
* --------------
|
||
*
|
||
* Updates the "Update <Client doc>" and "Exit & Return to <Client doc>"
|
||
* with the currently set client document name
|
||
*
|
||
* CUSTOMIZATION: Re-implement
|
||
*
|
||
*/
|
||
VOID UpdateFileMenu (INT iSaveUpdateId)
|
||
{
|
||
CHAR str[cchFilenameMax];
|
||
HMENU hMenu = GetMenu(hwndMain);
|
||
|
||
/* Change File menu so it contains "Update" instead of "Save". */
|
||
|
||
lstrcpy (str, "&Update ");
|
||
lstrcat (str, szClientDoc);
|
||
ModifyMenu(hMenu, iSaveUpdateId, MF_BYCOMMAND|MF_STRING, IDM_UPDATE, str);
|
||
|
||
/* Change File menu so it contains "Exit & Return to <client doc>" */
|
||
/* instead of just "Exit" */
|
||
|
||
lstrcpy (str, "E&xit && Return to ");
|
||
lstrcat (str, szClientDoc);
|
||
ModifyMenu(hMenu, IDM_EXIT, MF_BYCOMMAND|MF_STRING, IDM_EXIT, str);
|
||
}
|
||
|
||
|
||
|
||
/* EmbeddingModeOn
|
||
* ---------------
|
||
*
|
||
* Do whatever is necessary for the application to start "embedding mode."
|
||
*
|
||
* CUSTOMIZATION: Re-implement
|
||
*
|
||
*/
|
||
VOID EmbeddingModeOn(VOID)
|
||
{
|
||
HMENU hMenu = GetMenu(hwndMain);
|
||
|
||
UpdateFileMenu (IDM_SAVE);
|
||
|
||
/* Change File menu so it contains "Save Copy As..." instead of */
|
||
/* "Save As..." */
|
||
ModifyMenu(hMenu, IDM_SAVEAS, MF_BYCOMMAND|MF_STRING, IDM_SAVEAS,
|
||
"Save Copy As..");
|
||
|
||
/* In embedded mode, the user can edit only the embedded object, not
|
||
create new ones. */
|
||
EnableMenuItem(hMenu, menuposObject, MF_BYPOSITION | MF_GRAYED);
|
||
EnableMenuItem(hMenu, IDM_CUT, MF_BYCOMMAND | MF_GRAYED);
|
||
EnableMenuItem(hMenu, IDM_DELETE, MF_BYCOMMAND | MF_GRAYED);
|
||
DrawMenuBar (hwndMain);
|
||
}
|
||
|
||
|
||
|
||
|
||
/* EmbeddingModeOff
|
||
* ----------------
|
||
*
|
||
* Do whatever is necessary for the application to end "embedding mode."
|
||
*
|
||
* CUSTOMIZATION: Re-implement
|
||
*
|
||
*/
|
||
VOID EmbeddingModeOff (VOID)
|
||
{
|
||
HMENU hMenu = GetMenu(hwndMain);
|
||
|
||
/* Change File menu so it contains "Save" instead of "Update". */
|
||
ModifyMenu(hMenu, IDM_UPDATE, MF_BYCOMMAND | MF_STRING, IDM_SAVE, "&Save");
|
||
/* Change File menu so it contains "Exit & Return to <client doc>" */
|
||
/* instead of just "Exit" */
|
||
ModifyMenu(hMenu, IDM_EXIT, MF_BYCOMMAND | MF_STRING, IDM_EXIT, "E&xit");
|
||
|
||
/* Change File menu so it contains "Save As..." instead of */
|
||
/* "Save Copy As..." */
|
||
ModifyMenu(hMenu, IDM_SAVEAS, MF_BYCOMMAND|MF_STRING, IDM_SAVEAS,
|
||
"Save &As..");
|
||
|
||
/* In non-embedded mode, the user can create new objects. */
|
||
EnableMenuItem(hMenu, menuposObject, MF_BYPOSITION | MF_ENABLED);
|
||
|
||
lstrcpy (szClientDoc, "Client Document");
|
||
DrawMenuBar (hwndMain);
|
||
}
|
||
|
||
|
||
|
||
/* ErrorBox
|
||
* --------
|
||
*
|
||
* char *szMessage - String to display inside message box.
|
||
*
|
||
* CUSTOMIZATION: Server Demo specific
|
||
*
|
||
*/
|
||
VOID ErrorBox (CHAR *szMessage)
|
||
{
|
||
MessageBox (hwndMain, szMessage, szAppName, MB_OK);
|
||
}
|
||
|
||
|
||
|
||
/* GetWord
|
||
* -------
|
||
*
|
||
* LPSTR *plpszSrc - Pointer to a pointer to a source string
|
||
* LPSTR lpszDst - Pointer to destination buffer
|
||
*
|
||
* Will copy one space-terminated or null-terminated word from the source
|
||
* string to the destination buffer.
|
||
* When done, *plpszSrc will point to the character after the word.
|
||
*
|
||
* CUSTOMIZATION: Server Demo specific
|
||
*
|
||
*/
|
||
static VOID GetWord (LPSTR *plpszSrc, LPSTR lpszDst)
|
||
{
|
||
INT i = 0;
|
||
while (**plpszSrc && **plpszSrc != ' ')
|
||
{
|
||
lpszDst[i++] = *(*plpszSrc)++;
|
||
}
|
||
lpszDst[i] = '\0';
|
||
}
|
||
|
||
|
||
|
||
/* HiMetricToDevice
|
||
* ----------------
|
||
*
|
||
* Converts a point from HiMetric units to device units.
|
||
* This function is designed to be generic enough to be reused.
|
||
*
|
||
* HWND hwnd - The window whose display context is to be used
|
||
* LPPOINT lppt - The point to be converted.
|
||
*
|
||
* CUSTOMIZATION: None
|
||
*
|
||
*/
|
||
void HiMetricToDevice ( LPPOINT lppt )
|
||
{
|
||
lppt->x = MulDiv (giXppli, lppt->x, HIMETRIC_PER_INCH);
|
||
lppt->y = MulDiv (giYppli, lppt->y, HIMETRIC_PER_INCH);
|
||
}
|
||
|
||
|
||
|
||
/* HwndToLpobj
|
||
* -----------
|
||
*
|
||
* Given an object's window, return a pointer to the object.
|
||
* The GetWindowLong call extracts an LPOBJ from the extra data stored with
|
||
* the window.
|
||
*
|
||
* HWND hwndObj - Handle to the object's window
|
||
*
|
||
* RETURNS: A pointer to the object
|
||
*
|
||
* CUSTOMIZATION: Server Demo specific
|
||
*
|
||
*/
|
||
LPOBJ HwndToLpobj (HWND hwndObj)
|
||
{
|
||
return (LPOBJ) GetWindowLong (hwndObj, ibLpobj);
|
||
}
|
||
|
||
|
||
|
||
/* CreateUntitledDoc
|
||
* -----------------
|
||
*
|
||
* Create a fresh document with one object.
|
||
*
|
||
* RETURNS: TRUE if successful
|
||
* FALSE otherwise
|
||
*
|
||
* CUSTOMIZATION: Re-implement
|
||
*
|
||
*/
|
||
static BOOL CreateUntitledDoc (INT nCmdShow)
|
||
{
|
||
if (!CreateNewDoc (0, "(Untitled)", doctypeNew))
|
||
return FALSE;
|
||
CreateNewObj (FALSE);
|
||
ShowWindow(hwndMain, nCmdShow);
|
||
UpdateWindow(hwndMain);
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/* ProcessCmdLine
|
||
* --------------
|
||
*
|
||
* Parses the Windows command line which was passed to WinMain.
|
||
*
|
||
* Case One: SrvrDemo.exe
|
||
* fEmbedding = FALSE
|
||
* Create an untitled document.
|
||
*
|
||
* Case two: SrvrDemo.exe filename
|
||
* fEmbedding = FALSE
|
||
* Create a new document from the file.
|
||
*
|
||
* Case three: SrvrDemo.exe -Embedding
|
||
* fEmbedding = TRUE
|
||
* Do not create or register a document.
|
||
* Do not show window until client requests it.
|
||
*
|
||
* Case four: SrvrDemo.exe -Embedding filename
|
||
* fEmbedding = TRUE
|
||
* Load file.
|
||
* Call OleRegisterServerDoc.
|
||
* Do not show window until client requests it.
|
||
*
|
||
*
|
||
* LPSTR lpszLine - The Windows command line
|
||
* int nCmdShow - Parameter to WinMain
|
||
* HWND hwndMain - The application's main window
|
||
*
|
||
* RETURNS: TRUE if the command line was processed correctly.
|
||
* FALSE if a filename was specified which did not
|
||
* contain a proper document.
|
||
*
|
||
* CUSTOMIZATION: None.
|
||
*
|
||
*/
|
||
|
||
static BOOL ProcessCmdLine (LPSTR lpszLine, HWND hwndMain)
|
||
{
|
||
CHAR szBuf[cchFilenameMax];
|
||
BOOL fEmbedding = FALSE; // Is "-Embedding" on the command line?
|
||
INT i=0;
|
||
OFSTRUCT of;
|
||
|
||
if (!*lpszLine) // No filename or options, so start a fresh document.
|
||
{
|
||
return CreateUntitledDoc(SW_SHOWNORMAL);
|
||
}
|
||
|
||
SkipBlanks (&lpszLine);
|
||
|
||
// Check for "-Embedding" or "/Embedding" and set fEmbedding.
|
||
if(*lpszLine == '-' || *lpszLine == '/')
|
||
{
|
||
lpszLine++;
|
||
GetWord (&lpszLine, szBuf);
|
||
fEmbedding = !lstrcmp(szBuf, szEmbeddingFlag);
|
||
}
|
||
|
||
SkipBlanks (&lpszLine);
|
||
|
||
if (*lpszLine) // if there is a filename
|
||
{
|
||
// Put filename into szBuf.
|
||
GetWord (&lpszLine, szBuf);
|
||
|
||
if (-1 == OpenFile(szBuf, &of, OF_READ | OF_EXIST))
|
||
{
|
||
// File not found
|
||
if (fEmbedding)
|
||
return FALSE;
|
||
else
|
||
{
|
||
CHAR sz[100];
|
||
wsprintf (sz, "File %s not found.", (LPSTR) szBuf);
|
||
ErrorBox (sz);
|
||
return CreateUntitledDoc(SW_SHOWNORMAL);
|
||
}
|
||
}
|
||
|
||
if (!CreateDocFromFile (szBuf, 0, doctypeFromFile))
|
||
{
|
||
// File not in proper format.
|
||
if (fEmbedding)
|
||
return FALSE;
|
||
else
|
||
{
|
||
CHAR sz[100];
|
||
wsprintf (sz, "File %s not in proper format.", (LPSTR) szBuf);
|
||
ErrorBox (sz);
|
||
return CreateUntitledDoc(SW_SHOWNORMAL);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (fEmbedding)
|
||
{
|
||
/* Do not show window until told to do so by client. */
|
||
ShowWindow(hwndMain, SW_HIDE);
|
||
}
|
||
else
|
||
{
|
||
ShowWindow(hwndMain, SW_SHOWNORMAL);
|
||
UpdateWindow(hwndMain);
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
/* SaveDimensions
|
||
* --------------
|
||
*
|
||
* Save the dimensions of the main window in a private profile file.
|
||
*
|
||
* CUSTOMIZATION: This function may be removed. If you wish to support
|
||
* intelligent window placement, then the only necessary
|
||
* change is to change the string "SrvrDemo.Ini" to a filename
|
||
* appropriate for your application.
|
||
*/
|
||
static VOID SaveDimensions (VOID)
|
||
{
|
||
if ((dimsCurrent.nX != dimsSaved.nX) ||
|
||
(dimsCurrent.nY != dimsSaved.nY) ||
|
||
(dimsCurrent.nWidth != dimsSaved.nWidth) ||
|
||
(dimsCurrent.nHeight != dimsSaved.nHeight) )
|
||
{
|
||
// Save current window dimensions to private profile.
|
||
CHAR szBuf[7];
|
||
wsprintf (szBuf, "%d", dimsCurrent.nX);
|
||
WritePrivateProfileString
|
||
(szAppName, "x", szBuf, "SrvrDemo.Ini");
|
||
wsprintf (szBuf, "%d", dimsCurrent.nY);
|
||
WritePrivateProfileString
|
||
(szAppName, "y", szBuf, "SrvrDemo.Ini");
|
||
wsprintf (szBuf, "%d", dimsCurrent.nWidth);
|
||
WritePrivateProfileString
|
||
(szAppName, "w", szBuf, "SrvrDemo.Ini");
|
||
wsprintf (szBuf, "%d", dimsCurrent.nHeight);
|
||
WritePrivateProfileString
|
||
(szAppName, "h", szBuf, "SrvrDemo.Ini");
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/* SelectedObject
|
||
* --------------
|
||
*
|
||
* Return a pointer to the currently selected object.
|
||
*
|
||
* CUSTOMIZATION: What a "selected object" is will vary from application
|
||
* to application. You may find it useful to have a function
|
||
* like this. In your application it may be necessary to
|
||
* actually create an OBJ structure based on what data the
|
||
* user has selected from the document (by highlighting some
|
||
* text for example).
|
||
*
|
||
*/
|
||
LPOBJ SelectedObject (VOID)
|
||
{
|
||
return HwndToLpobj (SelectedObjectWindow());
|
||
}
|
||
|
||
|
||
|
||
|
||
/* SelectedObjectWindow
|
||
* --------------------
|
||
*
|
||
* Return a handle to the window for the currently selected object.
|
||
* The GetWindow calls returns a handle to the main window's first child,
|
||
* which is the selected object's window.
|
||
*
|
||
* CUSTOMIZATION: Server Demo specific
|
||
*
|
||
*/
|
||
HWND SelectedObjectWindow (VOID)
|
||
{
|
||
return GetWindow (hwndMain, GW_CHILD);
|
||
}
|
||
|
||
|
||
|
||
/* SetHiMetricFields
|
||
* -----------------
|
||
*
|
||
* Adjust the nHiMetricWidth and nHiMetricHeight fields of a NATIVE structure
|
||
* so that they are equivalent to the nWidth and nHeight fields.
|
||
* The negative sign in the last line is necessary because the positive
|
||
* y direction is toward the top of the screen in MM_HIMETRIC mode.
|
||
*
|
||
* LPOBJ lpobj - Pointer to the object whose native data will be adjusted
|
||
*
|
||
* CUSTOMIZATION: Server Demo specific, although you may need a function like
|
||
* this if you keep track of the size of an object, and an
|
||
* object handler needs to know the object's size in
|
||
* HiMetric units.
|
||
*
|
||
*
|
||
*/
|
||
VOID SetHiMetricFields (LPOBJ lpobj)
|
||
{
|
||
POINT pt;
|
||
|
||
pt.x = lpobj->native.nWidth;
|
||
pt.y = lpobj->native.nHeight;
|
||
DeviceToHiMetric ( &pt);
|
||
lpobj->native.nHiMetricWidth = pt.x;
|
||
lpobj->native.nHiMetricHeight = pt.y;
|
||
}
|
||
|
||
|
||
|
||
/* SkipBlanks
|
||
* ----------
|
||
*
|
||
* LPSTR *plpsz - Pointer to a pointer to a character
|
||
*
|
||
* Increment *plpsz past any blanks in the character string.
|
||
* This function is used in ProcessCmdLine.
|
||
*
|
||
*/
|
||
static VOID SkipBlanks (LPSTR *plpsz)
|
||
{
|
||
while (**plpsz && **plpsz == ' ')
|
||
(*plpsz)++;
|
||
}
|
||
|
||
|
||
|
||
/* UpdateObjMenus
|
||
* ---------------
|
||
*
|
||
* Grey or Ungrey menu items depending on the existence of at least one
|
||
* object in the document.
|
||
*
|
||
* CUSTOMIZATION: Server Demo specific
|
||
*
|
||
*/
|
||
static VOID UpdateObjMenus (VOID)
|
||
{
|
||
static BOOL fObjMenusEnabled = TRUE;
|
||
BOOL fOneObjExists; // Does at least one object exist?
|
||
WORD wEnable;
|
||
HMENU hMenu;
|
||
|
||
fOneObjExists = (SelectedObjectWindow() != NULL);
|
||
if (fOneObjExists == fObjMenusEnabled)
|
||
{
|
||
// Nothing has changed.
|
||
return;
|
||
}
|
||
|
||
wEnable = (WORD)(fOneObjExists ? MF_ENABLED : MF_GRAYED);
|
||
|
||
hMenu = GetMenu(hwndMain);
|
||
EnableMenuItem(hMenu, menuposColor, MF_BYPOSITION | wEnable);
|
||
|
||
hMenu = GetSubMenu(GetMenu(hwndMain), menuposFile);
|
||
EnableMenuItem(hMenu, IDM_SAVE, MF_BYCOMMAND | wEnable);
|
||
EnableMenuItem(hMenu, IDM_SAVEAS, MF_BYCOMMAND | wEnable);
|
||
|
||
hMenu = GetSubMenu(GetMenu(hwndMain), menuposEdit);
|
||
EnableMenuItem(hMenu, IDM_CUT, MF_BYCOMMAND | wEnable);
|
||
EnableMenuItem(hMenu, IDM_COPY, MF_BYCOMMAND | wEnable);
|
||
EnableMenuItem(hMenu, IDM_DELETE, MF_BYCOMMAND | wEnable);
|
||
|
||
hMenu = GetSubMenu(GetMenu(hwndMain), menuposObject);
|
||
EnableMenuItem(hMenu, IDM_NEXTOBJ, MF_BYCOMMAND | wEnable);
|
||
|
||
DrawMenuBar (hwndMain);
|
||
fObjMenusEnabled = fOneObjExists;
|
||
}
|
||
|
||
|
||
|
||
/* Wait
|
||
* ----
|
||
*
|
||
* Dispatch messages until the given flag is set to FALSE.
|
||
* One use of this function is to wait until a Release method is called
|
||
* after a function has returned OLE_WAIT_FOR_RELEASE.
|
||
*
|
||
* BOOL *pf - Pointer to the flag being waited on.
|
||
*
|
||
* CUSTOMIZATION: The use of OleUnblockServer is for illustration only.
|
||
* Since Server Demo does not call OleBlockServer, there
|
||
* will never be any messages in the OLE queue.
|
||
*
|
||
*/
|
||
VOID Wait (BOOL *pf)
|
||
{
|
||
MSG msg;
|
||
BOOL fMoreMsgs = FALSE;
|
||
|
||
*pf = TRUE;
|
||
while (*pf==TRUE)
|
||
{
|
||
OleUnblockServer (srvrMain.lhsrvr, &fMoreMsgs);
|
||
if (!fMoreMsgs)
|
||
// if there are no more messages in the OLE queue, go to system queue
|
||
{
|
||
if (GetMessage (&msg, NULL, 0, 0))
|
||
{
|
||
TranslateMessage (&msg);
|
||
DispatchMessage (&msg);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
static BOOL FailedUpdate(HWND hwnd)
|
||
{
|
||
|
||
return(DialogBox(hInst, "FailedUpdate", hwnd, (DLGPROC)fnFailedUpdate));
|
||
|
||
}
|
||
|
||
BOOL APIENTRY fnFailedUpdate (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||
{
|
||
|
||
switch (message)
|
||
{
|
||
case WM_COMMAND:
|
||
{
|
||
WORD wID = LOWORD(wParam);
|
||
|
||
switch (wID)
|
||
{
|
||
case IDCANCEL:
|
||
case IDD_CONTINUEEDIT:
|
||
EndDialog(hDlg, TRUE);
|
||
break;
|
||
|
||
case IDD_UPDATEEXIT:
|
||
EndDialog(hDlg, FALSE);
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
|
||
case WM_INITDIALOG:
|
||
{
|
||
CHAR szMsg[200];
|
||
|
||
szMsg[0] = '\0';
|
||
|
||
wsprintf(
|
||
szMsg,
|
||
"This %s document can only be updated when you exit %s.",
|
||
(LPSTR) szClient,
|
||
(LPSTR) szAppName
|
||
);
|
||
|
||
SetDlgItemText(hDlg, IDD_TEXT, szMsg);
|
||
return TRUE;
|
||
}
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
|
||
|