home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: InfoMgt / InfoMgt.zip / shr93.zip / SHARE.C < prev    next >
Text File  |  1993-04-12  |  20KB  |  692 lines

  1. /*
  2.  * OS/2 Work Place Shell Sample Program - Common functions, 
  3.  *     DLL initialization, and global variable initialization.
  4.  *
  5.  * Copyright (C) 1993 IBM Corporation
  6.  *
  7.  *   DISCLAIMER OF WARRANTIES.  The following [enclosed] code is 
  8.  *   sample code created by IBM Corporation.  This sample code is 
  9.  *   not part of any standard or IBM product and is provided to you 
  10.  *   solely for the purpose of assisting you in the development of 
  11.  *   your applications.  The code is provided "AS IS".  ALL 
  12.  *   WARRANTIES ARE EXPRESSLY DISCLAIMED, INCLUDING THE IMPLIED 
  13.  *   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  14.  *   PURPOSE.  IBM shall not be liable for any damages arising out 
  15.  *   of your use of the sample code, even if IBM has been advised of 
  16.  *   the possibility of such damages.  
  17.  */
  18.  
  19. #define SOM_NoTest
  20.  
  21. #include "share.h"
  22. #include "person.h"
  23. #include "addrbk.h"
  24. #include "addrbkv.h"
  25. #include "notify.h"
  26. #include "somlist.h"
  27. #include "shrfoldr.h"
  28.  
  29. /*
  30.  * Read-only global strings.
  31.  */
  32.  
  33. CHAR vszShrPersonClass[] = "ShrPerson";
  34. CHAR vszShrAddressBookClass[] = "ShrAddressBook";
  35. CHAR vszAddressNotebook[] = "ShrAddressNotebook";
  36. CHAR vszNullString[1] = "";
  37. CHAR vszDesktopObjectId[] = "<WP_DESKTOP>";
  38. CHAR vszShrUnderstandsProtocol[] = "shrUnderstandsProtocol";
  39. CHAR vszDRMObject[] = "DRM_OBJECT";
  40. CHAR vszDRFObject[] = "DRF_OBJECT";
  41. CHAR vszWcFrameCnrOwner[] = "ShrFrameCnrOwner";
  42. CHAR vszwpModifyPopupMenu[] = "wpModifyPopupMenu";
  43. CHAR vszAppName[] = "ShrExample";
  44. CHAR vszIndexedViewWindowPosKeyName[] = "AddressBook:WindowPos";
  45.  
  46. /*
  47.  * Global MRI-related strings.
  48.  */
  49.  
  50. CHAR vszAddressBookTitle[CCHMINSTRING];
  51. CHAR vszPersonTitle[CCHMINSTRING];
  52. CHAR vszPersonInfoTab[CCHMINSTRING];
  53. CHAR vaszIndexTabs[CINDEXTABS][CCHMINSTRING];
  54. CHAR vaszIndexChars[CINDEXCHARS][CCHMINSTRING];
  55. CHAR vszAllIndexChars[CCHMINSTRING];
  56. CHAR vszAddressBookViewTitle[CCHMINSTRING];
  57. CHAR vszAddressBookCnrTitle[CCHMINSTRING];
  58. CHAR vszPersonNewTitle[CCHMINSTRING];
  59. CHAR vszAddress[CCHMINSTRING];
  60. CHAR vszCity[CCHMINSTRING];
  61. CHAR vszState[CCHMINSTRING];
  62. CHAR vszZipCode[CCHMINSTRING];
  63. CHAR vszPhone[CCHMINSTRING];
  64. CHAR vszDefaultAddress[CCHMINSTRING];
  65. CHAR vszDefaultCity[CCHMINSTRING]; 
  66. CHAR vszDefaultState[CCHMINSTRING]; 
  67. CHAR vszDefaultZipCode[CCHMINSTRING]; 
  68. CHAR vszDefaultPhone[CCHMINSTRING]; 
  69.  
  70. /*
  71.  * Global PM-related variables.
  72.  */
  73.  
  74. PFNWP vpfnDefaultFrameProc = NULL;
  75. PFNWP vpfnWPSCnrOwnerProc = NULL;
  76.  
  77. /*
  78.  * Global SOM-related variables.
  79.  */
  80.  
  81. somId vmidShrUnderstandsProtocol = 0;
  82.  
  83. /*
  84.  * ShrDefPageDlgProc is a simple dialog procedure which tosses
  85.  * WM_COMMAND's since the default dialog procedure dismisses 
  86.  * the dialog.  Dialogs which are used as pages in the Settings
  87.  * view notebook should use ShrDefPageDlgProc.
  88.  */
  89.  
  90. extern MRESULT EXPENTRY ShrDefPageDlgProc
  91.     (HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
  92. {
  93.   MRESULT mr = NULL;
  94.  
  95.   switch (msg)
  96.   {
  97.     case WM_COMMAND:
  98.       mr = NULL;
  99.       break;
  100.  
  101.     default:
  102.       mr = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  103.       break;
  104.   }
  105.  
  106.   return mr;
  107. }
  108.  
  109. /*
  110.  * ShrSetDlgEntryFieldText simply sets a dialog box's entry
  111.  * field and clears the entry field's changed bit.
  112.  */
  113.  
  114. extern VOID ShrSetDlgEntryFieldText
  115.     (HWND hwndDlg, ULONG id, PSZ psz)
  116. {
  117.   WinSetDlgItemText(hwndDlg, id, psz);
  118.   WinSendDlgItemMsg(hwndDlg, id, EM_QUERYCHANGED, NULL, NULL);
  119. }
  120.  
  121. /*
  122.  * ShrSetDlgMLEText simply sets a dialog box's multi-line
  123.  * entry field and clears the multi-line entry field's changed bit.
  124.  */
  125.  
  126. extern VOID ShrSetDlgMLEText
  127.     (HWND hwndDlg, ULONG id, PSZ psz)
  128. {
  129.   ULONG ulOffset, ulCopy;
  130.   HWND hwndMLE;
  131.  
  132.   hwndMLE = WinWindowFromID(hwndDlg, id);
  133.  
  134.   /*
  135.    * Start by clearing out of the MLE what was there before.
  136.    */
  137.  
  138.   WinSendMsg(hwndMLE, MLM_SETSEL, MPFROMLONG(0),
  139.       MPFROMLONG(WinSendMsg(hwndMLE, MLM_QUERYTEXTLENGTH, 0, 0)));
  140.   WinSendMsg(hwndMLE, MLM_CLEAR, NULL, NULL);
  141.  
  142.   /*
  143.    * Define the import buffer address and length.
  144.    */
  145.  
  146.   ulCopy = strlen(psz);
  147.   WinSendMsg(hwndMLE, MLM_SETIMPORTEXPORT,
  148.       MPFROMP(psz), MPFROMLONG(ulCopy));
  149.  
  150.   /*
  151.    * Import the text and clear the changed bit.
  152.    */
  153.  
  154.   ulOffset = 0;
  155.   WinSendMsg(hwndMLE, MLM_IMPORT,
  156.       &ulOffset, MPFROMLONG(ulCopy));
  157.   
  158.   WinSendMsg(hwndMLE, MLM_SETCHANGED,
  159.       MPFROMLONG(FALSE), NULL);
  160. }
  161.  
  162. /*
  163.  * ShrFrameCnrOwnerWndProc is only necessary to work around
  164.  * a bug in the WPS.
  165.  *
  166.  * A hang results if an object is inserted with wpCnrInsertObject
  167.  * is then deleted from another open view.
  168.  *
  169.  * This bug has been reported to Boca (PMR 3x053).
  170.  */
  171.  
  172. extern MRESULT EXPENTRY ShrFrameCnrOwnerWndProc
  173.     (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  174. {
  175.   if (!ShrCheckForDeletedObject(hwnd, msg, mp1, mp2))
  176.     return ShrDefFrameProc(hwnd, msg, mp1, mp2);
  177.   else
  178.     return NULL;
  179. }
  180.  
  181. /*
  182.  * ShrSetObjectString sets an object's instance data string and
  183.  * notifies interested windows.
  184.  */
  185.  
  186. extern BOOL ShrSetObjectString
  187.     (SOMAny *somObject, PSZ pszNew, PSZ *ppszOld, ULONG ulChangeMsg)
  188. {
  189.   BOOL bHoldingSem = FALSE;
  190.   PSZ psz = NULL;
  191.  
  192.   /*
  193.    * NOTE!  It is very important that exception handlers be coded in 
  194.    * routines that request mutex semaphores!  The exception condition
  195.    * should relinquish the semaphore if it was successfully
  196.    * requested.  Otherwise, later requestors of the semaphore could
  197.    * wait indefinitely, typically resulting in a hang of one of the
  198.    * WPS threads or the entire WPS.
  199.    *
  200.    * ShrStartTryBlock is a macro that installs an exception
  201.    * handler for this function.  See SHARE.H for more details.
  202.    */
  203.  
  204.   ShrStartTryBlock;
  205.  
  206.   bHoldingSem = !_wpRequestObjectMutexSem(somObject, 
  207.       SEM_INDEFINITE_WAIT);
  208.  
  209.   if (bHoldingSem)
  210.   {
  211.     psz = _wpAllocMem(somObject, strlen(pszNew)+1, NULL);
  212.   
  213.     if (psz)
  214.     {
  215.       strcpy(psz, pszNew);
  216.   
  217.       if (*ppszOld)
  218.         _wpFreeMem(somObject, *ppszOld);
  219.   
  220.       *ppszOld = psz;
  221.   
  222.   
  223.       _wpSaveDeferred(somObject);
  224.     }
  225.  
  226.     /*
  227.      * Let's notify interested windows AFTER releasing the
  228.      * object's semaphore because the notified windows
  229.      * may want to acquire it. 
  230.      */
  231.  
  232.     bHoldingSem = _wpReleaseObjectMutexSem(somObject);
  233.  
  234.     if (psz)
  235.       _shrNotifyInterestedWindows(_shrQueryNotifier(somObject),
  236.           somObject, ulChangeMsg, somObject, psz);
  237.   }
  238.  
  239.   ShrEndTryBlock;
  240.   return BOOLFROMP(psz);
  241.  
  242.   /*
  243.    * Exception handling code for this function goes here.
  244.    */
  245.  
  246. OnException:
  247.   if (bHoldingSem)
  248.     bHoldingSem = _wpReleaseObjectMutexSem(somObject);
  249.  
  250.   ShrEndTryBlock;
  251.   return FALSE;
  252. }
  253.  
  254. /*
  255.  * ShrQueryObjectString returns an object's instance data string.
  256.  */
  257.  
  258. extern ULONG ShrQueryObjectString
  259.     (SOMAny *somObject, PSZ pszReturn, PSZ *ppsz, PSZ pszDefault)
  260. {
  261.   BOOL bHoldingSem = FALSE;
  262.   ULONG cch = 1;
  263.   PSZ pszCopy;
  264.  
  265.   /*
  266.    * NOTE!  It is very important that exception handlers be coded in 
  267.    * routines that request mutex semaphores!  The exception condition
  268.    * should relinquish the semaphore if it was successfully
  269.    * requested.  Otherwise, later requestors of the semaphore could
  270.    * wait indefinitely, typically resulting in a hang of one of the
  271.    * WPS threads or the entire WPS.
  272.    *
  273.    * ShrStartTryBlock is a macro that installs an exception
  274.    * handler for this function.  See SHARE.H for more details.
  275.    */
  276.  
  277.   ShrStartTryBlock;
  278.  
  279.   bHoldingSem = !_wpRequestObjectMutexSem(somObject, 
  280.       SEM_INDEFINITE_WAIT);
  281.  
  282.   if (bHoldingSem)
  283.   {
  284.     if (*ppsz)
  285.       pszCopy = *ppsz;
  286.     else
  287.       pszCopy = pszDefault;
  288.   
  289.     if (pszCopy)
  290.       cch += strlen(pszCopy);
  291.   
  292.     if (pszReturn)
  293.       if (cch > 1)
  294.         memcpy(pszReturn, pszCopy, cch);
  295.       else
  296.         pszReturn[0] = NULLCHAR;
  297.  
  298.     bHoldingSem = _wpReleaseObjectMutexSem(somObject);
  299.   }
  300.  
  301.   ShrEndTryBlock;
  302.   return cch;
  303.  
  304.   /*
  305.    * Exception handling code for this function goes here.
  306.    */
  307.  
  308. OnException:
  309.   if (bHoldingSem)
  310.     bHoldingSem = _wpReleaseObjectMutexSem(somObject);
  311.  
  312.   ShrEndTryBlock;
  313.   return 0;
  314. }
  315.  
  316. /*
  317.  * ShrEmptyObjectCnr empties an object container before 
  318.  * it is destroyed.
  319.  *
  320.  * WARNING: Remove all the WPS object container records from
  321.  * the container before closing (otherwise the default container 
  322.  * destroy action is to free the records, which throughly screws
  323.  * up WPS since its records are shared).
  324.  */
  325.  
  326. extern VOID ShrEmptyObjectCnr(HWND hwndCnr)
  327. {
  328.   PMINIRECORDCORE pMiniRecord, pNextMiniRecord;
  329.  
  330.   pMiniRecord = (PMINIRECORDCORE)
  331.       WinSendMsg(hwndCnr, CM_QUERYRECORD, MPFROMLONG(CMA_FIRST),
  332.       MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
  333.  
  334.   while (pMiniRecord)
  335.   {
  336.     /*
  337.      * Note when removing records from a container you should
  338.      * get the next record FIRST because the current record
  339.      * will no longer be valid.
  340.      */
  341.  
  342.     pNextMiniRecord = (PMINIRECORDCORE)
  343.         WinSendMsg(hwndCnr, CM_QUERYRECORD, MPFROMP(pMiniRecord),
  344.         MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
  345.     _wpCnrRemoveObject(OBJECT_FROM_PREC(pMiniRecord), hwndCnr);
  346.  
  347.     pMiniRecord = pNextMiniRecord;
  348.   }
  349. }
  350.  
  351. /*
  352.  * ShrOpeningView handles the mundane task of preparing a
  353.  * new view for its introduction to WPS.
  354.  */
  355.  
  356. extern BOOL ShrOpeningView
  357.     (SOMAny *somSelf, HWND hwndFrame, ULONG ulView, PSZ pszViewTitle)
  358. {
  359.   PUSEITEM pUseItem = NULL;
  360.   BOOL bSuccess = FALSE;
  361.  
  362.   /*
  363.    * Note!
  364.    *
  365.    * When a view is registered with wpRegisterView, it
  366.    * is subclassed and its window procedure pointer saved
  367.    * in a reserved window words.  The WPS subclass window procedure 
  368.    * handles * all the CN_ messages for WPS object container records
  369.    * inserted into our contents container, along with the system 
  370.    * menu code to display the context menu, and a few WM_COMMAND 
  371.    * messages (delete, copy, move, etc).
  372.    *
  373.    * Save a pointer to the WPS subclass for later we want
  374.    * to resubclass so our window procedure is called first.
  375.    * See "Problem 1" in WPS-PGM.TXT for more details, and
  376.    * ADDRBKV.C for an example.
  377.    */
  378.  
  379.   bSuccess = _wpRegisterView(somSelf, hwndFrame, pszViewTitle);
  380.  
  381.   if (bSuccess)
  382.   {
  383.     vpfnWPSCnrOwnerProc = (PFNWP) WinQueryWindowPtr(hwndFrame, QWP_PFNWP);
  384.  
  385.     pUseItem = (PUSEITEM) _wpAllocMem(somSelf, sizeof(USEITEM)+
  386.         sizeof(VIEWITEM), NULL);
  387.     bSuccess = BOOLFROMP(pUseItem);
  388.   }
  389.  
  390.   if (bSuccess)
  391.   {
  392.     pUseItem->type = USAGE_OPENVIEW;
  393.     ((PVIEWITEM) (pUseItem+1))->handle = hwndFrame;
  394.     ((PVIEWITEM) (pUseItem+1))->view = ulView;
  395.  
  396.     /*
  397.      * The WPS will automatically add the "in-use" (hashed)
  398.      * emphasis to the object's icon when an USAGE_OPENVIEW
  399.      * use item is added to the object's use list.
  400.      */
  401.   
  402.     bSuccess = _wpAddToObjUseList(somSelf, pUseItem);
  403.   }
  404.  
  405.   /*
  406.    * If any of the above fails, free the memory for the use item 
  407.    * (if it was successfully allocated) since it will not be needed.
  408.    */
  409.  
  410.   if (!bSuccess && pUseItem)
  411.     _wpFreeMem(somSelf, (PBYTE) pUseItem);
  412.  
  413.   return bSuccess;
  414. }
  415.  
  416. /*
  417.  * ShrClosingView handles the mundane task of closing a view
  418.  * which is no longer needed.
  419.  */
  420.  
  421. extern BOOL ShrClosingView
  422.     (SOMAny *somSelf, HWND hwndFrame)
  423. {
  424.   PUSEITEM pUseItem;
  425.  
  426.   /*
  427.    * Each object has a "use list".  Each structure in the use item
  428.    * list is always followed immediately by a type dependant struct 
  429.    * such as MEMORYITEM, RECORDITEM, VIEWITEM or some other user 
  430.    * defined structure.
  431.    *
  432.    * We're interested in the USAGE_OPENVIEW use items.  They look like:
  433.    *
  434.    *   struct _USEITEM
  435.    *   {
  436.    *      ULONG           type;         // Type of this item
  437.    *      struct _USEITEM *pNext;       // Next item in use list
  438.    *   } USEITEM;
  439.    *  
  440.    * followed immediately in memory by:
  441.    *  
  442.    *   struct _VIEWITEM         
  443.    *   {
  444.    *      ULONG        view;            // Object view this represents
  445.    *      LHANDLE      handle;          // Open handle 
  446.    *      ULONG        ulViewState;     // View State flags
  447.    *      HWND         hwndCnr;         // System use only 
  448.    *      PMINIRECORDCORE pRecord;      // System use only 
  449.    *   } VIEWITEM;
  450.    *  
  451.    * Find the USAGE_OPENVIEW use item in the object's list and remove
  452.    * it.  If this is the last USAGE_OPENVIEW use item for this object,
  453.    * the WPS will automatically remove the "in-use" (hashed) emphasis 
  454.    * of the object's icon.
  455.    */
  456.  
  457.   pUseItem = _wpFindUseItem(somSelf, USAGE_OPENVIEW, NULL);
  458.   while (pUseItem && ((PVIEWITEM) (pUseItem+1))->handle != hwndFrame)
  459.     pUseItem = _wpFindUseItem(somSelf, USAGE_OPENVIEW, pUseItem);
  460.  
  461.   if (pUseItem)
  462.   {
  463.     _wpDeleteFromObjUseList(somSelf, pUseItem);
  464.     _wpFreeMem(somSelf, (PBYTE) pUseItem);
  465.   }
  466.  
  467.   return BOOLFROMP(pUseItem);
  468. }
  469.  
  470. /*
  471.  * SOM/WPS class initialization
  472.  *
  473.  * When a SOM class is registered, SOM first tries to call
  474.  * the default DLL entry point SOMInitModule.  It is here
  475.  * that we register all the SOM/WPS classes for this DLL.
  476.  *
  477.  * Note that if this module had no SOMInitModule export, SOM
  478.  * would try to call the NewClass entry point, eg, registering
  479.  * class "Animal" would cause AnimalNewClass to be called.
  480.  */
  481.  
  482. void _System SOMInitModule(ULONG ulMajor, ULONG ulMinor)
  483. {
  484.   /*
  485.    * Initialize SOM/WPS classes.
  486.    */
  487.  
  488.   ShrListNewClass(0,0);
  489.   ShrNotifierNewClass(0,0);
  490.   ShrFolderNewClass(0, 0);
  491.   ShrAddressBookNewClass(0, 0);
  492.   ShrPersonNewClass(0, 0);
  493.  
  494.   /*
  495.    * Protocols are used during drag operations to determine
  496.    * if the dragged objects will understand a set of messages.
  497.    * Below we initialize a SOM ID used in determining if
  498.    * a dragged object will respond to the "shrUnderstandsProtocol"
  499.    * API.
  500.    *
  501.    * While in this implementation, only ShrPerson responds to
  502.    * this message, other classes may be added later.  This
  503.    * technique is better than using _somIsA which presupposes
  504.    * a specific location in the class hierarchy.
  505.    */
  506.  
  507.   vmidShrUnderstandsProtocol = 
  508.       SOM_IdFromString(vszShrUnderstandsProtocol);
  509. }
  510.  
  511. /*
  512.  * DLL Initialization
  513.  *
  514.  * When the DLL is loaded or unloaded, this entry point
  515.  * will be called.  Initialize/terminate the C runtime
  516.  * environment (see page 234 of the "IBM C Set/2 User's
  517.  * Guide" for more details), and allocate/free global
  518.  * resources.
  519.  *
  520.  * Note: This routine is invoked before SOMInitModule.
  521.  */
  522.  
  523. int _CRT_init(void);
  524. int _CRT_term(void);
  525.  
  526. unsigned long _System _DLL_InitTerm
  527.     (unsigned long hmod, unsigned long ulFlag)
  528. {
  529.   CLASSINFO classInfo;
  530.   ULONG i;
  531.   BOOL bSuccess = TRUE;
  532.  
  533.   /*
  534.    * ulFlag is zero if the DLL is being loaded, and
  535.    * one if the DLL is being unloaded.
  536.    */
  537.  
  538.   if (ulFlag == 0)
  539.   {
  540.     /*
  541.      * Initialize the C Set/2 runtime.
  542.      */
  543.  
  544.     if (_CRT_init() == -1)
  545.       bSuccess = FALSE;
  546.  
  547.     /*
  548.      * Load the MRI strings into global string variables.
  549.      *
  550.      * We are being rather cavalier in assuming WinLoadString
  551.      * cannot fail, but it is a fairly safe bet because the
  552.      * MRI strings are attached to the DLL this code is executing,
  553.      * and the strings are stored in global memory that was
  554.      * allocated when the DLL was loaded.
  555.      */
  556.  
  557.     WinLoadString(NULLHANDLE, hmod,
  558.         IDS_PERSONINFOTAB, sizeof(vszPersonInfoTab),
  559.         vszPersonInfoTab);
  560.     WinLoadString(NULLHANDLE, hmod,
  561.         IDS_PERSONTITLE, sizeof(vszPersonTitle),
  562.         vszPersonTitle);
  563.     WinLoadString(NULLHANDLE, hmod,
  564.         IDS_ADDRESSBOOKTITLE, sizeof(vszAddressBookTitle),
  565.         vszAddressBookTitle);
  566.     WinLoadString(NULLHANDLE, hmod,
  567.         IDS_ADDRESSBOOKVIEWTITLE, sizeof(vszAddressBookViewTitle),
  568.         vszAddressBookViewTitle);
  569.     WinLoadString(NULLHANDLE, hmod,
  570.         IDS_INDEXCHARSALL, sizeof(vszAllIndexChars),
  571.         vszAllIndexChars);
  572.     WinLoadString(NULLHANDLE, hmod,
  573.         IDS_PERSONNEWTITLE, sizeof(vszPersonNewTitle),
  574.         vszPersonNewTitle);
  575.     WinLoadString(NULLHANDLE, hmod,
  576.         IDS_PHONE, sizeof(vszPhone), vszPhone);
  577.     WinLoadString(NULLHANDLE, hmod,
  578.         IDS_ADDRESS, sizeof(vszAddress), vszAddress);
  579.     WinLoadString(NULLHANDLE, hmod,
  580.         IDS_CITY, sizeof(vszCity), vszCity);
  581.     WinLoadString(NULLHANDLE, hmod,
  582.         IDS_STATE, sizeof(vszState), vszState);
  583.     WinLoadString(NULLHANDLE, hmod,
  584.         IDS_ZIPCODE, sizeof(vszZipCode), vszZipCode);
  585.     WinLoadString(NULLHANDLE, hmod,
  586.         IDS_DEFAULTPHONE, sizeof(vszDefaultPhone), vszDefaultPhone);
  587.     WinLoadString(NULLHANDLE, hmod,
  588.         IDS_DEFAULTADDRESS, sizeof(vszDefaultAddress), vszDefaultAddress);
  589.     WinLoadString(NULLHANDLE, hmod,
  590.         IDS_DEFAULTCITY, sizeof(vszDefaultCity), vszDefaultCity);
  591.     WinLoadString(NULLHANDLE, hmod,
  592.         IDS_DEFAULTSTATE, sizeof(vszDefaultState), vszDefaultState);
  593.     WinLoadString(NULLHANDLE, hmod,
  594.         IDS_DEFAULTZIPCODE, sizeof(vszDefaultZipCode), vszDefaultZipCode);
  595.  
  596.     /*
  597.      * Load the MRI strings for the tabs, "A - C", "D - F", ...
  598.      * "V - Z", and "Misc".
  599.      */
  600.   
  601.     for (i=0; i < CINDEXTABS; i++)
  602.       WinLoadString(NULLHANDLE, hmod,
  603.           i+IDS_FIRSTINDEXTAB, sizeof(vaszIndexTabs[i]),
  604.           vaszIndexTabs[i]);
  605.  
  606.     /*
  607.      * Load the MRI strings "ABC", "DEF", ... "VWXYZ"
  608.      * used for determining what objects are shown on each
  609.      * page (see ShrFilterAddressBookRecord in ADDRBKV.C).
  610.      */
  611.   
  612.     for (i=0; i < CINDEXCHARS; i++)
  613.       WinLoadString(NULLHANDLE, hmod,
  614.           i+IDS_FIRSTINDEXCHARS, sizeof(vaszIndexChars[i]),
  615.           vaszIndexChars[i]);
  616.   
  617.     /*
  618.      * Register private window classes.
  619.      */
  620.   
  621.     WinQueryClassInfo(NULLHANDLE, WC_FRAME, &classInfo);
  622.     vpfnDefaultFrameProc = classInfo.pfnWindowProc;
  623.   
  624.     WinRegisterClass(NULLHANDLE, vszWcFrameCnrOwner,
  625.         ShrFrameCnrOwnerWndProc,
  626.         ((classInfo.flClassStyle & ~CS_PUBLIC)),
  627.         classInfo.cbWindowData);
  628.   }
  629.   else if (ulFlag == 1)
  630.   {
  631.     /*
  632.      * Free resources allocated during DLL initialization.
  633.      */
  634.  
  635.     _CRT_term();
  636.  
  637.     /*
  638.      * Note we didn't have to free the MRI strings since
  639.      * they're stored in global string buffers that are
  640.      * freed when the DLL is unloaded.
  641.      *
  642.      * If we had allocated other resources, eg, memory,
  643.      * PM pointers, etc, we would check if they were
  644.      * allocated here and free them if necessary.
  645.      */
  646.   }
  647.  
  648.   return bSuccess;
  649. }
  650.  
  651. /*
  652.  * Exception handler that returns traps via longjmp().
  653.  */
  654.  
  655. extern ULONG APIENTRY ShrExceptionHandler
  656.     (PEXCEPTIONREPORTRECORD pReportRecord, 
  657.     PEXCEPTIONREGISTRATIONRECORD pRegRecord,
  658.     PCONTEXTRECORD pContextRecord, PVOID pReserved)
  659. {
  660.   /*
  661.    * The report record is set by the system exception handler
  662.    * to tell us what happen.  The exception registration record
  663.    * pointer points to the address on the stack of the registration
  664.    * record we passed to DosSetExceptionHandler.
  665.    *
  666.    * See the ShrStartTryBlock and ShrEndTryBlock macros in
  667.    * SHARE.H for more details.
  668.    */
  669.  
  670.   if (pReportRecord->ExceptionNum == XCPT_ACCESS_VIOLATION)
  671.   {
  672.     /*
  673.      * This long, ominous, beep will let the user know something
  674.      * is amiss.  Putting up a message box might be nice,
  675.      * but we'd need to check if we're running on a PM thread
  676.      * before doing that.
  677.      */
  678.  
  679.     DosBeep(200, 1500);
  680.  
  681.     longjmp(((PSHREXCEPTIONREGISTRATIONRECORD) pRegRecord)->env, -1);
  682.   }
  683.  
  684.   /* 
  685.    * If we return to here then we could not handle the exception.
  686.    * The next handler will be invoked (eg, to handle a guard page
  687.    * exception to grow the stack).
  688.    */
  689.  
  690.   return XCPT_CONTINUE_SEARCH;
  691. }
  692.