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

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: 

unix.superglobalmegacorp.com

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