home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / msysjour / vol05 / 02 / clipbrd / viewer1.c < prev    next >
Text File  |  1990-03-01  |  26KB  |  784 lines

  1. /*
  2.  * WINDOWS CLIPBOARD VIEWER - SOURCE CODE
  3.  *
  4.  * LANGUAGE      : Microsoft C 5.1
  5.  * MODEL         : medium
  6.  * ENVIRONMENT   : Microsoft Windows 2.1 SDK
  7.  * STATUS        : operational
  8.  *
  9.  * 1.01-Kevin P. Welch- add param to GetClipboardFmtName.
  10.  *
  11.  */
  12.  
  13. #define  NOCOMM
  14.  
  15. #include <windows.h>
  16. #include <process.h>
  17. #include <memory.h>
  18. #include <string.h>
  19. #include <stdio.h>
  20.  
  21. #include "viewer.h"
  22.  
  23. /* viewer window child id numbers */
  24. #define  ID_STATUS     1
  25. #define  ID_CLIENT     2
  26. #define  ID_SIZEBOX    3
  27.  
  28. /* viewer window properties */
  29. #define  CBCHAIN       MAKEINTRESOURCE(1)
  30. #define  CBFORMAT      MAKEINTRESOURCE(2)
  31. #define  CBGETDATA     MAKEINTRESOURCE(3)
  32. #define  CBLIBRARY     MAKEINTRESOURCE(4)
  33. #define  HWNDSTATUS    MAKEINTRESOURCE(5)
  34. #define  HWNDCLIENT    MAKEINTRESOURCE(6)
  35. #define  HWNDSIZEBOX   MAKEINTRESOURCE(7)
  36.  
  37.  
  38.  
  39. /*
  40.  * WinMain( hInstance, hPrevInstance, lpszCmd, wCmdShow ) : VOID
  41.  *
  42.  *    hCrntInst      current instance handle
  43.  *    hPrevInst     previous instance handle
  44.  *    lpszCmdLine    current command line
  45.  *    wInitShowCmd   initial show window command
  46.  *
  47.  * This function is responsible for registering and creating
  48.  * the clipboard viewer window.  Once the window has been created,
  49.  * it is also responsible for retrieving and dispatching all the
  50.  * messages related to the window.
  51.  *
  52.  */
  53.  
  54. VOID PASCAL WinMain(
  55.    HANDLE      hCrntInst,
  56.    HANDLE      hPrevInst,
  57.    LPSTR       lpszCmdLine,
  58.    WORD        wInitShowCmd )
  59. {
  60.    /* local variables */
  61.    MSG         msgViewer;
  62.  WORD      wWndWidth;
  63.  WORD      wWndHeight;
  64.  HWND      hWndViewer;
  65.  WNDCLASS    classViewer;
  66.  
  67.  /* warning level 3 compatibility */
  68.  lpszCmdLine;
  69.  
  70.  /* define viewer class */
  71.    memset( &classViewer, 0, sizeof(WNDCLASS) );
  72.    classViewer.lpszClassName =(LPSTR)"Viewer";
  73.    classViewer.hCursor =      LoadCursor( NULL, IDC_ARROW );
  74.    classViewer.lpszMenuName = (LPSTR)"ViewerMenu";
  75.    classViewer.style =        CS_HREDRAW | CS_VREDRAW;
  76.    classViewer.lpfnWndProc =  ViewerWndFn;
  77.    classViewer.hInstance =    hCrntInst;
  78.    classViewer.hIcon =        LoadIcon( hCrntInst, "ViewerIcon" );
  79.  
  80.  /* register class if no previous instance */
  81.  if ( (hPrevInst) || (RegisterClass(&classViewer)) ) {
  82.  
  83.    /* calculate initial width & height */
  84.    wWndWidth = ( GetSystemMetrics(SM_CXSCREEN) >
  85.                  40 * GetSystemMetrics(SM_CXVSCROLL) ) ?
  86.                  40 * GetSystemMetrics(SM_CXVSCROLL )  :
  87.                   2 * GetSystemMetrics(SM_CXSCREEN) / 3;
  88.  
  89.    wWndHeight = ( GetSystemMetrics(SM_CYSCREEN) >
  90.                  30 * GetSystemMetrics(SM_CYHSCROLL) ) ?
  91.                  30 * GetSystemMetrics(SM_CYHSCROLL )  :
  92.                   2 * GetSystemMetrics(SM_CYSCREEN) / 3;
  93.  
  94.    /* create viewer window */
  95.       hWndViewer = CreateWindow(
  96.             "Viewer",
  97.             "Clipboard Viewer",
  98.             WS_TILEDWINDOW|WS_CLIPCHILDREN,
  99.             CW_USEDEFAULT,
  100.             CW_USEDEFAULT,
  101.        wWndWidth,
  102.        wWndHeight,
  103.             (HWND)NULL,
  104.             (HMENU)NULL,
  105.             hCrntInst,
  106.             (LPSTR)(DWORD)hPrevInst
  107.          );
  108.  
  109.       /* continue if successful */
  110.       if ( hWndViewer ) {
  111.  
  112.      /* display window */
  113.          ShowWindow( hWndViewer, wInitShowCmd );
  114.  
  115.          /* process all related messages */
  116.          while ( GetMessage( &msgViewer, NULL, 0, 0 ) ) {
  117.             TranslateMessage( &msgViewer );
  118.             DispatchMessage( &msgViewer );
  119.          }
  120.  
  121.          /* normal exit */
  122.          exit( msgViewer.wParam );
  123.  
  124.       } else
  125.          WARNING( NULL, "Unable to create Clipboard Viewer!" );
  126.  
  127.    } else
  128.       WARNING( NULL, "Unable to register Clipboard Viewer!" );
  129.  
  130.  /* abnormal exit */
  131.  exit( TRUE );
  132.  
  133. }
  134.  
  135.  
  136.  
  137. /*
  138.  * ViewerWndFn( hWnd, wMsg, wParam, lParam ) : LONG
  139.  *
  140.  *    hWnd        window handle
  141.  *    wMsg      message number
  142.  *    wParam      additional message information
  143.  *    lParam      additional message information
  144.  *
  145.  * This window function processes all the messages related to
  146.  * the clipboard viewer window.  When created this window
  147.  * registers and creates the associated status and client windows.
  148.  *
  149.  */
  150.  
  151. LONG FAR PASCAL ViewerWndFn( hWnd, wMsg, wParam, lParam )
  152.    HWND        hWnd;
  153.    WORD        wMsg;
  154.    WORD        wParam;
  155.    LONG        lParam;
  156. {
  157.    LONG        lResult;
  158.  
  159.    /* initialization */
  160.    lResult = FALSE;
  161.  
  162.    /* process each message */
  163.    switch( wMsg )
  164.       {
  165.  case WM_CREATE : /* create window */
  166.    {
  167.      char *    pKey;
  168.      HANDLE    hFmtLib;
  169.      HANDLE    hLibrary;
  170.      HANDLE    hCrntInst;
  171.      HANDLE    hPrevInst;
  172.      LPLIBRARY lpLibrary;
  173.      HWND      hWndStatus;
  174.      HWND      hWndClient;
  175.      HWND      hWndSizebox;
  176.      WNDCLASS    classStatus;
  177.      WNDCLASS    classClient;
  178.      char      szLib[128];
  179.      char      szList[128];
  180.  
  181.      /* define instance handles */
  182.      hCrntInst = INSTANCE(hWnd);
  183.      hPrevInst = (HANDLE)((LPCREATESTRUCT)lParam)->lpCreateParams;
  184.  
  185.      /* define initial property lists */
  186.      SetProp( hWnd, CBCHAIN, NULL );
  187.      SetProp( hWnd, CBFORMAT, NULL );
  188.      SetProp( hWnd, CBGETDATA, NULL );
  189.      SetProp( hWnd, HWNDSTATUS, NULL );
  190.      SetProp( hWnd, HWNDCLIENT, NULL );
  191.      SetProp( hWnd, HWNDSIZEBOX, NULL );
  192.  
  193. /* define library data structure */
  194. hLibrary = GlobalAlloc( GHND, (DWORD)sizeof(LIBRARY) );
  195. if ( hLibrary ) {
  196.   lpLibrary = (LPLIBRARY)GlobalLock( hLibrary );
  197.   if ( lpLibrary ) {
  198.  
  199.     /* initialization */
  200.     lpLibrary->wModules = 0;
  201.  
  202.     /* retrieve list of supported formats */
  203.     if ( GetProfileString("Clipboard",NULL,"",
  204.                           szList,sizeof(szList)) ) {
  205.       pKey = &szList[0];
  206.       while ( *pKey ) {
  207.         GetProfileString("Clipboard",pKey,"", szLib, sizeof(szLib));
  208.         if ( szLib[0] > ' ' ) {
  209.           hFmtLib = LoadLibrary( szLib );
  210.           if ( hFmtLib >= 32 ) {
  211.             lpLibrary->Module[lpLibrary->wModules].hModule = hFmtLib;
  212.             lpLibrary->Module[lpLibrary->wModules++].wFormat =
  213.               GetClipboardFmtNumber(pKey);
  214.           }
  215.         }
  216.         pKey += strlen(pKey) + 1;
  217.       }
  218.     }
  219.  
  220.          /* unlock library & save handle */
  221.          GlobalUnlock( hLibrary );
  222.          SetProp( hWnd, CBLIBRARY, hLibrary );
  223.  
  224.          /* define status class */
  225.            memset( &classStatus, 0, sizeof(WNDCLASS) );
  226.            classStatus.lpszClassName =(LPSTR)"ViewerStatus";
  227.            classStatus.hCursor =      LoadCursor( NULL, IDC_ARROW );
  228.            classStatus.style =        CS_HREDRAW | CS_VREDRAW;
  229.            classStatus.lpfnWndProc =  StatusWndFn;
  230.            classStatus.hInstance =    hCrntInst;
  231.            classStatus.hbrBackground =(HBRUSH)(COLOR_WINDOW + 1);
  232.  
  233.            /* define client class */
  234.            memset( &classClient, 0, sizeof(WNDCLASS) );
  235.            classClient.lpszClassName =(LPSTR)"ViewerClient";
  236.            classClient.hCursor =      LoadCursor( NULL, IDC_ARROW );
  237.            classClient.style =        CS_HREDRAW | CS_VREDRAW;
  238.            classClient.lpfnWndProc =  ClientWndFn;
  239.            classClient.hInstance =    hCrntInst;
  240.            classClient.hbrBackground =(HBRUSH)(COLOR_APPWORKSPACE+1);
  241.  
  242.          /* register classes if no previous instance */
  243.          if ( (hPrevInst) ||
  244.               (RegisterClass(&classStatus) &&
  245.                RegisterClass(&classClient))
  246.             ) {
  247.  
  248.            /* create child windows */
  249.              hWndSizebox = CreateWindow(
  250.                                          "Scrollbar",
  251.                                          "",
  252.                                          WS_CHILD|SBS_SIZEBOX,
  253.                                          CW_USEDEFAULT,
  254.                                          CW_USEDEFAULT,
  255.                                          CW_USEDEFAULT,
  256.                                          CW_USEDEFAULT,
  257.                                          hWnd,
  258.                                          (HMENU)ID_SIZEBOX,
  259.                                          hCrntInst,
  260.                                          (LPSTR)(DWORD)hPrevInst
  261.                                         );
  262.  
  263.              hWndClient = CreateWindow(
  264.                                         "ViewerClient",
  265.                                         "",
  266.                                         WS_CHILD|WS_BORDER|
  267.                                         WS_HSCROLL|WS_VSCROLL|
  268.                                         WS_CLIPSIBLINGS,
  269.                                         CW_USEDEFAULT,
  270.                                         CW_USEDEFAULT,
  271.                                         CW_USEDEFAULT,
  272.                                         CW_USEDEFAULT,
  273.                                         hWnd,
  274.                                         (HMENU)ID_CLIENT,
  275.                                         hCrntInst,
  276.                                         (LPSTR)(DWORD)hPrevInst
  277.                                       );
  278.  
  279.            hWndStatus = CreateWindow(
  280.                                      "ViewerStatus",
  281.                                      "",
  282.                                      WS_CHILD|WS_BORDER|
  283.                                      WS_CLIPSIBLINGS,
  284.                                      CW_USEDEFAULT,
  285.                                      CW_USEDEFAULT,
  286.                                      CW_USEDEFAULT,
  287.                                      CW_USEDEFAULT,
  288.                                      hWnd,
  289.                                      (HMENU)ID_STATUS,
  290.                                      hCrntInst,
  291.                                      (LPSTR)(DWORD)hPrevInst
  292.                                     );
  293.  
  294.            /* continue if successful */
  295.            if ( hWndStatus && hWndClient && hWndSizebox ) {
  296.  
  297.              /* update property lists */
  298.              SetProp( hWnd, HWNDSTATUS, hWndStatus );
  299.              SetProp( hWnd, HWNDCLIENT, hWndClient );
  300.              SetProp( hWnd, HWNDSIZEBOX, hWndSizebox );
  301.  
  302.              SetProp( hWnd, CBCHAIN, SetClipboardViewer(hWnd) );
  303.  
  304.              /* make child windows visible */
  305.                ShowWindow( hWndStatus, SW_SHOWNA );
  306.                ShowWindow( hWndClient, SW_SHOWNA );
  307.                ShowWindow( hWndSizebox, SW_SHOWNA );
  308.  
  309.            } else {
  310.                  WARNING( hWnd, "Unable to create child windows!" );
  311.              PostQuitMessage( 4 );
  312.            }
  313.  
  314.          } else {
  315.                WARNING( hWnd, "Unable to register child windows!" );
  316.            PostQuitMessage( 3 );
  317.          }
  318.  
  319.        } else {
  320.          WARNING( hWnd, "Unable to access instance data!" );
  321.          PostQuitMessage( 2 );
  322.        }
  323.      } else {
  324.        WARNING( hWnd, "Insufficient memory!" );
  325.        PostQuitMessage( 1 );
  326.      }
  327.  
  328.    }
  329.    break;
  330.  case WM_GETMINMAXINFO : /* retrieve window size constraints */
  331.  
  332.    /* set minimum tracking size */
  333.    ((LPPOINT)lParam)[3].x = 22 * GetSystemMetrics(SM_CXVSCROLL);
  334.    ((LPPOINT)lParam)[3].y = 10 * GetSystemMetrics(SM_CYCAPTION);
  335.  
  336.    break;
  337.  case WM_INITMENU : /* initialize menu */
  338.    {
  339.      LPLIBRARY     lpLibrary;
  340.  
  341.      /* check status window visibility */
  342.      CheckMenuItem(
  343.        wParam,
  344.        IDM_STATUS,
  345.        IsWindowVisible(GetProp(hWnd,HWNDSTATUS)) ?
  346.                        MF_CHECKED : MF_UNCHECKED
  347.      );
  348.  
  349.      /* enable-disable format library menu options */
  350.      lpLibrary = (LPLIBRARY)GlobalLock( GetProp(hWnd,CBLIBRARY) );
  351.      if ( lpLibrary ) {
  352.        EnableMenuItem(wParam,IDM_ADDFMT,(lpLibrary->wModules <
  353.                       MAX_MODULE) ? MF_ENABLED : MF_GRAYED );
  354.        EnableMenuItem(wParam,IDM_REMFMT,(lpLibrary->wModules) ?
  355.                       MF_ENABLED : MF_GRAYED );
  356.        GlobalUnlock( GetProp(hWnd,CBLIBRARY) );
  357.      } else
  358.        WARNING( hWnd, "Unable to access instance data!" );
  359.  
  360.      /* enable-disable erase menu option */
  361.      EnableMenuItem( wParam, IDM_ERASE, (GetProp(hWnd,CBFORMAT) >
  362.                      IDM_FORMATS) ? MF_ENABLED : MF_GRAYED );
  363.  
  364.    }
  365.    break;
  366.  case WM_COMMAND : /* menu command */
  367.  
  368.    /* process sub-message */
  369.    switch( wParam )
  370.      {
  371.    case IDM_STATUS : /* toggle status bar visibility */
  372.      {
  373.        RECT    rcClient;
  374.  
  375.        /* change status bar visibility */
  376.        ShowWindow(
  377.          GetProp(hWnd,HWNDSTATUS),
  378.          IsWindowVisible(
  379.             GetProp(hWnd,HWNDSTATUS)) ? SW_HIDE : SW_SHOWNA
  380.        );
  381.  
  382.        /* force resizing of child windows */
  383.        GetClientRect( hWnd, &rcClient );
  384.        SendMessage( hWnd, WM_SIZE, 0,
  385.                     MAKELONG(rcClient.right,rcClient.bottom) );
  386.  
  387.      }
  388.      break;
  389.    case IDM_EXIT : /* exit application */
  390.        PostQuitMessage( 0 );
  391.      break;
  392.    case IDM_ABOUT : /* about viewer */
  393.      Dialog( hWnd, "ViewerAbout", AboutDlgFn );
  394.      break;
  395.    case IDM_ADDFMT : /* add a new clipboard format */
  396.      Dialog( hWnd, "ViewerAdd", AddFormatDlgFn );
  397.      break;
  398.    case IDM_REMFMT : /* remove a clipboard format */
  399.      Dialog( hWnd, "ViewerRemove", RemFormatDlgFn );
  400.      break;
  401.    case IDM_ERASE : /* erase clipboard contents */
  402.  
  403.      /* verify option */
  404.      if ( MessageBox(hWnd,"Erase clipboard contents?",
  405.                      "Clipboard Viewer",
  406.                      MB_ICONQUESTION|MB_YESNO) == IDYES ) {
  407.        if ( OpenClipboard(hWnd) ) {
  408.          EmptyClipboard();
  409.          CloseClipboard();
  410.        } else
  411.          WARNING( hWnd, "Unable to open clipboard!" );
  412.      }
  413.  
  414.      break;
  415.    default : /* one of the selected formats */
  416.  
  417.      /* open clipboard */
  418.      if ( OpenClipboard(hWnd) ) {
  419.  
  420.        WORD      wCrntFmt;
  421.        HANDLE    hCrntData;
  422.        HANDLE    hCrntModule;
  423.  
  424.        /* attempt to retrieve clipboard data - semaphore call */
  425.        wCrntFmt = wParam - IDM_FORMATS;
  426.        if ( wCrntFmt ) {
  427.          SetProp( hWnd, CBGETDATA, TRUE );
  428.          hCrntData = GetClipboardData( wCrntFmt );
  429.          hCrntModule = GetClipboardModule( wCrntFmt,
  430.                                            GetProp(hWnd,CBLIBRARY) );
  431.          SetProp( hWnd, CBGETDATA, NULL );
  432.          if ( hCrntData == NULL )
  433.            WARNING( hWnd, "Unable to retrieve clipboard data!" );
  434.        } else {
  435.          hCrntData = NULL;
  436.          hCrntModule = NULL;
  437.        }
  438.  
  439.        /* close clipboard */
  440.        CloseClipboard();
  441.  
  442.        /* update checked menu item - even if data inaccessible */
  443.        CheckMenuItem( GetMenu(hWnd), GetProp(hWnd,CBFORMAT),
  444.                       MF_UNCHECKED );
  445.        SetProp( hWnd, CBFORMAT, wParam );
  446.        CheckMenuItem( GetMenu(hWnd), wParam, MF_CHECKED );
  447.  
  448.        /* notify child windows - note that clipboard is now closed */
  449.        SendMessage( GetProp(hWnd,HWNDSTATUS), WM_UPDATE, wCrntFmt,
  450.                     MAKELONG(hCrntData,hCrntModule) );
  451.        SendMessage( GetProp(hWnd,HWNDCLIENT), WM_UPDATE, wCrntFmt,
  452.                     MAKELONG(hCrntData,hCrntModule) );
  453.  
  454.      } else
  455.        WARNING( hWnd, "Unable to open clipboard!" );
  456.  
  457.      break;
  458.    }
  459.  
  460.    break;
  461.  case WM_ADDFMT : /* add a new clipboard library */
  462.    {
  463.      WORD        wEntry;
  464.      HANDLE      hFmtLib;
  465.      HANDLE      hOldLib;
  466.      LPLIBRARY   lpLibrary;
  467.      char        szFmt[64];
  468.      char        szLib[64];
  469.      char        szMsg[80];
  470.  
  471.      /* copy name of library */
  472.      lstrcpy( szLib, (LPSTR)lParam );
  473.  
  474.      /* lock down instance data */
  475.      lpLibrary = (LPLIBRARY)GlobalLock( GetProp(hWnd,CBLIBRARY) );
  476.      if ( lpLibrary ) {
  477.  
  478.        /* define clipboard format name */
  479.        GetClipboardFmtName( wParam, szFmt, sizeof(szFmt), FALSE );
  480.  
  481.        /* check to see if format already listed */
  482.        for (wEntry=0;
  483.             (wEntry<lpLibrary->wModules)&&
  484.             (wParam!=lpLibrary->Module[wEntry].wFormat); wEntry++ );
  485.        if ( wEntry < lpLibrary->wModules ) {
  486.  
  487.          /* entry already present - ask if replace? */
  488.          GetModuleFileName( lpLibrary->Module[wEntry].hModule,
  489.                             szLib, sizeof(szLib) );
  490.          sprintf( szMsg, "Replace %s?", szLib );
  491.          if ( MessageBox(hWnd,szMsg,"Clipboard Viewer",
  492.                          MB_ICONQUESTION|MB_YESNO) == IDYES ) {
  493.            hFmtLib = LoadLibrary( (LPSTR)lParam );
  494.            if ( hFmtLib >= 32 ) {
  495.              lResult = TRUE;
  496.              hOldLib = lpLibrary->Module[wEntry].hModule;
  497.              lpLibrary->Module[wEntry].hModule = hFmtLib;
  498.              SendMessage( hWnd, WM_COMMAND, GetProp(hWnd,CBFORMAT),
  499.                           0L );
  500.              WriteProfileString( "Clipboard", szFmt, szLib );
  501.              FreeLibrary( hOldLib );
  502.            }
  503.          }
  504.  
  505.        } else {
  506.  
  507.          /* check if space available internally */
  508.          if ( lpLibrary->wModules < MAX_MODULE ) {
  509.            hFmtLib = LoadLibrary( (LPSTR)lParam );
  510.            if ( hFmtLib >= 32 ) {
  511.              lResult = TRUE;
  512.              lpLibrary->Module[lpLibrary->wModules].hModule=hFmtLib;
  513.              lpLibrary->Module[lpLibrary->wModules++].wFormat =
  514.                 wParam;
  515.              SendMessage( hWnd, WM_COMMAND, GetProp(hWnd,CBFORMAT),
  516.                           0L );
  517.              WriteProfileString("Clipboard", szFmt, (LPSTR)lParam );
  518.            }
  519.          } else
  520.            WARNING( hWnd, "Insufficient memory to add library!" );
  521.  
  522.        }
  523.  
  524.        /* unlock library data */
  525.        GlobalUnlock( GetProp(hWnd,CBLIBRARY) );
  526.  
  527.      } else
  528.        WARNING( hWnd, "Unable to access instance data!" );
  529.    }
  530.    break;
  531.  case WM_GETFMT : /* retrieve clipboard format list */
  532.    {
  533.      LPSTR       lpStr;
  534.      WORD        wEntry;
  535.      LPLIBRARY   lpLibrary;
  536.      char        szFmt[64];
  537.      char        szLib[80];
  538.      char        szEntry[128];
  539.  
  540.      /* lock down instance data */
  541.      lpLibrary = (LPLIBRARY)GlobalLock( GetProp(hWnd,CBLIBRARY) );
  542.      if ( lpLibrary ) {
  543.        lpStr = (LPSTR)lParam;
  544.        lResult = lpLibrary->wModules;
  545.        for (wEntry=0; wEntry<lpLibrary->wModules; wEntry++) {
  546.          GetClipboardFmtName( lpLibrary->Module[wEntry].wFormat,
  547.                               szFmt, sizeof(szFmt), FALSE );
  548.          GetModuleFileName( lpLibrary->Module[wEntry].hModule,
  549.                             szLib, sizeof(szLib) );
  550.          sprintf( szEntry, "%s - %s", szFmt, szLib );
  551.          lstrcpy( lpStr, szEntry );
  552.          lpStr += strlen(szEntry) + 1;
  553.        }
  554.        lstrcpy( lpStr, "" );
  555.        GlobalUnlock( GetProp(hWnd,CBLIBRARY) );
  556.      } else
  557.        WARNING( hWnd, "Unable to access instance data!" );
  558.  
  559.    }
  560.    break;
  561.  case WM_REMFMT : /* remove a listed clipboard library */
  562.    {
  563.      HANDLE      hOldLib;
  564.      LPLIBRARY   lpLibrary;
  565.      char        szFmt[64];
  566.  
  567.      /* lock down instance data & remove library module */
  568.      lpLibrary = (LPLIBRARY)GlobalLock( GetProp(hWnd,CBLIBRARY) );
  569.      if ( lpLibrary ) {
  570.        if ( wParam < lpLibrary->wModules ) {
  571.          lResult = TRUE;
  572.          hOldLib = lpLibrary->Module[wParam].hModule;
  573.          GetClipboardFmtName( lpLibrary->Module[wParam].wFormat,
  574.                               szFmt, sizeof(szFmt), FALSE );
  575.          while ( ++wParam < lpLibrary->wModules ) {
  576.            lpLibrary->Module[wParam-1].wFormat =
  577.                               lpLibrary->Module[wParam].wFormat;
  578.            lpLibrary->Module[wParam-1].hModule =
  579.                               lpLibrary->Module[wParam].hModule;
  580.          }
  581.          lpLibrary->wModules--;
  582.          SendMessage( hWnd, WM_COMMAND, GetProp(hWnd,CBFORMAT), 0L );
  583.          WriteProfileString( "Clipboard", szFmt, "" );
  584.          FreeLibrary( hOldLib );
  585.        } else
  586.          WARNING( hWnd, "Attempt to remove invalid library!" );
  587.        GlobalUnlock( GetProp(hWnd,CBLIBRARY) );
  588.      } else
  589.        WARNING( hWnd, "Unable to access instance data!" );
  590.  
  591.    }
  592.    break;
  593.  case WM_SIZE : /* window being resized */
  594.  
  595.    /* reposition status window (even if invisible) */
  596.    MoveWindow(
  597.      GetProp(hWnd,HWNDSTATUS),
  598.      -1,
  599.      -1,
  600.      LOWORD(lParam)+2,
  601.      GetSystemMetrics(SM_CYMENU)+2,
  602.      TRUE
  603.    );
  604.  
  605.    /* reposition client window (always visible) */
  606.    MoveWindow(
  607.               GetProp(hWnd,HWNDCLIENT),
  608.               -1,
  609.               (IsWindowVisible(GetProp(hWnd,HWNDSTATUS))) ?
  610.                 GetSystemMetrics(SM_CYMENU) : -1,
  611.               LOWORD(lParam)+2,
  612.               (IsWindowVisible(GetProp(hWnd,HWNDSTATUS))) ?
  613.               HIWORD(lParam)-GetSystemMetrics(SM_CYMENU)+1 :
  614.                 HIWORD(lParam)+2,
  615.               TRUE
  616.    );
  617.  
  618.    /* reposition sizebox window (always visible) */
  619.    MoveWindow(
  620.               GetProp(hWnd,HWNDSIZEBOX),
  621.               LOWORD(lParam)-GetSystemMetrics(SM_CXVSCROLL)+1,
  622.               HIWORD(lParam)-GetSystemMetrics(SM_CYHSCROLL)+1,
  623.               GetSystemMetrics(SM_CXVSCROLL),
  624.               GetSystemMetrics(SM_CYHSCROLL),
  625.               TRUE
  626.    );
  627.  
  628.    break;
  629.  case WM_DRAWCLIPBOARD : /* clipboard contents changing */
  630.    {
  631.      HMENU       hSubMenu;
  632.      WORD        wCrntFmt;
  633.      WORD        wCrntEntry;
  634.      HANDLE      hCrntData;
  635.      HANDLE      hCrntModule;
  636.      char        szFmtName[48];
  637.      char        szMenuName[48];
  638.  
  639.      /* filter out spurious WM_DRAWCLIPBOARD messages */
  640.      if ( GetProp(hWnd,CBGETDATA) == NULL ) {
  641.  
  642.        /* pass the message down the chain first */
  643.        if ( GetProp(hWnd,CBCHAIN) )
  644.          SendMessage( GetProp(hWnd,CBCHAIN), wMsg, wParam, lParam );
  645.  
  646.        /* retrieve handle to view sub-menu */
  647.        hSubMenu = GetSubMenu( GetMenu(hWnd), 1 );
  648.  
  649.        /* remove old clipboard formats */
  650.        SetProp( hWnd, CBFORMAT, IDM_FORMATS );
  651.        for ( wCrntEntry = GetMenuItemCount(hSubMenu)-1; wCrntEntry>1;
  652.              wCrntEntry-- )
  653.          ChangeMenu(
  654.              hSubMenu,
  655.              wCrntEntry,
  656.              (wCrntEntry>2) ? NULL : "&1. (Empty)",
  657.              (wCrntEntry>2) ? NULL : IDM_FORMATS,
  658.              (wCrntEntry>2) ? MF_DELETE|MF_BYPOSITION :
  659.                               MF_CHANGE|MF_GRAYED|MF_BYPOSITION
  660.            );
  661.  
  662.        /* open clipboard */
  663.        if ( OpenClipboard(hWnd) ) {
  664.  
  665.          /* enumerate available clipboard formats */
  666.          wCrntEntry = 0;
  667.          hCrntModule = NULL;
  668.          wCrntFmt = EnumClipboardFormats( NULL );
  669.  
  670.          while ( wCrntFmt ) {
  671.  
  672.            /* define new menu entry */
  673.            GetClipboardFmtName( wCrntFmt, szFmtName,
  674.                                 sizeof(szFmtName), TRUE );
  675.            sprintf( szMenuName, "&%u. %s", wCrntEntry+1,
  676.                     (szFmtName[0]) ? szFmtName : "Undefined" );
  677.  
  678.            /* update view menu */
  679.            ChangeMenu(
  680.              hSubMenu,
  681.              (wCrntEntry) ? NULL : IDM_FORMATS,
  682.              szMenuName,
  683.              IDM_FORMATS + wCrntFmt,
  684.              (wCrntEntry) ? MF_APPEND : MF_CHANGE
  685.            );
  686.  
  687.            /* define selected format */
  688.            if ( hCrntModule == NULL ) {
  689.              SetProp( hWnd, CBFORMAT, IDM_FORMATS+wCrntFmt );
  690.              hCrntModule=GetClipboardModule(wCrntFmt,
  691.                                             GetProp(hWnd,CBLIBRARY));
  692.            }
  693.  
  694.            /* retrieve next available format */
  695.            wCrntEntry++;
  696.            wCrntFmt = EnumClipboardFormats( wCrntFmt );
  697.  
  698.          }
  699.  
  700.          /* attempt to retrieve data handle - semaphore call */
  701.          wCrntFmt = GetProp(hWnd,CBFORMAT) - IDM_FORMATS;
  702.          if ( wCrntFmt ) {
  703.            SetProp( hWnd, CBGETDATA, TRUE );
  704.            hCrntData = GetClipboardData( wCrntFmt );
  705.            SetProp( hWnd, CBGETDATA, NULL );
  706.          } else {
  707.            hCrntData = NULL;
  708.            hCrntModule = NULL;
  709.          }
  710.  
  711.          /* close clipboard */
  712.          CloseClipboard();
  713.  
  714.          /* mark selected format */
  715.          CheckMenuItem(hSubMenu, GetProp(hWnd,CBFORMAT), MF_CHECKED);
  716.  
  717.          /* notify child windows - clipboard now closed */
  718.          SendMessage( GetProp(hWnd,HWNDSTATUS), WM_UPDATE, wCrntFmt,
  719.                       MAKELONG(hCrntData,hCrntModule) );
  720.          SendMessage( GetProp(hWnd,HWNDCLIENT), WM_UPDATE, wCrntFmt,
  721.                       MAKELONG(hCrntData,hCrntModule) );
  722.  
  723.        } else
  724.          WARNING( hWnd, "Unable to open clipboard!" );
  725.  
  726.      }
  727.  
  728.    }
  729.    break;
  730.  case WM_CHANGECBCHAIN : /* clipboard viewer chain being changed */
  731.  
  732.    /* re-link viewer chain */
  733.    if ( wParam == GetProp(hWnd,CBCHAIN) )
  734.      SetProp( hWnd, CBCHAIN, LOWORD(lParam) );
  735.    else
  736.      if ( GetProp(hWnd,CBCHAIN) )
  737.        SendMessage( GetProp(hWnd,CBCHAIN), wMsg, wParam, lParam );
  738.  
  739.    break;
  740.    case WM_DESTROY : /* destroy window */
  741.    {
  742.      WORD        wEntry;
  743.      LPLIBRARY   lpLibrary;
  744.  
  745.      /* retrieve & lock module library */
  746.      lpLibrary = (LPLIBRARY)GlobalLock( GetProp(hWnd,CBLIBRARY) );
  747.      if ( lpLibrary ) {
  748.  
  749.        /* free each listed library */
  750.        for ( wEntry=0; wEntry<lpLibrary->wModules; wEntry++ )
  751.          FreeLibrary( lpLibrary->Module[wEntry].hModule );
  752.  
  753.        /* unlock data structure */
  754.        GlobalUnlock( GetProp(hWnd,CBLIBRARY) );
  755.  
  756.      }
  757.  
  758.      /* free allocated memory & unlink from clipboard chain */
  759.      GlobalFree( RemoveProp(hWnd,CBLIBRARY) );
  760.      ChangeClipboardChain( hWnd, RemoveProp(hWnd,CBCHAIN) );
  761.  
  762.      /* remove remaining properties */
  763.      RemoveProp( hWnd, CBFORMAT );
  764.      RemoveProp( hWnd, CBGETDATA );
  765.      RemoveProp( hWnd, HWNDSTATUS );
  766.      RemoveProp( hWnd, HWNDCLIENT );
  767.      RemoveProp( hWnd, HWNDSIZEBOX );
  768.  
  769.      /* end it all */
  770.      PostQuitMessage( 0 );
  771.  
  772.    }
  773.    break;
  774.    default : /* send to default */
  775.       lResult = DefWindowProc( hWnd, wMsg, wParam, lParam );
  776.       break;
  777.    }
  778.  
  779.    /* return normal result */
  780.    return( lResult );
  781.  
  782. }
  783.  
  784.