Annotation of mstools/samples/ole/srvrdemo/doc.c, revision 1.1

1.1     ! root        1: /*
        !             2:   OLE SERVER DEMO           
        !             3:   Doc.c             
        !             4:                                                                      
        !             5:   This file contains document methods and various document-related support 
        !             6:   functions.
        !             7:                                                                      
        !             8:   (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved   
        !             9: */                                                                     
        !            10:  
        !            11: /* 
        !            12:    Important Note:
        !            13: 
        !            14:    No method should ever dispatch a DDE message or allow a DDE message to
        !            15:    be dispatched.
        !            16:    Therefore, no method should ever enter a message dispatch loop.
        !            17:    Also, a method should not show a dialog or message box, because the 
        !            18:    processing of the dialog box messages will allow DDE messages to be
        !            19:    dispatched.
        !            20: */
        !            21: 
        !            22: 
        !            23: 
        !            24: #define SERVERONLY
        !            25: #include <windows.h>
        !            26: #include <ole.h>
        !            27: 
        !            28: #include "srvrdemo.h"
        !            29: 
        !            30: /* AssociateClient
        !            31:  * ---------------
        !            32:  *
        !            33:  * Add a client to the list of clients associated with an object.
        !            34:  *
        !            35:  * This function is necessary only because ServerDemo does not create object
        !            36:  * structures as they are requested, but rather has a fixed set of objects.
        !            37:  * When DocGetObject is called with a NULL object name, the entire 
        !            38:  * document is requested, but ServerDemo does not currently support making
        !            39:  * the entire document an object, so DocGetObject returns one object.
        !            40:  * That object now goes by two names: NULL and its real name.  Therefore
        !            41:  * we need to keep track of both lpoleclient's that were passed to 
        !            42:  * DocGetObject.  Ideally, DocGetObject should always create a new OBJ 
        !            43:  * structure containing a pointer (or some reference) to the object's native
        !            44:  * data and also containing one lpoleclient.
        !            45:  *
        !            46:  * LPOLECLIENT lpoleclient - the client to be associated with the object.
        !            47:  * LPOBJ lpobj             - the object 
        !            48:  *
        !            49:  * RETURNS: TRUE if successful
        !            50:  *          FALSE if out of memory
        !            51:  *
        !            52:  * CUSTOMIZATION: Server Demo specific
        !            53:  *
        !            54:  */
        !            55: static BOOL AssociateClient (LPOLECLIENT lpoleclient, LPOBJ lpobj)
        !            56: {
        !            57:    INT i;
        !            58:    for (i=0; i < clpoleclient; i++)
        !            59:    {
        !            60:       if (lpobj->lpoleclient[i]==lpoleclient)
        !            61:       {
        !            62:          return TRUE;
        !            63:       }
        !            64:       if (lpobj->lpoleclient[i]==NULL)
        !            65:       {
        !            66:          lpobj->lpoleclient[i]=lpoleclient;
        !            67:          return TRUE;
        !            68:       }
        !            69:    }
        !            70:    return FALSE;
        !            71: }
        !            72: 
        !            73: 
        !            74: 
        !            75: /* CreateNewDoc
        !            76:  * ------------
        !            77:  *
        !            78:  * If lhdoc == NULL then we must register the new document by calling
        !            79:  * OleRegisterServerDoc, which will return a new handle which will be stored
        !            80:  * in docMain.lhdoc.
        !            81:  * Also if lhdoc==NULL then this document is being created at the request of
        !            82:  * the user, not of the client library.
        !            83:  *
        !            84:  * LONG lhdoc      - Document handle
        !            85:  * LPSTR lpszDoc   - Title of the new document
        !            86:  * DOCTYPE doctype - What type of document is being created
        !            87:  * 
        !            88:  * RETURNS: TRUE if successful, FALSE otherwise.
        !            89:  *
        !            90:  * CUSTOMIZATION: Re-implement
        !            91:  *
        !            92:  */
        !            93: BOOL CreateNewDoc (LONG lhdoc, LPSTR lpszDoc, DOCTYPE doctype)
        !            94: {
        !            95:    INT i;
        !            96: 
        !            97:    // Fill in the fields of the document structure.
        !            98:    if (lhdoc == NULL)
        !            99:    {
        !           100:       if (OLE_OK != OleRegisterServerDoc 
        !           101:                      (srvrMain.lhsrvr, 
        !           102:                       lpszDoc,
        !           103:                       (LPOLESERVERDOC) &docMain, 
        !           104:                       (LHSERVERDOC FAR *) &docMain.lhdoc))
        !           105:          return FALSE;
        !           106:    }
        !           107:    else
        !           108:       docMain.lhdoc = lhdoc;
        !           109: 
        !           110:    docMain.doctype      = doctype;
        !           111:    docMain.oledoc.lpvtbl= &docvtbl;
        !           112:    // Reset all the flags because no object numbers have been used.
        !           113:    for (i=1; i <= cfObjNums; i++)
        !           114:       docMain.rgfObjNums[i] = FALSE;
        !           115: 
        !           116:    fDocChanged = FALSE;
        !           117: 
        !           118:    SetTitle (lpszDoc, doctype == doctypeEmbedded);
        !           119:    return TRUE;
        !           120: }
        !           121: 
        !           122: 
        !           123: 
        !           124: /* DestroyDoc
        !           125:  * ----------
        !           126:  *
        !           127:  * Free all memory that had been allocated for a document.
        !           128:  *
        !           129:  *
        !           130:  * CUSTOMIZATION: Re-implement.  Your application will probably use some
        !           131:  *                other method for enumerating all the objects in a document.
        !           132:  *                ServerDemo enumerates the child windows, but if each object 
        !           133:  *                does not have its own window, this will not work.
        !           134:  *
        !           135:  */
        !           136: VOID DestroyDoc (VOID)
        !           137: {
        !           138:    HWND hwnd;
        !           139:    HWND hwndNext;
        !           140: 
        !           141:    // Delete all object windows.  
        !           142:    hwnd = SelectedObjectWindow();
        !           143:    while (hwnd) 
        !           144:    {
        !           145:       hwndNext = GetWindow (hwnd, GW_HWNDNEXT);
        !           146:       // Each object window frees its own memory upon receiving WM_DESTROY.
        !           147:       DestroyWindow (hwnd);
        !           148:       hwnd = hwndNext;
        !           149:    } 
        !           150: 
        !           151:    if (docMain.aName)
        !           152:    {
        !           153:       GlobalDeleteAtom (docMain.aName);
        !           154:       docMain.aName = NULL;
        !           155:    }
        !           156: 
        !           157:    if (docMain.hpal)
        !           158:       DeleteObject (docMain.hpal);
        !           159: }
        !           160: 
        !           161: 
        !           162: 
        !           163: /* DocClose                DOCUMENT "Close" METHOD
        !           164:  * --------
        !           165:  *
        !           166:  * The library calls this method to unconditionally close the document.
        !           167:  *
        !           168:  * LPOLESERVERDOC lpoledoc - The server document to close
        !           169:  * 
        !           170:  * RETURNS: Return value from RevokeDoc.
        !           171:  *
        !           172:  * CUSTOMIZATION: None
        !           173:  *
        !           174:  */
        !           175: OLESTATUS  APIENTRY DocClose (LPOLESERVERDOC lpoledoc)
        !           176: {
        !           177:    return RevokeDoc();
        !           178: }
        !           179: 
        !           180: 
        !           181: 
        !           182: /* DocExecute                DOCUMENT "Execute" METHOD
        !           183:  * ----------
        !           184:  *
        !           185:  * This application does not support the execution of DDE execution commands.
        !           186:  * 
        !           187:  * LPOLESERVERDOC lpoledoc - The server document
        !           188:  * HANDLE hCommands        - DDE execute commands
        !           189:  * 
        !           190:  * RETURNS: OLE_ERROR_COMMAND
        !           191:  *
        !           192:  * CUSTOMIZATION: Re-implement if your application supports the execution of
        !           193:  *                DDE commands.
        !           194:  *
        !           195:  */
        !           196: OLESTATUS  APIENTRY DocExecute (LPOLESERVERDOC lpoledoc, HANDLE hCommands)
        !           197: {
        !           198:    return OLE_ERROR_COMMAND;
        !           199: }
        !           200: 
        !           201: 
        !           202: 
        !           203: /* DocGetObject                DOCUMENT "GetObject" METHOD
        !           204:  * ------------
        !           205:  *
        !           206:  * The library uses this method to get an object's structure for the
        !           207:  * client.  Memory needs to be allocated and initialized here for this.
        !           208:  * A NULL string indicates that the client has an embedded object
        !           209:  * which was started from Create, CreateFromTemplate, or Edit, but not Open.
        !           210:  *
        !           211:  * First see if the object name is NULL.  If so, you would ordinarily
        !           212:  * return the entire document, but Server Demo returns the selected object.
        !           213:  * If the object name is not NULL, then go through the list of objects, 
        !           214:  * searching for one with that name.  Return an error if there is not one.
        !           215:  *
        !           216:  * LPOLESERVERDOC lpoledoc        - The server document
        !           217:  * LPSTR lpszObjectName           - The name of the object to get data for
        !           218:  * LPOLEOBJECT FAR *lplpoleobject - The object's data is put here
        !           219:  * LPOLECLIENT lpoleclient        - The client structure
        !           220:  * 
        !           221:  * RETURNS:        OLE_OK
        !           222:  *                 OLE_ERROR_NAME if object not found
        !           223:  *                 OLE_ERROR_MEMORY if no more memory to store lpoleclient
        !           224:  *
        !           225:  * CUSTOMIZATION: Re-implement.
        !           226:  *                lpszObjectName == "" indicates that the whole document 
        !           227:  *                should be the object returned.
        !           228:  *
        !           229:  */
        !           230: OLESTATUS  APIENTRY DocGetObject
        !           231:    (LPOLESERVERDOC lpoledoc, LPSTR lpszObjectName, 
        !           232:     LPOLEOBJECT FAR *lplpoleobject, LPOLECLIENT lpoleclient)
        !           233: {
        !           234:     HWND  hwnd;
        !           235:     ATOM  aName;
        !           236:     LPOBJ lpobj;
        !           237: 
        !           238: 
        !           239:     if (lpszObjectName == NULL || lpszObjectName[0] == '\0')
        !           240:     {   
        !           241:         // Return a new object or the selected object.
        !           242:         hwnd = SelectedObjectWindow();
        !           243:         lpobj = hwnd ? HwndToLpobj (hwnd) : CreateNewObj (FALSE);
        !           244:         *lplpoleobject = (LPOLEOBJECT) lpobj;
        !           245:         // Associate client with object.
        !           246:         if (!AssociateClient (lpoleclient, lpobj))
        !           247:             return OLE_ERROR_MEMORY;
        !           248:         return OLE_OK;
        !           249:     }
        !           250: 
        !           251:     if (!(aName = GlobalFindAtom (lpszObjectName)))
        !           252:         return OLE_ERROR_NAME;
        !           253: 
        !           254:     hwnd = SelectedObjectWindow();
        !           255: 
        !           256:     // Go through all the child windows and find the window whose name
        !           257:     // matches the given object name.
        !           258: 
        !           259:     while (hwnd)
        !           260:     {
        !           261:          lpobj = HwndToLpobj (hwnd);
        !           262: 
        !           263:          if (aName == lpobj->aName)
        !           264:          {
        !           265:             // Return the object with the matching name.
        !           266:             *lplpoleobject = (LPOLEOBJECT) lpobj;
        !           267:             // Associate client with the object.
        !           268:             if (!AssociateClient (lpoleclient, lpobj))
        !           269:                return OLE_ERROR_MEMORY;
        !           270:             return OLE_OK;
        !           271:          }
        !           272:          hwnd = GetWindow (hwnd, GW_HWNDNEXT);
        !           273:     }
        !           274: 
        !           275:    if (((DOCPTR)lpoledoc)->doctype ==  doctypeEmbedded)
        !           276:    {
        !           277:       lpobj = CreateNewObj (FALSE);
        !           278:       *lplpoleobject = (LPOLEOBJECT) lpobj;
        !           279:       
        !           280:       // Associate client with object.
        !           281:       if (!AssociateClient (lpoleclient, lpobj))
        !           282:          return OLE_ERROR_MEMORY;
        !           283:       return OLE_OK;
        !           284:     }
        !           285: 
        !           286:     // Object with name lpszObjName was not found.
        !           287:     return OLE_ERROR_NAME;
        !           288: }
        !           289: 
        !           290: /* DocRelease                DOCUMENT "Release" METHOD
        !           291:  * ----------
        !           292:  *
        !           293:  * The library uses this method to notify the server that a revoked
        !           294:  * document has finally finished all conversations, and can be 
        !           295:  * destroyed.
        !           296:  * It sets fWaitingForDocRelease to FALSE so a new document can be created
        !           297:  * and the user can continue working.
        !           298:  *
        !           299:  * LPOLESERVERDOC lpoledoc        - The server document
        !           300:  * 
        !           301:  * RETURNS: OLE_OK
        !           302:  *
        !           303:  * CUSTOMIZATION: None
        !           304:  *
        !           305:  */
        !           306: OLESTATUS  APIENTRY DocRelease (LPOLESERVERDOC lpoledoc)
        !           307: {
        !           308:    fWaitingForDocRelease = FALSE;
        !           309:    // Free all memory that has been allocated for the document.
        !           310:    DestroyDoc();
        !           311: 
        !           312:    return OLE_OK;
        !           313: }
        !           314: 
        !           315: 
        !           316: 
        !           317: /* DocSave                DOCUMENT "Save" METHOD
        !           318:  * -------
        !           319:  *
        !           320:  * Save document to a file.
        !           321:  *
        !           322:  * LPOLESERVERDOC lpoledoc - The document to save
        !           323:  * 
        !           324:  * RETURNS: OLE_OK
        !           325:  *
        !           326:  * CUSTOMIZATION: None
        !           327:  *
        !           328:  */
        !           329: OLESTATUS  APIENTRY DocSave (LPOLESERVERDOC lpoledoc)
        !           330: {
        !           331:     if (docMain.doctype == doctypeFromFile)
        !           332:     {
        !           333:          // No "File Save As" dialog box will be brought up because the
        !           334:          // file name is already known.
        !           335:          return SaveDoc() ? OLE_OK : OLE_ERROR_GENERIC;
        !           336:     }
        !           337:     else
        !           338:       return OLE_ERROR_GENERIC;
        !           339: }
        !           340: 
        !           341: 
        !           342: 
        !           343: /* DocSetDocDimensions        DOCUMENT "SetDocDimensions" METHOD
        !           344:  * -------------------
        !           345:  *
        !           346:  * The library calls this method to tell the server the bounds on
        !           347:  * the target device for rendering the document.
        !           348:  * A call to this method is ignored for linked objects because the size of
        !           349:  * a linked document depends only on the source file.
        !           350:  *
        !           351:  * LPOLESERVERDOC lpoledoc - The server document
        !           352:  * LPRECT         lprect   - The target size in MM_HIMETRIC units
        !           353:  * 
        !           354:  * RETURNS: OLE_OK
        !           355:  *
        !           356:  * CUSTOMIZATION: Re-implement
        !           357:  *                How an object is sized is application-specific. (Server Demo
        !           358:  *                uses MoveWindow.)
        !           359:  *                     
        !           360:  */
        !           361: OLESTATUS  APIENTRY DocSetDocDimensions 
        !           362:    (LPOLESERVERDOC lpoledoc, LPRECT lprect)
        !           363: {
        !           364:    if (docMain.doctype == doctypeEmbedded)
        !           365:    {
        !           366:       RECT rect = *lprect;
        !           367:       
        !           368:       // the units are in HIMETRIC
        !           369:       rect.right   = rect.right - rect.left;
        !           370:       rect.bottom  = rect.bottom -  rect.top;
        !           371:                
        !           372:       HiMetricToDevice (hwndMain, (LPPOINT) &rect.right);
        !           373:       MoveWindow (SelectedObjectWindow(), 0, 0, 
        !           374:                   rect.right + 2 * GetSystemMetrics(SM_CXFRAME), 
        !           375:                   rect.bottom + 2 * GetSystemMetrics(SM_CYFRAME), 
        !           376:                   TRUE);
        !           377:       /* If for some reason your application needs to notify the client that
        !           378:          the data has changed because DocSetDocDimensions has been called,
        !           379:          then notify the client here.
        !           380:          SendDocMsg (OLE_CHANGED);
        !           381:       */
        !           382:    }
        !           383:    return OLE_OK;
        !           384: }
        !           385: 
        !           386: 
        !           387: 
        !           388: /* DocSetHostNames        DOCUMENT "SetHostNames" METHOD
        !           389:  * ---------------
        !           390:  *
        !           391:  * The library uses this method to set the name of the document
        !           392:  * window.
        !           393:  * All this function does is change the title bar text, although it could
        !           394:  * do more if necesary. 
        !           395:  * This function is only called for embedded objects; linked objects
        !           396:  * use their filenames for the title bar text.
        !           397:  *
        !           398:  * LPOLESERVERDOC lpoledoc    - The server document
        !           399:  * LPSTR lpszClient           - The name of the client
        !           400:  * LPSTR lpszDoc              - The client's name for the document
        !           401:  * 
        !           402:  * RETURNS:        OLE_OK
        !           403:  * 
        !           404:  * CUSTOMIZATION: None
        !           405:  *
        !           406:  */
        !           407: OLESTATUS  APIENTRY DocSetHostNames 
        !           408:    (LPOLESERVERDOC lpoledoc, LPSTR lpszClient, LPSTR lpszDoc)
        !           409: {
        !           410:    SetTitle (lpszDoc, TRUE);
        !           411:    lstrcpy ((LPSTR) szClient, lpszClient);
        !           412:    lstrcpy ((LPSTR) szClientDoc, Abbrev(lpszDoc));
        !           413:    UpdateFileMenu (IDM_UPDATE);   
        !           414:    return OLE_OK;
        !           415: }
        !           416: 
        !           417: 
        !           418: 
        !           419: /* DocSetColorScheme                DOCUMENT "SetColorScheme" METHOD
        !           420:  * -----------------
        !           421:  *
        !           422:  * The client calls this method to suggest a color scheme (palette) for
        !           423:  * the server to use.
        !           424:  * In Server Demo the document's palette is never actually used because each 
        !           425:  * object has its own palette.  See ObjSetColorScheme.
        !           426:  *
        !           427:  * LPOLESERVERDOC lpoledoc - The server document
        !           428:  * LPLOGPALETTE   lppal    - Suggested palette
        !           429:  *
        !           430:  * RETURNS: OLE_ERROR_PALETTE if CreatePalette fails, 
        !           431:  *          OLE_OK otherwise
        !           432:  *
        !           433:  * 
        !           434:  * CUSTOMIZATION: If your application supports color schemes, then this 
        !           435:  *                function is a good example of how to create and store
        !           436:  *                a palette.
        !           437:  */
        !           438: OLESTATUS  APIENTRY DocSetColorScheme 
        !           439:    (LPOLESERVERDOC lpoledoc, LPLOGPALETTE lppal)
        !           440: {
        !           441:    HPALETTE hpal = CreatePalette (lppal);
        !           442: 
        !           443:    if (hpal==NULL)
        !           444:       return OLE_ERROR_PALETTE;
        !           445: 
        !           446:    if (docMain.hpal) 
        !           447:    {
        !           448:       // Delete old palette
        !           449:       DeleteObject (docMain.hpal);
        !           450:    }
        !           451:    // Store handle to new palette
        !           452:    docMain.hpal = hpal;
        !           453:    return OLE_OK;
        !           454: }
        !           455: 
        !           456: 
        !           457: 
        !           458: /* RevokeDoc
        !           459:  * ---------
        !           460:  *
        !           461:  * Call OleRevokeServerDoc.
        !           462:  * If the return value is OLE_WAIT_FOR_BUSY, then set fWaitingForDocRelease
        !           463:  * and enter a message-dispatch loop until fWaitingForDocRelease is reset.
        !           464:  * As long as fWaitingForDocRelease is set, the user interface will be 
        !           465:  * disabled so that the user will not be able to manipulate the document.
        !           466:  * When the DocRelease method is called, it will reset fWaitingForDocRelease,
        !           467:  * allowing RevokeDoc to free the document's memory and return.
        !           468:  *
        !           469:  * This is essentially a way to make an asynchronous operation synchronous.
        !           470:  * We need to wait until the old document is revoked before we can delete
        !           471:  * its data and create a new one.
        !           472:  *
        !           473:  * Note that we cannot call RevokeDoc from a method because it is illegal to
        !           474:  * enter a message-dispatch loop within a method.
        !           475:  *
        !           476:  * RETURNS: The return value of OleRevokeServerDoc.
        !           477:  *
        !           478:  * CUSTOMIZATION: lhdoc may need to be passed in as a parameter if your 
        !           479:  *                application does not have a global variable corresponding 
        !           480:  *                to docMain.
        !           481:  * 
        !           482:  */
        !           483: OLESTATUS RevokeDoc (VOID)
        !           484: {
        !           485:    OLESTATUS olestatus;
        !           486: 
        !           487:    if ((olestatus = OleRevokeServerDoc(docMain.lhdoc)) > OLE_WAIT_FOR_RELEASE)
        !           488:       DestroyDoc();
        !           489: 
        !           490:    docMain.lhdoc = NULL; // A NULL handle indicates that the document 
        !           491:                          // has been revoked or is being revoked.
        !           492:    return olestatus;
        !           493: 
        !           494: }
        !           495: 
        !           496: 
        !           497: 
        !           498: /* SaveChangesOption
        !           499:  * -----------------
        !           500:  *
        !           501:  * Give the user the opportunity to save changes to the current document
        !           502:  * before continuing.
        !           503:  *
        !           504:  * BOOL *pfUpdateLater - Will be set to TRUE if the client does not accept
        !           505:  *                       the update and needs to be updated when the document
        !           506:  *                       is closed.  In that case, OLE_CLOSED will be sent.
        !           507:  *
        !           508:  * RETURNS: IDYES, IDNO, or IDCANCEL
        !           509:  *
        !           510:  * CUSTOMIZATION: None
        !           511:  *
        !           512:  */
        !           513: INT SaveChangesOption (BOOL *pfUpdateLater)
        !           514: {
        !           515:    INT  nReply;
        !           516:    CHAR szBuf[cchFilenameMax];
        !           517:    
        !           518:    *pfUpdateLater = FALSE;
        !           519:    
        !           520:    if (fDocChanged)
        !           521:    {
        !           522:        CHAR szTmp[cchFilenameMax];
        !           523:        
        !           524:        if (docMain.aName) 
        !           525:            GlobalGetAtomName (docMain.aName, szTmp, cchFilenameMax);
        !           526:        else 
        !           527:            szTmp[0] = NULL;
        !           528: 
        !           529:        if (docMain.doctype == doctypeEmbedded)
        !           530:            wsprintf (szBuf, "The object has been changed.\n\nUpdate %s before closing the object?", Abbrev (szTmp));        
        !           531:        else
        !           532:            lstrcpy (szBuf, (LPSTR) "Save changes?");         
        !           533:      
        !           534:        nReply = MessageBox (hwndMain, szBuf, szAppName, 
        !           535:                       MB_ICONEXCLAMATION | MB_YESNOCANCEL);
        !           536:                   
        !           537:        switch (nReply)
        !           538:        {
        !           539:           case IDYES:
        !           540:               if (docMain.doctype != doctypeEmbedded)
        !           541:                   SaveDoc();
        !           542:               else
        !           543:                   switch (OleSavedServerDoc (docMain.lhdoc))
        !           544:                   {
        !           545:                       case OLE_ERROR_CANT_UPDATE_CLIENT:
        !           546:                           *pfUpdateLater = TRUE;
        !           547:                           break;
        !           548:                       case OLE_OK:
        !           549:                           break;
        !           550:                       default:
        !           551:                           ErrorBox ("Fatal Error: Cannot update.");
        !           552:                   }                                      
        !           553:               return IDYES;
        !           554:           case IDNO:
        !           555:               return IDNO;
        !           556:          case IDCANCEL:
        !           557:               return IDCANCEL;
        !           558:        }
        !           559:    }
        !           560:    return TRUE;
        !           561: }
        !           562: 
        !           563: 
        !           564: 
        !           565: /* SendDocMsg
        !           566:  * ----------
        !           567:  *
        !           568:  * This function sends messages to all the objects in a document when
        !           569:  * the document has changed.
        !           570:  *
        !           571:  * WORD wMessage - The message to send
        !           572:  * 
        !           573:  * CUSTOMIZATION: The means of enumerating all the objects in a document
        !           574:  *                is application specific.
        !           575:  */
        !           576: VOID SendDocMsg (WORD wMessage)
        !           577: {
        !           578:     HWND    hwnd;
        !           579: 
        !           580:     // Get handle to first object window.
        !           581:     hwnd = SelectedObjectWindow();
        !           582: 
        !           583:     // Send message to all object windows.
        !           584:     while (hwnd)
        !           585:     {
        !           586:         SendObjMsg (HwndToLpobj(hwnd), wMessage);
        !           587:         hwnd = GetWindow (hwnd, GW_HWNDNEXT);
        !           588:     }
        !           589: }
        !           590: 
        !           591: 

unix.superglobalmegacorp.com

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