|
|
1.1 root 1: /*
2: * clidemo.c - OLE client application sample code
3: *
4: * Created by Microsoft Corporation.
5: * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
6: *
7: */
8:
9: /***************************************************************************
10: * IMPORTANT - README:
11: * OLE client applications are windows programs which use the OLE client
12: * APIs. Therefore it is imperative that you understand how these APIs
13: * operate. Most importantly it is essential that you keep in mind which
14: * procedure calls result in asynchronous states: a state where the operation
15: * is not truely complete after a return from the call.
16: *
17: * Many functions produce asynchronous states, for example, OleActivate,
18: * OleClose, OleCopyFromLink, OleCreate ... Reference your SDK manual for
19: * a complete list.
20: *
21: * So whenever you call any of these library functions keep in mind that
22: * the operation is not necessarily complete once a return is made.
23: * These operations require communications with a server application. With
24: * OLE the inter-application communication is done through DDE. In order
25: * for a DDE conversation to complete several DDE messages need to be
26: * sent and recieved by both the server and client OLE DLLs. So, the
27: * asynchronous operations will not complete until the client application
28: * enters a message dipatch loop. Therefore, it is necessary to enter
29: * a dispatch loop and wait for completion. It is not necessary to block
30: * all other operation; however, it is very important to coordinate the
31: * user activity to prevent disastrous re-entry cases.
32: *
33: * In this application I have written a macro to prevent re-entry
34: * problems. Namely: ANY_OBJECT_BUSY which prevents a user from initiating
35: * an action which will result in an asynchronous call if there is an object
36: * already in an asynchronous state.
37: *
38: * The following is brief summary of the three macros:
39: *
40: * ANY_OBJECT_BUSY: checks to see if any object in the document is busy.
41: * This prevents a new document from being saved to file if there are
42: * objects in asynchronous states.
43: *
44: * So, the problem is that we have to enter a message dispatch loop in order
45: * to let DDE messages get through so that asynchronous operations can finish.
46: * And while we are in the message dispatch loops (WaitForObject or WaitForAllObjects)
47: * we have to prevent the user from doing things that can't be done when an
48: * object(s) is busy. Yes, it is confusing , but, the end result is a super
49: * cool application that can have linked and embbeded objects!
50: ***************************************************************************/
51:
52: //*** INCLUDES ***
53:
54: #include <windows.h> //* WINDOWS
55: #include <ole.h> //* OLE structs and defines
56: #include <shellapi.h> //* Shell, drag and drop headers
57:
58: #include "demorc.h" //* header for resource file
59: #include "global.h" //* global app variables
60: #include "clidemo.h" //* app includes:
61: #include "register.h"
62: #include "stream.h"
63: #include "object.h"
64: #include "dialog.h"
65: #include "utility.h"
66:
67: //*** VARIABLES ***
68:
69: //** Global
70: HANDLE hInst;
71: BOOL fRetry = FALSE;
72: HWND hwndFrame; //* main window
73: HANDLE hAccTable; //* accelerator table
74: CHAR szFrameClass[] = "CliDemo";//* main window class name
75: CHAR szItemClass[] = "ItemClass";//* item window class name
76: CHAR szAppName[CBMESSAGEMAX];//* Application name
77: INT iObjects = 0; //* object count
78: INT iObjectNumber = 0; //* object number for object name
79: CHAR szFileName[CBPATHMAX];
1.1.1.2 ! root 80:
! 81: extern INT giXppli ;
! 82: extern INT giYppli ;
1.1 root 83: //* ClipBoard formats:
84: OLECLIPFORMAT vcfLink; //* "ObjectLink"
85: OLECLIPFORMAT vcfNative; //* "Native"
86: OLECLIPFORMAT vcfOwnerLink; //* "OwnerLink"
87:
88:
89: /***************************************************************************
90: * WinMain() - Main Windows routine
91: ***************************************************************************/
92:
1.1.1.2 ! root 93: int APIENTRY WinMain(
1.1 root 94: HANDLE hInstance,
95: HANDLE hPrevInst,
96: LPSTR lpCmdLine,
97: INT nCmdLine
98: ){
99: hInst = hInstance;
100:
101: if (!InitApplication(hInst)) //* register window classes
102: return FALSE;
103:
104: if (!InitInstance(hInst)) //* create window instance
105: return FALSE;
106:
107: OfnInit(hInst); //* setup to use <commdlg.dll>
108:
109: //* register clipboard formats
110: //* used for OLE
111: vcfLink = RegisterClipboardFormat("ObjectLink");
112: vcfNative = RegisterClipboardFormat("Native");
113: vcfOwnerLink = RegisterClipboardFormat("OwnerLink");
114:
115:
116: ShowWindow(hwndFrame, SW_SHOWNORMAL);
117: UpdateWindow(hwndFrame);
118: ProcessCmdLine(lpCmdLine);
119:
120: while (ProcessMessage(hwndFrame, hAccTable)) ;
121:
122: return FALSE;
123: }
124:
125: /***************************************************************************
126: * InitApplication()
127: *
128: * registers the window classes used by the application.
129: *
130: * Returns BOOL: - TRUE if successful.
131: ***************************************************************************/
132:
133: static BOOL InitApplication( //* ENTRY:
134: HANDLE hInst //* instance handle
135: ){ //* LOCAL:
136: WNDCLASS wc; //* temp wind-class structure
137:
138: wc.style = NULL;
139: wc.lpfnWndProc = (WNDPROC)FrameWndProc;
140: wc.cbClsExtra = 0;
141: wc.cbWndExtra = 0;
142: wc.hInstance = hInst;
143: wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(ID_APPLICATION));
144: wc.hCursor = LoadCursor(NULL, IDC_ARROW);
145: wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
146: wc.lpszMenuName = MAKEINTRESOURCE(ID_APPLICATION);
147: wc.lpszClassName = szFrameClass;
148:
149: if (!RegisterClass(&wc))
150: return FALSE;
151: //* application item class
152: wc.style = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW;
153: wc.lpfnWndProc = (WNDPROC)ItemWndProc;
154: wc.hIcon = NULL;
155: wc.cbWndExtra = sizeof(APPITEMPTR);
156: wc.lpszMenuName = NULL;
157: wc.lpszClassName = szItemClass;
158:
159: if (!RegisterClass(&wc))
160: return FALSE;
161:
162: return TRUE;
163:
164: }
165:
166: /***************************************************************************
167: * InitInstance()
168: *
169: * create the main application window.
170: *
171: * Returns BOOL: - TRUE if successful else FALSE.
172: ***************************************************************************/
173:
174: static BOOL InitInstance( //* ENTRY:
175: HANDLE hInst //* instance handel
176: ){
1.1.1.2 ! root 177: HDC hDC ;
1.1 root 178:
179: hAccTable = LoadAccelerators(hInst, MAKEINTRESOURCE(ID_APPLICATION));
180:
181: if (!(hwndFrame =
182: CreateWindow(
183: szFrameClass, "",
184: WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
185: CW_USEDEFAULT, CW_USEDEFAULT,
186: CW_USEDEFAULT, CW_USEDEFAULT,
187: NULL,
188: NULL,
189: hInst,
190: NULL
191: )))
192: return FALSE; //* ERROR return
193:
194: LoadString(hInst, IDS_APPNAME, szAppName, CBMESSAGEMAX);
195: DragAcceptFiles(hwndFrame, TRUE); //* allow dragged and dropped files
196:
1.1.1.2 ! root 197: hDC = GetDC (NULL); // Get the hDC of the desktop window
! 198: giXppli = GetDeviceCaps (hDC, LOGPIXELSX);
! 199: giYppli = GetDeviceCaps (hDC, LOGPIXELSY);
! 200: ReleaseDC (NULL, hDC);
! 201:
! 202:
1.1 root 203:
204: return TRUE; //* SUCCESS return
205:
206: }
207:
208: /***************************************************************************
209: * ProcessCmdLine()
210: *
211: * process command line getting any command arguments.
212: ***************************************************************************/
213:
214: VOID ProcessCmdLine(LPSTR lpCmdLine)
215: { //* LOCAL:
216: OFSTRUCT ofs;
217:
218:
219: if (*lpCmdLine)
220: { //* look for file extension
221: LPSTR lpstrExt = lpCmdLine; //* pointer to file extension
222:
223: while (*lpstrExt && *lpstrExt != '.')
224: lpstrExt = AnsiNext(lpstrExt);
225:
226: lstrcpy(szFileName, lpCmdLine);
227: if (!(*lpstrExt)) //* append default extension
228: {
229: lstrcat(szFileName,".");
230: lstrcat(szFileName,szDefExtension);
231: }
232: //* get the files fully
233: OpenFile(szFileName, &ofs, OF_PARSE);//* qualified name
234: lstrcpy(szFileName, ofs.szPathName);
235: }
236: else
237: *szFileName = NULL;
238: //* pass filename to main winproc
239: SendMessage(hwndFrame,WM_INIT,NULL,(LONG)NULL);
240:
241: }
242:
243:
244: /***************************************************************************
245: * FrameWndProc()
246: *
247: * Message handler for the application frame window.
248: *
249: * Returns long - Variable, depends on message.
250: ***************************************************************************/
251:
252: LONG APIENTRY FrameWndProc( //* ENTRY:
253: HWND hwnd, //* standard wind-proc parameters
254: UINT msg,
255: DWORD wParam,
256: LONG lParam
257: ){ //* LOCAL:
258: //* ^ Document file name
259: static LHCLIENTDOC lhcDoc; //* Document Handle
260: static LPOLECLIENT lpClient; //* pointer to client
261: static LPAPPSTREAM lpStream; //* pointer to stream vtbl
262: APPITEMPTR pItem; //* application item pointer
263:
264: switch (msg)
265: {
266: case WM_INIT: //* user defined message
267: if (!InitAsOleClient(hInst, hwnd, szFileName, &lhcDoc, &lpClient, &lpStream))
268: DestroyWindow(hwnd);
269: break;
270: //* the following three messages are
271: //* used to avoid problems with OLE
272: //* see the comment in object.h
273: case WM_DELETE: //* user defined message
274: pItem = (APPITEMPTR) wParam; //* delete object
275: WaitForObject(pItem);
276: ObjDelete(pItem,OLE_OBJ_DELETE);
277: if (lParam)
278: cOleWait--;
279: break;
280:
281: case WM_ERROR: //* user defined message
282: ErrorMessage(wParam); //* display error message
283: break;
284:
285: case WM_RETRY: //* user defined message
286: RetryMessage((APPITEMPTR)wParam, RD_RETRY | RD_CANCEL);
287: break;
288:
289: case WM_INITMENU:
290: UpdateMenu((HMENU)wParam);
291: break;
292:
293: case WM_COMMAND:
294: {
295: WORD wID = LOWORD(wParam);
296:
297: pItem = GetTopItem();
298:
299: switch (wID)
300: {
301: case IDM_NEW:
302: ANY_OBJECT_BUSY;
303: NewFile(szFileName,&lhcDoc,lpStream);
304: break;
305:
306: case IDM_OPEN:
307: ANY_OBJECT_BUSY;
308: MyOpenFile(szFileName,&lhcDoc,lpClient,lpStream);
309: break;
310:
311: case IDM_SAVE:
312: ANY_OBJECT_BUSY;
313: SaveFile(szFileName,lhcDoc,lpStream);
314: break;
315:
316: case IDM_SAVEAS:
317: ANY_OBJECT_BUSY;
318: SaveasFile(szFileName,lhcDoc,lpStream);
319: break;
320:
321: case IDM_ABOUT:
322: AboutBox();
323: break;
324:
325: case IDM_INSERT:
326: ANY_OBJECT_BUSY;
327: ObjInsert(lhcDoc, lpClient);
328: break;
329:
330: case IDM_INSERTFILE:
331: ANY_OBJECT_BUSY;
332: ObjCreateFromTemplate(lhcDoc,lpClient);
333: break;
334:
335: case IDM_PASTE:
336: case IDM_PASTELINK:
337: ANY_OBJECT_BUSY;
338: ObjPaste(wID == IDM_PASTE,lhcDoc,lpClient);
339: break;
340:
341: case IDM_LINKS:
342: ANY_OBJECT_BUSY;
343: pItem = GetTopItem();
344: LinkProperties();
345: break;
346:
347: case IDM_EXIT:
348: ANY_OBJECT_BUSY;
349: SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
350: break;
351:
352: case IDM_COPY:
353: case IDM_CUT:
354: ANY_OBJECT_BUSY;
355:
356: if (!ObjCopy(pItem))
357: {
358: ErrorMessage((wParam == IDM_CUT) ?
359: E_CLIPBOARD_CUT_FAILED : E_CLIPBOARD_COPY_FAILED);
360: break;
361: }
362:
363: if (wParam == IDM_COPY)
364: break;
365:
366: case IDM_CLEAR: //* CUT falls through to clear
367: ANY_OBJECT_BUSY;
368: ClearItem(pItem);
369: break;
370:
371: case IDM_CLEARALL:
372: ANY_OBJECT_BUSY;
373: ClearAll(lhcDoc,OLE_OBJ_DELETE);
374: Dirty(DOC_DIRTY);
375: break;
376:
377: default:
378: if( (wParam >= IDM_VERBMIN) && (wParam <= IDM_VERBMAX) )
379: {
380: ANY_OBJECT_BUSY;
381: ExecuteVerb(wParam - IDM_VERBMIN,pItem);
382: break;
383: }
384: return DefWindowProc(hwnd, msg, wParam, lParam);
385: }
386: break;
387: }
388:
389: case WM_DROPFILES:
390: ANY_OBJECT_BUSY;
391: ObjCreateWrap((HANDLE)wParam, lhcDoc, lpClient);
392: break;
393:
394: case WM_CLOSE:
395: ANY_OBJECT_BUSY;
396: if (!SaveAsNeeded(szFileName, lhcDoc, lpStream))
397: break;
398: DeregDoc(lhcDoc);
399: DestroyWindow(hwnd);
400: break;
401:
402: case WM_DESTROY:
403: EndStream(lpStream);
404: EndClient(lpClient);
405: PostQuitMessage(0);
406: break;
407:
408: case WM_QUERYENDSESSION: //* don't let windows terminate
409: return (QueryEndSession(szFileName,lhcDoc, lpStream));
410:
411: default:
412: return DefWindowProc(hwnd, msg, wParam, lParam);
413: }
414: return 0L;
415:
416: }
417:
418: /***************************************************************************
419: * InitAsOleClient()
420: *
421: * Initiates the creation of stream and client vtbls. These vtbls are very
422: * important for the proper operation of this application. The stream vtbl
423: * lets the OLE librarys know where the location of the stream I/O routines
424: * reside. The stream routines are used by OleLoadFromStream and the like.
425: * The client vtbl is used to hold the pointer to the CallBack function.
426: * IMPORTANT: both the client and the stream structures have pointers to
427: * vtbls which have the pointers to the functions. Therefore, it is
428: * necessary to allocate space for the vtbl and the client structure
429: * which has the pointer to the vtbl.
430: **************************************************************************/
431:
432: static BOOL InitAsOleClient( //* ENTRY:
433: HANDLE hInstance, //* applicaion instance handle
434: HWND hwnd, //* main window handle
435: PSTR pFileName, //* document file name
436: LHCLIENTDOC *lhcDoc, //* pointer to document Handle
437: LPOLECLIENT *lpClient, //* pointer to client pointer
438: LPAPPSTREAM *lpStream //* pointer to APPSTREAM pointer
439: ){
440: //* initiate client vtbl creation
441: if (!(*lpClient = InitClient(hInstance)))
442: {
443: SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
444: return FALSE; //* ERROR return
445: }
446: //* initiate stream vtbl creation
447: if (!(*lpStream = InitStream(hInstance)))
448: {
449: SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
450: return FALSE; //* ERROR return
451: }
452:
453: if (*pFileName && RegDoc(pFileName,lhcDoc)
454: && LoadFile(pFileName,*lhcDoc,*lpClient,*lpStream))
455: {
456: SetTitle(pFileName);
457: return TRUE; //* SUCCESS return
458: }
459:
460: NewFile(pFileName, lhcDoc, *lpStream);
461: return TRUE; //* SUCCESS return
462:
463: } //* SUCCESS return
464:
465: /****************************************************************************
466: * InitClient()
467: *
468: * Initialize the OLE client structure, create and fill the OLECLIENTVTBL
469: * structure.
470: *
471: * Returns LPOLECLIENT - if successful a pointer to a client structure
472: * , otherwise NULL.
473: ***************************************************************************/
474:
475: static LPOLECLIENT InitClient( //* ENTRY:
476: HANDLE hInstance //* application instance handle
477: ){ //* LOCAL:
478: LPOLECLIENT lpClient=NULL; //* pointer to client struct
479: //* Allocate vtbls
480: if (!(lpClient = (LPOLECLIENT)GlobalLock(
481: GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(OLECLIENT))
482: )))
483: goto Error; //* ERROR jump
484:
485: if (!(lpClient->lpvtbl = (LPOLECLIENTVTBL)GlobalLock(
486: GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(OLECLIENTVTBL))
487: )))
488: goto Error; //* ERROR jump
489: //* set the CALLBACK function
490: //* pointer
491: lpClient->lpvtbl->CallBack = CallBack;
492:
493: return lpClient; //* SUCCESS return
494:
495: Error: //* ERROR Tag
496:
497: ErrorMessage(E_FAILED_TO_ALLOC);
498: EndClient(lpClient); //* free any allocated space
499:
500: return NULL; //* ERROR return
501:
502: }
503:
504: /****************************************************************************
505: * InitStream()
506: *
507: * Create and fill the STREAMVTBL. Create a stream structure and initialize
508: * pointer to stream vtbl.
509: *
510: * Returns LPAPPSTREAM - if successful a pointer to a stream structure
511: * , otherwise NULL .
512: ***************************************************************************/
513:
514: static LPAPPSTREAM InitStream( //* ENTRY:
515: HANDLE hInstance //* handle to application instance
516: ){ //* LOCAL:
517: LPAPPSTREAM lpStream = NULL; //* pointer to stream structure
518:
519: if (!(lpStream = (LPAPPSTREAM)GlobalLock(
520: GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(APPSTREAM))
521: )))
522: goto Error; //* ERROR jump
523:
524: if (!(lpStream->olestream.lpstbl = (LPOLESTREAMVTBL)GlobalLock(
525: GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(OLESTREAMVTBL))
526: )))
527: goto Error; //* ERROR jump
528:
529: //* set stream func. pointers
530: lpStream->olestream.lpstbl->Get = (DWORD ( CALLBACK *)(LPOLESTREAM, VOID FAR *, DWORD)) ReadStream;
531: lpStream->olestream.lpstbl->Put = (DWORD ( CALLBACK *)(LPOLESTREAM, OLE_CONST VOID FAR *, DWORD)) WriteStream;
532:
533: return lpStream; //* SUCCESS return
534:
535: Error: //* ERROR Tag
536:
537: ErrorMessage(E_FAILED_TO_ALLOC);
538: EndStream(lpStream);
539:
540: return NULL; //* ERROR return
541:
542: }
543:
544: /***************************************************************************
545: * UpdateMenu()
546: *
547: * Enabling or disable menuitems based upon program state.
548: ***************************************************************************/
549:
550: static VOID UpdateMenu( //* ENTRY:
551: HMENU hMenu //* menu handle to updated
552: ){ //* LOCAL:
553: INT mf; //* generic menu flag
554: APPITEMPTR paItem; //* app item pointer
555: HMENU hSub;
556: //* there must be at least on object
557: //* for the following to be enabled
558:
559: paItem = GetTopItem() ;
560:
561: mf = (paItem ? MF_ENABLED : MF_GRAYED);
562: EnableMenuItem(hMenu, IDM_CUT, mf); //* i.e. Cut,Copy,Clear,Clearall...
563: EnableMenuItem(hMenu, IDM_COPY, mf);
564: EnableMenuItem(hMenu, IDM_CLEAR, mf);
565: EnableMenuItem(hMenu, IDM_CLEARALL, mf);
566: //* enable links option only if there
567: //* is at least one linked object
568: EnableMenuItem(hMenu, IDM_LINKS, MF_GRAYED);
569: for (; paItem; paItem = GetNextItem(paItem))
570: {
571: if (paItem->otObject == OT_LINK)
572: {
573: EnableMenuItem(hMenu, IDM_LINKS, MF_ENABLED);
574: break;
575: }
576: }
577:
578: if (hSub = GetSubMenu(hMenu,POS_EDITMENU))
579: UpdateObjectMenuItem(hSub);
580:
581: if (OleQueryCreateFromClip(STDFILEEDITING, olerender_draw, 0) == OLE_OK)
582: EnableMenuItem(hMenu, IDM_PASTE, MF_ENABLED);
583: else if (OleQueryCreateFromClip(STATICP, olerender_draw, 0) == OLE_OK)
584: EnableMenuItem(hMenu, IDM_PASTE, MF_ENABLED);
585: else
586: EnableMenuItem(hMenu, IDM_PASTE, MF_GRAYED);
587:
588: if (OleQueryLinkFromClip(STDFILEEDITING, olerender_draw, 0) == OLE_OK)
589: EnableMenuItem(hMenu, IDM_PASTELINK, MF_ENABLED);
590: else
591: EnableMenuItem(hMenu, IDM_PASTELINK, MF_GRAYED);
592:
593: }
594:
595: /***************************************************************************
596: * NewFile()
597: *
598: * Save the present document and open a new blank one.
599: ***************************************************************************/
600:
601: static VOID NewFile( //* ENTRY:
602: PSTR pFileName, //* open file name
603: LHCLIENTDOC *lhcptrDoc, //* pointer to client doc. handle
604: LPAPPSTREAM lpStream //* pointer to stream structure
605: ){ //* LOCAL:
606: static CHAR szUntitled[CBMESSAGEMAX] = "";//* "(Untitled)" string
607: LHCLIENTDOC lhcDocNew; //* handle for new doc.
608:
609: if (!(*szUntitled))
610: LoadString(hInst, IDS_UNTITLED, (LPSTR)szUntitled, CBMESSAGEMAX);
611:
612: if (SaveAsNeeded(pFileName, *lhcptrDoc, lpStream))
613: { //* try to register new document
614: if (!RegDoc(szUntitled, &lhcDocNew))
615: return; //* before deregistring the old one
616: DeregDoc(*lhcptrDoc);
617: *lhcptrDoc = lhcDocNew;
618: Dirty(DOC_CLEAN); //* new document is clean
619: lstrcpy(pFileName,szUntitled);
620: SetTitle(pFileName);
621: iObjectNumber = 0;
622: }
623:
624: }
625:
626: /***************************************************************************
627: * MyOpenFile()
628: *
629: * Open a file and load it. Notice that the new file is loaded before
630: * the old is removed. This is done to assure a succesful file load
631: * before removing an existing document.
632: ***************************************************************************/
633:
634: static VOID MyOpenFile( //* ENTRY:
635: PSTR pFileName, //* open file name
636: LHCLIENTDOC *lhcptrDoc, //* pointer to document handle
637: LPOLECLIENT lpClient, //* pointer to client structure
638: LPAPPSTREAM lpStream //* pointer to stream structure
639: ){ //* LOCAL:
640: CHAR szNewFile[CBPATHMAX];//* new file name buffer
641: LHCLIENTDOC lhcDocNew; //* handle of new document
642: APPITEMPTR pItem; //* hold top item
643:
644: if (SaveAsNeeded(pFileName, *lhcptrDoc, lpStream))
645: {
646: *szNewFile = NULL;
647:
648: if (!OfnGetName(hwndFrame, szNewFile, IDM_OPEN))
649: return; //* ERROR return
650:
651: if (!RegDoc(szNewFile,&lhcDocNew))
652: return; //* ERROR return
653:
654: pItem = GetTopItem();
655: ShowDoc(*lhcptrDoc,0); //* make old doc objects hidden.
656: //* try to load the new file before
657: if (!LoadFile(szNewFile, lhcDocNew, lpClient, lpStream))
658: { //* before removing the old.
659: DeregDoc(lhcDocNew); //* restore old document if new
660: SetTopItem(pItem); //* file did not load
661: ShowDoc(*lhcptrDoc,1);
662: return; //* ERROR return
663: }
664:
665: DeregDoc(*lhcptrDoc); //* deregister old document
666: *lhcptrDoc = lhcDocNew;
667: lstrcpy(pFileName,szNewFile);
668: SetTitle(pFileName); //* set new title
669: Dirty(DOC_CLEAN);
670: }
671:
672: } //* SUCCESS return
673:
674: /***************************************************************************
675: * SaveasFile()
676: *
677: * Prompt the user for a new file name. Write the document to the new
678: * filename.
679: ***************************************************************************/
680:
681: static VOID SaveasFile( //* ENTRY:
682: PSTR pFileName, //* old filename
683: LHCLIENTDOC lhcDoc, //* document handle
684: LPAPPSTREAM lpStream //* pointer to stream structure
685: ){
686: CHAR szNewFile[CBPATHMAX];//* new file name
687:
688: *szNewFile = NULL; //* prompt user for new file name
689: if (!OfnGetName(hwndFrame, szNewFile, IDM_SAVEAS))
690: return; //* ERROR return
691: //* rename document
692: if (!SaveFile(szNewFile, lhcDoc, lpStream))
693: return;
694:
695: if (Error(OleRenameClientDoc(lhcDoc, szNewFile)))
696: {
697: ErrorMessage(W_FAILED_TO_NOTIFY);
698: return; //* ERROR return
699: }
700:
701: lstrcpy(pFileName,szNewFile);
702: SetTitle(pFileName);
703:
704: } //* SUCCESS return
705:
706: /***************************************************************************
707: * SaveFile()
708: *
709: * Save a compound document file. If the file is untitled, ask the user
710: * for a name and save the document to that file.
711: ***************************************************************************/
712:
713: static BOOL SaveFile( //* ENTRY:
714: PSTR pFileName, //* file to save document to
715: LHCLIENTDOC lhcDoc, //* OLE document handle
716: LPAPPSTREAM lpStream //* pointer to app. stream struct
717: ){ //* LOCAL:
718: CHAR szNewFile[CBPATHMAX];//* New file name strings
719: CHAR szOemFileName[2*CBPATHMAX];
720: static CHAR szUntitled[CBMESSAGEMAX] = "";
721: int fh; //* file handle
722:
723: *szNewFile = NULL;
724: if (!(*szUntitled))
725: LoadString(hInst, IDS_UNTITLED, (LPSTR)szUntitled, CBMESSAGEMAX);
726:
727: if (!lstrcmp(szUntitled, pFileName))//* get filename for the untitled case
728: {
729: if (!OfnGetName(hwndFrame, szNewFile, IDM_SAVEAS))
730: return FALSE; //* CANCEL return
731: lstrcpy(pFileName,szNewFile);
732: SetTitle(pFileName);
733: }
734:
735: AnsiToOem(pFileName, szOemFileName);
736: if ((fh = _lcreat((LPSTR)szOemFileName, 0)) <= 0)
737: {
738: ErrorMessage(E_INVALID_FILENAME);
739: return FALSE; //* ERROR return
740: }
741:
742: lpStream->fh = fh;
743: //* save file on disk
744: if (!WriteToFile(lpStream))
745: {
746: _lclose(fh);
747: ErrorMessage(E_FAILED_TO_SAVE_FILE);
748: return FALSE; //* ERROR return
749: }
750: _lclose(fh);
751:
752: if (Error(OleSavedClientDoc(lhcDoc)))
753: {
754: ErrorMessage(W_FAILED_TO_NOTIFY);
755: return FALSE; //* ERROR return
756: }
757:
758: Dirty(DOC_CLEAN);
759: return TRUE; //* SUCCESS return
760:
761: }
762:
763: /***************************************************************************
764: * LoadFile()
765: *
766: * Load a document file from disk.
767: ***************************************************************************/
768:
769: static BOOL LoadFile( //* ENTRY:
770: PSTR pFileName, //* file name
771: LHCLIENTDOC lhcDoc, //* document handle
772: LPOLECLIENT lpClient, //* pointer to client structure
773: LPAPPSTREAM lpStream //* pointer to stream structure
774: ){ //* LOCAL:
775: //* OEM file name
776: CHAR szOemFileName[2*CBPATHMAX];
777: int fh; //* file handle
778: INT iObjectNumberHold; //* hold object number
779:
780: AnsiToOem(pFileName, szOemFileName);
781: if ((fh = _lopen(szOemFileName, OF_READ | OF_SHARE_DENY_WRITE)) == -1)
782: {
783: ErrorMessage(E_FAILED_TO_READ_FILE);
784: return FALSE; //* ERROR return
785: }
786:
787: lpStream->fh = fh;
788:
789: iObjectNumberHold = iObjectNumber; //* save object number so it can
790: iObjectNumber = 0; //* be restored if read from file
791: //* fails
792: if (!ReadFromFile(lpStream, lhcDoc, lpClient))
793: {
794: _lclose(fh);
795: ErrorMessage(E_FAILED_TO_READ_FILE);
796: iObjectNumber = iObjectNumberHold;
797: return FALSE; //* ERROR return
798: }
799: return TRUE; //* SUCCESS return
800:
801: }
802:
803: /***************************************************************************
804: * RegDoc()
805: *
806: * Register the client document with the OLE library.
807: **************************************************************************/
808:
809: static BOOL RegDoc( //* ENTRY:
810: PSTR pFileName, //* file name
811: LHCLIENTDOC *lhcptrDoc //* pointer to client document handle
812: ){
813:
814: if (Error(OleRegisterClientDoc(szAppName, (LPSTR)pFileName, 0L, lhcptrDoc)))
815: {
816: ErrorMessage(W_FAILED_TO_NOTIFY);
817: return FALSE; //* ERROR return
818: }
819: return TRUE; //* SUCCESS return
820:
821: }
822:
823: /****************************************************************************
824: * DeregDoc()
825: *
826: * This function initiates the removal of all OLE objects from the
827: * current document and deregisters the document with the OLE library.
828: ***************************************************************************/
829:
830: static VOID DeregDoc( //* ENTRY:
831: LHCLIENTDOC lhcDoc //* client document handle
832: ){
833:
834: if (lhcDoc)
835: { //* release all OLE objects
836: ClearAll(lhcDoc,OLE_OBJ_RELEASE); //* and remove them from the screen
837: WaitForAllObjects();
838: if (Error(OleRevokeClientDoc(lhcDoc)))
839: ErrorMessage(W_FAILED_TO_NOTIFY);
840: }
841:
842: } //* SUCCESS return
843:
844: /***************************************************************************
845: * ClearAll()
846: *
847: * This function will destroy all of the item windows in the current
848: * document and delete all OLE objects. The loop is basically an enum
849: * of all child windows.
850: **************************************************************************/
851:
852: static VOID ClearAll( //* ENTRY:
853: LHCLIENTDOC lhcDoc, //* application document handle
854: BOOL fDelete //* Delete / Release
855: ){ //* LOCAL:
856: APPITEMPTR pItemNext; //* working handles
857: APPITEMPTR pItem; //* pointer to application item
858:
859: pItem = GetTopItem();
860:
861: while (pItem)
862: {
863: pItemNext = GetNextItem(pItem);
864: if (pItem->lhcDoc == lhcDoc)
865: ObjDelete(pItem, fDelete);
866: pItem = pItemNext;
867: }
868:
869: }
870: //* SUCCESS return
871: /***************************************************************************
872: * ClearItem()
873: *
874: * This function will destroy an item window, and make the
875: * next window active.
876: **************************************************************************/
877:
878: VOID FAR ClearItem( //* ENTRY:
879: APPITEMPTR pItem //* application item pointer
880: ){
881:
882: pItem->fVisible = FALSE;
883: SetTopItem(GetNextActiveItem());
884: ObjDelete(pItem, OLE_OBJ_DELETE);
885: Dirty(DOC_DIRTY);
886:
887: }
888:
889: /****************************************************************************
890: * SaveAsNeeded()
891: *
892: * This function will have the file saved if and only
893: * if the document has been modified. If the fDirty flag has
894: * been set to TRUE, then the document needs to be saved.
895: *
896: * Returns: BOOL - TRUE if document doesn't need saving or if the
897: * document has been saved successfully.
898: ***************************************************************************/
899:
900: static BOOL SaveAsNeeded( //* ENTRY:
901: PSTR pFileName, //* file to save
902: LHCLIENTDOC lhcDoc, //* OLE doc handle
903: LPAPPSTREAM lpStream //* pointer to OLE stream vtbl ...
904: ){ //* LOCAL:
905: CHAR sz[CBMESSAGEMAX]; //* work strings
906: CHAR sz2[CBMESSAGEMAX + CBPATHMAX];
907:
908: if (Dirty(DOC_QUERY)) //* if doc is clean don't bother
909: {
910:
911: LoadString(hInst, IDS_MAYBESAVE, sz, CBMESSAGEMAX);
912: wsprintf(sz2, sz, (LPSTR)pFileName );
913:
914: switch (MessageBox(hwndFrame, sz2, szAppName, MB_YESNOCANCEL | MB_ICONQUESTION))
915: {
916:
917: case IDCANCEL:
918: return FALSE; //* CANCEL return
919:
920: case IDYES:
921: return (SaveFile(pFileName,lhcDoc,lpStream));
922:
923: default:
924: break;
925: }
926: }
927: return TRUE; //* SUCCESS return
928:
929: }
930:
931: /****************************************************************************
932: * SetTitle()
933: *
934: * Set the window caption to the current file name. If szFileName is
935: * NULL, the caption will be set to "(Untitled)".
936: ***************************************************************************/
937:
938: static VOID SetTitle( //* ENTRY:
939: PSTR pFileName //* file name
940: ){ //* LOCAL
941: //* window title string
942: CHAR szTitle[CBMESSAGEMAX + CBPATHMAX];
943:
944: wsprintf(szTitle, "%s - %s", (LPSTR)szAppName, (LPSTR)pFileName);
945: SetWindowText(hwndFrame, szTitle);
946:
947: }
948:
949: /***************************************************************************
950: * EndClient()
951: *
952: * Perform cleanup prior to app termination. The OLECLIENT
953: * memory blocks and procedure instance thunks freed.
954: **************************************************************************/
955:
956: static VOID EndStream( //* ENTRY:
957: LPAPPSTREAM lpStream //* pointer to stream structure
958: ){ //* LOCAL:
959: HANDLE hGeneric; //* temp handle
960:
961: if (lpStream) //* is there a STREAM struct?
962: {
963: if (lpStream->olestream.lpstbl)
964: {
965: FreeProcInstance((FARPROC)lpStream->olestream.lpstbl->Get);
966: FreeProcInstance((FARPROC)lpStream->olestream.lpstbl->Put);
967: hGeneric = GlobalHandle((LPSTR)lpStream->olestream.lpstbl);
968: GlobalUnlock(hGeneric);
969: GlobalFree(hGeneric);
970: }
971: hGeneric = GlobalHandle((LPSTR)lpStream);
972: GlobalUnlock(hGeneric);
973: GlobalFree(hGeneric);
974: }
975:
976: } //* SUCCESS return
977:
978: /***************************************************************************
979: * EndClient()
980: *
981: * Perform cleanup prior to app termination. The OLECLIENT
982: * memory blocks and procedure instance thunks are freed.
983: **************************************************************************/
984:
985: static VOID EndClient( //* ENTRY:
986: LPOLECLIENT lpClient //* pointer to client structure
987: ){ //* LOCAL:
988: HANDLE hGeneric; //* temp handle
989:
990: if (lpClient) //* is there a client structure
991: {
992: if (lpClient->lpvtbl)
993: {
994: FreeProcInstance(lpClient->lpvtbl->CallBack);
995: hGeneric = GlobalHandle((LPSTR)lpClient->lpvtbl);
996: GlobalUnlock(hGeneric);
997: GlobalFree(hGeneric);
998: }
999: hGeneric = GlobalHandle((LPSTR)lpClient);
1000: GlobalUnlock(hGeneric);
1001: GlobalFree(hGeneric);
1002: }
1003:
1004: } //* SUCCESS return
1005:
1006: /****************************************************************************
1007: * QueryEndSession()
1008: ***************************************************************************/
1009:
1010: static LONG QueryEndSession( //* ENTRY:
1011: PSTR pFileName, //* document name
1012: LHCLIENTDOC lhcDoc, //* client document handle
1013: LPAPPSTREAM lpStream //* application stream pointer
1014: ){ //* LOCAL:
1015: APPITEMPTR pItem; //* application item pointer
1016:
1017:
1018: for (pItem = GetTopItem(); pItem; pItem = GetNextItem(pItem))
1019: if (OleQueryOpen(pItem->lpObject) == OLE_OK)
1020: {
1021: MessageBox(hwndFrame,"Exit CliDemo before closing Windows",
1022: szAppName, MB_OK | MB_ICONSTOP);
1023: return 0L;
1024: }
1025:
1026: if (!SaveAsNeeded(pFileName, lhcDoc, lpStream))
1027: return 0L;
1028: DeregDoc(lhcDoc);
1029: return 1L;
1030:
1031: }
1032:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.