Annotation of mstools/samples/ole/clidemo/clidemo.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.