mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1335 lines
33 KiB
1335 lines
33 KiB
/*
|
|
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= (OLECLIPFORMAT)RegisterClipboardFormat ("ObjectLink");
|
|
cfOwnerLink = (OLECLIPFORMAT)RegisterClipboardFormat ("OwnerLink");
|
|
cfNative = (OLECLIPFORMAT)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;
|
|
}
|
|
|
|
|
|
|
|
|