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

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:  ***************************************************************************/
1.1.1.2   root       92: int APIENTRY WinMain(
1.1.1.3 ! root       93:    HINSTANCE hInstance,
        !            94:    HINSTANCE hPrevInst,
1.1       root       95:    LPSTR  lpCmdLine,
                     96:    INT    nCmdLine
                     97: ){
                     98:     hInst = hInstance;
                     99: 
                    100:     if (!InitApplication(hInst))   //* register window classes
                    101:       return FALSE;
                    102: 
                    103:     if (!InitInstance(hInst))          //* create window instance
                    104:         return FALSE;
                    105: 
                    106:     OfnInit(hInst);                    //* setup to use <commdlg.dll>
                    107: 
                    108:                                        //* register clipboard formats
                    109:                                        //* used for OLE
                    110:     vcfLink      = RegisterClipboardFormat("ObjectLink");
                    111:     vcfNative    = RegisterClipboardFormat("Native");
                    112:     vcfOwnerLink = RegisterClipboardFormat("OwnerLink");
                    113:     
                    114: 
                    115:     ShowWindow(hwndFrame, SW_SHOWNORMAL);
                    116:     UpdateWindow(hwndFrame);
                    117:     ProcessCmdLine(lpCmdLine);
                    118: 
                    119:     while (ProcessMessage(hwndFrame, hAccTable)) ;
                    120: 
                    121:     return FALSE;
                    122: }
                    123: 
                    124: /***************************************************************************
                    125:  * InitApplication() 
                    126:  *
                    127:  * registers the window classes used by the application.
                    128:  *
                    129:  * Returns BOOL:      - TRUE if successful.
                    130:  ***************************************************************************/
                    131: 
                    132: static BOOL InitApplication(           //* ENTRY:
                    133:    HANDLE         hInst                //* instance handle
                    134: ){                                     //* LOCAL:
                    135:    WNDCLASS       wc;                  //* temp wind-class structure
                    136: 
1.1.1.3 ! root      137:    wc.style          = 0;
1.1       root      138:    wc.lpfnWndProc    = (WNDPROC)FrameWndProc;
                    139:    wc.cbClsExtra     = 0;
                    140:    wc.cbWndExtra     = 0;
                    141:    wc.hInstance      = hInst;
                    142:    wc.hIcon          = LoadIcon(hInst, MAKEINTRESOURCE(ID_APPLICATION));
                    143:    wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
                    144:    wc.hbrBackground  = (HBRUSH)(COLOR_APPWORKSPACE + 1);
                    145:    wc.lpszMenuName   = MAKEINTRESOURCE(ID_APPLICATION);
                    146:    wc.lpszClassName  = szFrameClass;
                    147: 
                    148:    if (!RegisterClass(&wc))
                    149:       return FALSE;
                    150:                                        //* application item class
                    151:    wc.style          = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW;
                    152:    wc.lpfnWndProc    = (WNDPROC)ItemWndProc;
                    153:    wc.hIcon          = NULL;
                    154:    wc.cbWndExtra     = sizeof(APPITEMPTR);
                    155:    wc.lpszMenuName   = NULL;
                    156:    wc.lpszClassName  = szItemClass;
                    157: 
                    158:    if (!RegisterClass(&wc))
                    159:       return FALSE;
                    160: 
                    161:    return TRUE;
                    162: 
                    163: }
                    164: 
                    165: /***************************************************************************
                    166:  * InitInstance()
                    167:  *
                    168:  * create the main application window.
                    169:  *
                    170:  * Returns BOOL:      - TRUE if successful else FALSE.
                    171:  ***************************************************************************/
                    172: 
                    173: static BOOL InitInstance(              //* ENTRY:
                    174:    HANDLE         hInst                //* instance handel
                    175: ){
1.1.1.2   root      176:        HDC hDC ;
1.1       root      177:    
                    178:    hAccTable = LoadAccelerators(hInst, MAKEINTRESOURCE(ID_APPLICATION));
                    179: 
                    180:    if (!(hwndFrame = 
                    181:       CreateWindow(
                    182:          szFrameClass, "",
                    183:          WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
                    184:          CW_USEDEFAULT, CW_USEDEFAULT,   
                    185:          CW_USEDEFAULT, CW_USEDEFAULT,   
                    186:          NULL, 
                    187:          NULL, 
                    188:          hInst, 
                    189:          NULL
                    190:       )))
                    191:       return FALSE;                    //* ERROR return
                    192: 
                    193:    LoadString(hInst, IDS_APPNAME, szAppName, CBMESSAGEMAX);
                    194:    DragAcceptFiles(hwndFrame, TRUE);   //* allow dragged and dropped files
                    195: 
1.1.1.2   root      196:    hDC    = GetDC (NULL);       // Get the hDC of the desktop window
                    197:    giXppli = GetDeviceCaps (hDC, LOGPIXELSX);
                    198:    giYppli = GetDeviceCaps (hDC, LOGPIXELSY);
                    199:    ReleaseDC (NULL, hDC);
                    200:        
                    201: 
1.1       root      202:        
                    203:    return TRUE;                        //* SUCCESS return
                    204: 
                    205: }
                    206: 
                    207: /***************************************************************************
                    208:  *  ProcessCmdLine()
                    209:  *
                    210:  *  process command line getting any command arguments.  
                    211:  ***************************************************************************/
                    212: 
                    213: VOID ProcessCmdLine(LPSTR lpCmdLine)
                    214: {                                     //* LOCAL:
                    215:    OFSTRUCT       ofs;    
                    216: 
                    217: 
                    218:    if (*lpCmdLine)                     
                    219:    {                                   //* look for file extension
                    220:       LPSTR lpstrExt = lpCmdLine;      //* pointer to file extension
                    221: 
                    222:       while (*lpstrExt && *lpstrExt != '.') 
                    223:          lpstrExt = AnsiNext(lpstrExt);
                    224: 
                    225:       lstrcpy(szFileName, lpCmdLine);
                    226:       if (!(*lpstrExt))                //* append default extension
                    227:       {
                    228:          lstrcat(szFileName,".");
                    229:          lstrcat(szFileName,szDefExtension);
                    230:       }
                    231:                                        //* get the files fully 
                    232:       OpenFile(szFileName, &ofs, OF_PARSE);//* qualified name
                    233:       lstrcpy(szFileName, ofs.szPathName);
                    234:    }
                    235:    else 
1.1.1.3 ! root      236:       *szFileName = 0;
1.1       root      237:                                        //* pass filename to main winproc
1.1.1.3 ! root      238:    SendMessage(hwndFrame,WM_INIT,(WPARAM)0,(LPARAM)0);
1.1       root      239: 
                    240: }
                    241: 
                    242: 
                    243: /***************************************************************************
                    244:  *  FrameWndProc()
                    245:  *
                    246:  *  Message handler for the application frame window.
                    247:  *
                    248:  *  Returns long - Variable, depends on message.
                    249:  ***************************************************************************/
                    250: 
                    251: LONG  APIENTRY FrameWndProc(           //* ENTRY:
                    252:    HWND           hwnd,                //* standard wind-proc parameters 
                    253:    UINT           msg, 
                    254:    DWORD          wParam, 
                    255:    LONG           lParam
                    256: ){                                     //* LOCAL:
                    257:                                        //* ^ Document file name
                    258:    static LHCLIENTDOC   lhcDoc;        //* Document Handle
                    259:    static LPOLECLIENT   lpClient;      //* pointer to client 
                    260:    static LPAPPSTREAM   lpStream;      //* pointer to stream vtbl
                    261:    APPITEMPTR           pItem;         //* application item pointer
                    262: 
                    263:    switch (msg) 
                    264:    {     
                    265:       case WM_INIT:                    //* user defined message
                    266:          if (!InitAsOleClient(hInst, hwnd, szFileName, &lhcDoc, &lpClient, &lpStream))
                    267:             DestroyWindow(hwnd);
                    268:          break;
                    269:                                        //* the following three messages are
                    270:                                        //* used to avoid problems with OLE
                    271:                                        //* see the comment in object.h
                    272:       case WM_DELETE:                  //* user defined message
1.1.1.3 ! root      273:          pItem = (APPITEMPTR) lParam;  //* delete object
1.1       root      274:          WaitForObject(pItem);
                    275:          ObjDelete(pItem,OLE_OBJ_DELETE);
1.1.1.3 ! root      276:          if (wParam)
1.1       root      277:             cOleWait--;
                    278:          break;
                    279: 
                    280:       case WM_ERROR:                   //* user defined message
                    281:          ErrorMessage(wParam);         //* display error message
                    282:          break;
                    283: 
                    284:       case WM_RETRY:                   //* user defined message
1.1.1.3 ! root      285:          RetryMessage((APPITEMPTR)lParam, RD_RETRY | RD_CANCEL);
1.1       root      286:          break;
                    287: 
                    288:       case WM_INITMENU:
                    289:          UpdateMenu((HMENU)wParam);
                    290:          break;
                    291: 
                    292:       case WM_COMMAND: 
                    293:       {
                    294:          WORD wID = LOWORD(wParam);
                    295:    
                    296:          pItem = GetTopItem();
                    297: 
                    298:          switch (wID) 
                    299:          {
                    300:             case IDM_NEW:
                    301:                ANY_OBJECT_BUSY;
                    302:                NewFile(szFileName,&lhcDoc,lpStream);
                    303:                break;
                    304: 
                    305:             case IDM_OPEN:
                    306:                ANY_OBJECT_BUSY;
                    307:                MyOpenFile(szFileName,&lhcDoc,lpClient,lpStream);
                    308:                break;
                    309: 
                    310:             case IDM_SAVE:
                    311:                ANY_OBJECT_BUSY;
                    312:                SaveFile(szFileName,lhcDoc,lpStream);
                    313:                break;
                    314: 
                    315:             case IDM_SAVEAS:
                    316:                ANY_OBJECT_BUSY;
                    317:                SaveasFile(szFileName,lhcDoc,lpStream);
                    318:                break;
                    319: 
                    320:             case IDM_ABOUT:
                    321:                AboutBox();
                    322:                break;
                    323: 
                    324:             case IDM_INSERT:
                    325:                ANY_OBJECT_BUSY;
                    326:                ObjInsert(lhcDoc, lpClient);
                    327:                break;
                    328: 
                    329:             case IDM_INSERTFILE:
                    330:                ANY_OBJECT_BUSY;
                    331:                ObjCreateFromTemplate(lhcDoc,lpClient);
                    332:                break;
                    333: 
                    334:             case IDM_PASTE:
                    335:             case IDM_PASTELINK:
                    336:                ANY_OBJECT_BUSY;
                    337:                ObjPaste(wID == IDM_PASTE,lhcDoc,lpClient); 
                    338:                break;
                    339: 
                    340:             case IDM_LINKS:
                    341:                ANY_OBJECT_BUSY;
                    342:                pItem = GetTopItem();
                    343:                LinkProperties();
                    344:                break;
                    345:             
                    346:             case IDM_EXIT:
                    347:                ANY_OBJECT_BUSY;
                    348:                SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
                    349:                break;
                    350: 
                    351:             case IDM_COPY:
                    352:             case IDM_CUT:
                    353:                ANY_OBJECT_BUSY;
                    354:              
                    355:                if (!ObjCopy(pItem))
                    356:                {
                    357:                   ErrorMessage((wParam == IDM_CUT) ?
                    358:                      E_CLIPBOARD_CUT_FAILED : E_CLIPBOARD_COPY_FAILED);
                    359:                   break;
                    360:                }   
                    361: 
                    362:                if (wParam == IDM_COPY)
                    363:                   break;
                    364: 
                    365:             case IDM_CLEAR:            //* CUT falls through to clear
                    366:                ANY_OBJECT_BUSY;
                    367:                ClearItem(pItem);
                    368:                break;
                    369: 
                    370:             case IDM_CLEARALL:
                    371:                ANY_OBJECT_BUSY;
                    372:                ClearAll(lhcDoc,OLE_OBJ_DELETE);
                    373:                Dirty(DOC_DIRTY);
                    374:                break;
                    375: 
                    376:             default:
                    377:                if( (wParam >= IDM_VERBMIN) && (wParam <= IDM_VERBMAX) )
                    378:                {    
                    379:                   ANY_OBJECT_BUSY;
                    380:                   ExecuteVerb(wParam - IDM_VERBMIN,pItem);
                    381:                   break;
                    382:                }
                    383:                return DefWindowProc(hwnd, msg, wParam, lParam);
                    384:          }
                    385:          break;
                    386:       }
                    387: 
                    388:       case WM_DROPFILES:
                    389:          ANY_OBJECT_BUSY;
                    390:          ObjCreateWrap((HANDLE)wParam, lhcDoc, lpClient);
                    391:          break;
                    392: 
                    393:       case WM_CLOSE:
                    394:          ANY_OBJECT_BUSY;   
                    395:          if (!SaveAsNeeded(szFileName, lhcDoc, lpStream))
                    396:             break;
                    397:          DeregDoc(lhcDoc);
                    398:          DestroyWindow(hwnd);
                    399:          break;
                    400: 
                    401:       case WM_DESTROY:
                    402:          EndStream(lpStream);
                    403:          EndClient(lpClient);
                    404:          PostQuitMessage(0);
                    405:          break;
                    406:                                        
                    407:       case WM_QUERYENDSESSION:         //* don't let windows terminate 
                    408:          return (QueryEndSession(szFileName,lhcDoc, lpStream));
                    409: 
                    410:       default:
                    411:          return DefWindowProc(hwnd, msg, wParam, lParam);
                    412:    } 
                    413:    return 0L;
                    414: 
                    415: }
                    416: 
                    417: /***************************************************************************
                    418:  * InitAsOleClient()
                    419:  *
                    420:  * Initiates the creation of stream and client vtbls.  These vtbls are very
                    421:  * important for the proper operation of this application.  The stream vtbl
                    422:  * lets the OLE librarys know where the location of the stream I/O routines
                    423:  * reside.  The stream routines are used by OleLoadFromStream and the like.
                    424:  * The client vtbl is used to hold the pointer to the CallBack function.
                    425:  * IMPORTANT: both the client and the stream structures have pointers to 
                    426:  * vtbls which have the pointers to the functions.  Therefore, it is 
                    427:  * necessary to allocate space for the vtbl and the client structure
                    428:  * which has the pointer to the vtbl.  
                    429:  **************************************************************************/
                    430: 
                    431: static BOOL InitAsOleClient(           //* ENTRY:
                    432:    HANDLE         hInstance,           //* applicaion instance handle
                    433:    HWND           hwnd,                //* main window handle
                    434:    PSTR           pFileName,           //* document file name
                    435:    LHCLIENTDOC    *lhcDoc,             //* pointer to document Handle
                    436:    LPOLECLIENT    *lpClient,           //* pointer to client pointer 
                    437:    LPAPPSTREAM    *lpStream            //* pointer to APPSTREAM pointer
                    438: ){
                    439:                                        //* initiate client vtbl creation
                    440:    if (!(*lpClient = InitClient(hInstance)))
                    441:    {
                    442:       SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
                    443:       return FALSE;                    //* ERROR return
                    444:    }
                    445:                                        //* initiate stream vtbl creation
                    446:    if (!(*lpStream = InitStream(hInstance)))
                    447:    {
                    448:       SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
                    449:       return FALSE;                    //* ERROR return
                    450:    }
                    451: 
                    452:    if (*pFileName && RegDoc(pFileName,lhcDoc)
                    453:        && LoadFile(pFileName,*lhcDoc,*lpClient,*lpStream)) 
                    454:    {  
                    455:       SetTitle(pFileName); 
                    456:       return TRUE;                     //* SUCCESS return
                    457:    }
                    458: 
                    459:    NewFile(pFileName, lhcDoc, *lpStream);
                    460:    return TRUE;                        //* SUCCESS return
                    461: 
                    462: }                                      //* SUCCESS return
                    463: 
                    464: /****************************************************************************
                    465:  *  InitClient()
                    466:  *
                    467:  *  Initialize the OLE client structure, create and fill the OLECLIENTVTBL 
                    468:  *  structure.
                    469:  *
                    470:  *  Returns LPOLECLIENT - if successful a pointer to a client structure
                    471:  *                        , otherwise NULL.
                    472:  ***************************************************************************/
                    473: 
                    474: static LPOLECLIENT InitClient(         //* ENTRY:
                    475:    HANDLE hInstance                    //* application instance handle
                    476: ){                                     //* LOCAL:
                    477:    LPOLECLIENT lpClient=NULL;          //* pointer to client struct
                    478:                                        //* Allocate vtbls
                    479:    if (!(lpClient = (LPOLECLIENT)GlobalLock(
                    480:          GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(OLECLIENT))
                    481:       )))
                    482:       goto Error;                      //* ERROR jump        
                    483: 
                    484:    if (!(lpClient->lpvtbl = (LPOLECLIENTVTBL)GlobalLock(
                    485:             GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(OLECLIENTVTBL))
                    486:       )))
                    487:       goto Error;                      //* ERROR jump
                    488:                                        //* set the CALLBACK function
                    489:                                        //* pointer
                    490:    lpClient->lpvtbl->CallBack  = CallBack;
                    491: 
                    492:    return lpClient;                    //* SUCCESS return
                    493:    
                    494: Error:                                 //* ERROR Tag
                    495:    
                    496:    ErrorMessage(E_FAILED_TO_ALLOC);
                    497:    EndClient(lpClient);                //* free any allocated space
                    498: 
                    499:    return NULL;                        //* ERROR return
                    500:   
                    501: }
                    502:     
                    503: /****************************************************************************
                    504:  *  InitStream()
                    505:  *
                    506:  *  Create and fill the STREAMVTBL. Create a stream structure and initialize
                    507:  *  pointer to stream vtbl.
                    508:  *
                    509:  *  Returns LPAPPSTREAM - if successful a pointer to a stream structure
                    510:  *                        , otherwise NULL .     
                    511:  ***************************************************************************/
                    512: 
                    513: static LPAPPSTREAM InitStream(         //* ENTRY:
                    514:    HANDLE hInstance                    //* handle to application instance
                    515: ){                                     //* LOCAL:
                    516:    LPAPPSTREAM lpStream = NULL;        //* pointer to stream structure
                    517: 
                    518:    if (!(lpStream = (LPAPPSTREAM)GlobalLock(
                    519:          GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(APPSTREAM))
                    520:       )))
                    521:       goto Error;                      //* ERROR jump
                    522: 
                    523:    if (!(lpStream->olestream.lpstbl = (LPOLESTREAMVTBL)GlobalLock(
                    524:          GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(OLESTREAMVTBL))
                    525:       )))
                    526:       goto Error;                      //* ERROR jump
                    527: 
                    528:                                        //* set stream func. pointers
                    529:    lpStream->olestream.lpstbl->Get = (DWORD ( CALLBACK *)(LPOLESTREAM, VOID FAR *, DWORD)) ReadStream;
                    530:    lpStream->olestream.lpstbl->Put = (DWORD ( CALLBACK *)(LPOLESTREAM, OLE_CONST VOID FAR *, DWORD)) WriteStream;
                    531: 
                    532:    return lpStream;                    //* SUCCESS return
                    533: 
                    534: Error:                                 //* ERROR Tag
                    535: 
                    536:    ErrorMessage(E_FAILED_TO_ALLOC);
                    537:    EndStream(lpStream);
                    538: 
                    539:    return NULL;                        //* ERROR return
                    540: 
                    541: }
                    542: 
                    543: /***************************************************************************
                    544:  *  UpdateMenu()
                    545:  *
                    546:  *  Enabling or disable menuitems based upon program state.
                    547:  ***************************************************************************/
                    548: 
                    549: static VOID UpdateMenu(                //* ENTRY:
                    550:    HMENU       hMenu                   //* menu handle to updated
                    551: ){                                     //* LOCAL:
                    552:    INT         mf;                     //* generic menu flag 
                    553:    APPITEMPTR  paItem;                 //* app item pointer
                    554:    HMENU       hSub;
                    555:                                        //* there must be at least on object
                    556:                                        //* for the following to be enabled
                    557: 
                    558:    paItem = GetTopItem() ; 
                    559: 
                    560:    mf = (paItem ? MF_ENABLED : MF_GRAYED);
                    561:    EnableMenuItem(hMenu, IDM_CUT, mf); //* i.e. Cut,Copy,Clear,Clearall...
                    562:    EnableMenuItem(hMenu, IDM_COPY, mf);
                    563:    EnableMenuItem(hMenu, IDM_CLEAR, mf);
                    564:    EnableMenuItem(hMenu, IDM_CLEARALL, mf);
                    565:                                        //* enable links option only if there
                    566:                                        //* is at least one linked object
                    567:    EnableMenuItem(hMenu, IDM_LINKS, MF_GRAYED);
                    568:    for (; paItem; paItem = GetNextItem(paItem))
                    569:    {
                    570:       if (paItem->otObject == OT_LINK)
                    571:       {   
                    572:          EnableMenuItem(hMenu, IDM_LINKS, MF_ENABLED);
                    573:          break;
                    574:       }
                    575:    }
                    576: 
                    577:    if (hSub = GetSubMenu(hMenu,POS_EDITMENU))
                    578:       UpdateObjectMenuItem(hSub);
                    579: 
                    580:    if (OleQueryCreateFromClip(STDFILEEDITING, olerender_draw, 0) == OLE_OK)
                    581:       EnableMenuItem(hMenu, IDM_PASTE, MF_ENABLED);
                    582:    else if (OleQueryCreateFromClip(STATICP, olerender_draw, 0) == OLE_OK)
                    583:       EnableMenuItem(hMenu, IDM_PASTE, MF_ENABLED);
                    584:    else  
                    585:       EnableMenuItem(hMenu, IDM_PASTE, MF_GRAYED);
                    586: 
                    587:    if (OleQueryLinkFromClip(STDFILEEDITING, olerender_draw, 0) == OLE_OK)
                    588:       EnableMenuItem(hMenu, IDM_PASTELINK, MF_ENABLED);
                    589:    else  
                    590:       EnableMenuItem(hMenu, IDM_PASTELINK, MF_GRAYED);
                    591: 
                    592: }
                    593: 
                    594: /***************************************************************************
                    595:  *  NewFile()
                    596:  *
                    597:  *  Save the present document and open a new blank one. 
                    598:  ***************************************************************************/
                    599: 
                    600: static VOID NewFile(                   //* ENTRY:
                    601:    PSTR           pFileName,           //* open file name
                    602:    LHCLIENTDOC    *lhcptrDoc,          //* pointer to client doc. handle
                    603:    LPAPPSTREAM    lpStream             //* pointer to stream structure
                    604: ){                                     //* LOCAL:
                    605:    static CHAR  szUntitled[CBMESSAGEMAX] = "";//* "(Untitled)" string 
                    606:    LHCLIENTDOC lhcDocNew;              //* handle for new doc.
                    607: 
                    608:    if (!(*szUntitled))
                    609:       LoadString(hInst, IDS_UNTITLED, (LPSTR)szUntitled, CBMESSAGEMAX);
                    610: 
                    611:    if (SaveAsNeeded(pFileName, *lhcptrDoc, lpStream))
                    612:    {                                   //* try to register new document
                    613:       if (!RegDoc(szUntitled, &lhcDocNew)) 
                    614:          return;                       //* before deregistring the old one
                    615:       DeregDoc(*lhcptrDoc);            
                    616:       *lhcptrDoc = lhcDocNew;
                    617:       Dirty(DOC_CLEAN);                //* new document is clean
                    618:       lstrcpy(pFileName,szUntitled);
                    619:       SetTitle(pFileName);
                    620:       iObjectNumber = 0;
                    621:    }
                    622: 
                    623: }
                    624: 
                    625: /***************************************************************************
                    626:  *  MyOpenFile()
                    627:  *
                    628:  *  Open a file and load it.  Notice that the new file is loaded before
                    629:  *  the old is removed.  This is done to assure a succesful file load
                    630:  *  before removing an existing document. 
                    631:  ***************************************************************************/
                    632: 
                    633: static VOID MyOpenFile(                //* ENTRY:
                    634:    PSTR           pFileName,           //* open file name
                    635:    LHCLIENTDOC    *lhcptrDoc,          //* pointer to document handle
                    636:    LPOLECLIENT    lpClient,            //* pointer to client structure
                    637:    LPAPPSTREAM    lpStream             //* pointer to stream structure
                    638: ){                                     //* LOCAL:
                    639:    CHAR           szNewFile[CBPATHMAX];//* new file name buffer
                    640:    LHCLIENTDOC    lhcDocNew;           //* handle of new document
                    641:    APPITEMPTR     pItem;               //* hold top item
                    642: 
                    643:    if (SaveAsNeeded(pFileName, *lhcptrDoc, lpStream))
                    644:    {
1.1.1.3 ! root      645:       *szNewFile = 0;
1.1       root      646: 
                    647:       if (!OfnGetName(hwndFrame, szNewFile, IDM_OPEN)) 
                    648:          return;                       //* ERROR return
                    649:       
                    650:       if (!RegDoc(szNewFile,&lhcDocNew)) 
                    651:          return;                       //* ERROR return
                    652:       
                    653:       pItem = GetTopItem();
                    654:       ShowDoc(*lhcptrDoc,0);           //* make old doc objects hidden.
                    655:                                        //* try to load the new file before
                    656:       if (!LoadFile(szNewFile, lhcDocNew, lpClient, lpStream))
                    657:       {                                //* before removing the old.
                    658:          DeregDoc(lhcDocNew);          //* restore old document if new
                    659:          SetTopItem(pItem);            //* file did not load
                    660:          ShowDoc(*lhcptrDoc,1);
                    661:          return;                       //* ERROR return
                    662:       }
                    663:       
                    664:       DeregDoc(*lhcptrDoc);            //* deregister old document
                    665:       *lhcptrDoc = lhcDocNew;
                    666:       lstrcpy(pFileName,szNewFile);
                    667:       SetTitle(pFileName);             //* set new title
                    668:       Dirty(DOC_CLEAN);   
                    669:    }
                    670: 
                    671: }                                      //* SUCCESS return
                    672: 
                    673: /***************************************************************************
                    674:  *  SaveasFile()
                    675:  *
                    676:  * Prompt the user for a new file name.  Write the document to the new
                    677:  * filename.
                    678:  ***************************************************************************/
                    679: 
                    680: static VOID SaveasFile(                //* ENTRY:
                    681:    PSTR           pFileName,           //* old filename
                    682:    LHCLIENTDOC    lhcDoc,              //* document handle
                    683:    LPAPPSTREAM    lpStream             //* pointer to stream structure
                    684: ){
                    685:    CHAR           szNewFile[CBPATHMAX];//* new file name
                    686: 
1.1.1.3 ! root      687:    *szNewFile = 0;                  //* prompt user for new file name
1.1       root      688:    if (!OfnGetName(hwndFrame, szNewFile, IDM_SAVEAS)) 
                    689:       return;                          //* ERROR return
                    690:                                        //* rename document
                    691:    if (!SaveFile(szNewFile, lhcDoc, lpStream))
                    692:       return;
                    693: 
                    694:    if (Error(OleRenameClientDoc(lhcDoc, szNewFile)))
                    695:    {
                    696:       ErrorMessage(W_FAILED_TO_NOTIFY);
                    697:       return;                          //* ERROR return
                    698:    }   
                    699: 
                    700:    lstrcpy(pFileName,szNewFile);
                    701:    SetTitle(pFileName);
                    702: 
                    703: }                                      //* SUCCESS return
                    704: 
                    705: /***************************************************************************
                    706:  *  SaveFile()
                    707:  *
                    708:  * Save a compound document file.  If the file is untitled, ask the user
                    709:  * for a name and save the document to that file. 
                    710:  ***************************************************************************/
                    711: 
                    712: static BOOL SaveFile(                  //* ENTRY:
                    713:    PSTR           pFileName,           //* file to save document to
                    714:    LHCLIENTDOC    lhcDoc,              //* OLE document handle
                    715:    LPAPPSTREAM    lpStream             //* pointer to app. stream struct
                    716: ){                                     //* LOCAL:
                    717:    CHAR           szNewFile[CBPATHMAX];//* New file name strings
                    718:    CHAR           szOemFileName[2*CBPATHMAX]; 
                    719:    static CHAR    szUntitled[CBMESSAGEMAX] = "";
                    720:    int            fh;                  //* file handle
                    721:    
1.1.1.3 ! root      722:    *szNewFile = 0;
1.1       root      723:    if (!(*szUntitled))
                    724:       LoadString(hInst, IDS_UNTITLED, (LPSTR)szUntitled, CBMESSAGEMAX);
                    725:                     
                    726:    if (!lstrcmp(szUntitled, pFileName))//* get filename for the untitled case
                    727:    {
                    728:       if (!OfnGetName(hwndFrame, szNewFile, IDM_SAVEAS))
                    729:          return FALSE;                 //* CANCEL return    
                    730:       lstrcpy(pFileName,szNewFile);
                    731:       SetTitle(pFileName);
                    732:    }
                    733: 
                    734:    AnsiToOem(pFileName, szOemFileName);
                    735:    if ((fh = _lcreat((LPSTR)szOemFileName, 0)) <= 0) 
                    736:    {
                    737:       ErrorMessage(E_INVALID_FILENAME);
                    738:       return FALSE;                    //* ERROR return
                    739:    }
                    740: 
                    741:    lpStream->fh = fh;
                    742:                                        //* save file on disk
                    743:    if (!WriteToFile(lpStream)) 
                    744:    {
                    745:       _lclose(fh);
                    746:       ErrorMessage(E_FAILED_TO_SAVE_FILE);
                    747:       return FALSE;                    //* ERROR return
                    748:    }
                    749:    _lclose(fh);
                    750: 
                    751:    if (Error(OleSavedClientDoc(lhcDoc)))
                    752:    {
                    753:       ErrorMessage(W_FAILED_TO_NOTIFY);
                    754:       return FALSE;                    //* ERROR return
                    755:    }
                    756: 
                    757:    Dirty(DOC_CLEAN);
                    758:    return TRUE;                        //* SUCCESS return
                    759: 
                    760: } 
                    761: 
                    762: /***************************************************************************
                    763:  *  LoadFile()
                    764:  *
                    765:  *  Load a document file from disk. 
                    766:  ***************************************************************************/
                    767: 
                    768: static BOOL LoadFile(                  //* ENTRY:
                    769:    PSTR           pFileName,           //* file name
                    770:    LHCLIENTDOC    lhcDoc,              //* document handle
                    771:    LPOLECLIENT    lpClient,            //* pointer to client structure
                    772:    LPAPPSTREAM    lpStream             //* pointer to stream structure
                    773: ){                                     //* LOCAL:
                    774:                                        //* OEM file name
                    775:    CHAR           szOemFileName[2*CBPATHMAX];      
                    776:    int            fh;                  //* file handle
                    777:    INT            iObjectNumberHold;   //* hold object number
                    778: 
                    779:    AnsiToOem(pFileName, szOemFileName);
                    780:    if ((fh = _lopen(szOemFileName, OF_READ | OF_SHARE_DENY_WRITE)) == -1) 
                    781:    {
                    782:       ErrorMessage(E_FAILED_TO_READ_FILE);
                    783:       return FALSE;                    //* ERROR return
                    784:    }
                    785: 
                    786:    lpStream->fh = fh;
                    787: 
                    788:    iObjectNumberHold = iObjectNumber;  //* save object number so it can 
                    789:    iObjectNumber     = 0;              //* be restored if read from file
                    790:                                        //* fails
                    791:    if (!ReadFromFile(lpStream, lhcDoc, lpClient)) 
                    792:    {
                    793:       _lclose(fh);
                    794:       ErrorMessage(E_FAILED_TO_READ_FILE);
                    795:       iObjectNumber = iObjectNumberHold;
                    796:       return FALSE;                    //* ERROR return
                    797:    }
1.1.1.3 ! root      798:    _lclose(fh);
1.1       root      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.