|
|
1.1 ! root 1: /* ! 2: * This module serves to demonstrate one way a sophisticated DDE server ! 3: * that uses enumerable topics and items might be implemented. It takes ! 4: * full advantage of appowned data handles (when fAppowned is set) to ! 5: * minimize the need for repeated rendering of data when shared with ! 6: * multiple clients. ! 7: * ! 8: * The server supports full system topic information plus help and non ! 9: * system topic item enumeration for the benefit of browsing clients ! 10: * that are wondering what's around. ! 11: * ! 12: * This server can be made secure by altering the conversation context ! 13: * filter. ! 14: * ! 15: * This server can appear to support alternate codepages and languages ! 16: * by altering the conversation context filter. On Windows this is ! 17: * pretty much moot since there is not yet a clearly defined way of ! 18: * doing international communication and because the atom manager restricts ! 19: * what topic and item strings can be used on the system. ! 20: */ ! 21: ! 22: #include <string.h> ! 23: #include <stdlib.h> ! 24: #include <stdio.h> ! 25: #include <memory.h> ! 26: #include "server.h" ! 27: #include "huge.h" ! 28: ! 29: /* ! 30: * This function verifies that the incomming conversation context fits the ! 31: * server's context filter's requirements. ! 32: */ ! 33: BOOL ValidateContext( ! 34: PCONVCONTEXT pCC) ! 35: { ! 36: // make sure our CCFilter allows it...mock security, language support ! 37: // old DDE app client case...pCC == NULL ! 38: if (pCC == NULL && ! 39: CCFilter.dwSecurity == 0 && // were nonsecure ! 40: CCFilter.iCodePage == CP_WINANSI // were normal cp ! 41: ) { ! 42: return(TRUE); ! 43: } ! 44: ! 45: if (pCC && ! 46: pCC->wFlags == CCFilter.wFlags && // no special flags needed ! 47: pCC->iCodePage == CCFilter.iCodePage && // codepages match ! 48: pCC->dwSecurity == CCFilter.dwSecurity) { // security passes ! 49: // dont care about language and country. ! 50: return(TRUE); ! 51: } ! 52: return(FALSE); // disallow no match ! 53: } ! 54: ! 55: ! 56: /***************************** Public Function ****************************\ ! 57: * ! 58: * This function is called by the DDE manager DLL and passes control onto ! 59: * the apropriate function pointed to by the global topic and item arrays. ! 60: * It handles all DDE interaction generated by external events. ! 61: * ! 62: \***************************************************************************/ ! 63: HDDEDATA CALLBACK DdeCallback( ! 64: WORD wType, ! 65: WORD wFmt, ! 66: HCONV hConv, ! 67: HSZ hszTopic, ! 68: HSZ hszItem, ! 69: HDDEDATA hData, ! 70: DWORD lData1, ! 71: DWORD lData2) ! 72: { ! 73: WORD i, j; ! 74: register ITEMLIST *pItemList; ! 75: WORD cItems, iFmt; ! 76: HDDEDATA hDataRet; ! 77: ! 78: /* ! 79: * Block this callback if its blockable and we are supposed to. ! 80: */ ! 81: if (fBlockNextCB && !(wType & XTYPF_NOBLOCK)) { ! 82: fBlockNextCB = FALSE; ! 83: fAllEnabled = FALSE; ! 84: return(CBR_BLOCK); ! 85: } ! 86: ! 87: /* ! 88: * Block this callback if its associated with a conversation and we ! 89: * are supposed to. ! 90: */ ! 91: if (fTermNextCB && hConv) { ! 92: fTermNextCB = FALSE; ! 93: DdeDisconnect(hConv); ! 94: wType = XTYP_DISCONNECT; ! 95: } ! 96: ! 97: /* ! 98: * Keep a count of connections ! 99: */ ! 100: if (wType == XTYP_CONNECT_CONFIRM) { ! 101: cServers++; ! 102: InvalidateRect(hwndServer, &rcConnCount, TRUE); ! 103: return(0); ! 104: } ! 105: if (wType == XTYP_DISCONNECT) { ! 106: cServers--; ! 107: InvalidateRect(hwndServer, &rcConnCount, TRUE); ! 108: return(0); ! 109: } ! 110: ! 111: ! 112: /* ! 113: * only allow transactions on the formats we support if they have a format. ! 114: */ ! 115: if (wFmt) { ! 116: for (iFmt = 0; iFmt < CFORMATS; iFmt++) { ! 117: if (wFmt == aFormats[iFmt].atom) ! 118: break; ! 119: } ! 120: if (iFmt == CFORMATS) ! 121: return(0); // illegal format - ignore now. ! 122: } ! 123: ! 124: /* ! 125: * Executes are allowed only on the system topic. This is a general ! 126: * convention, not a requirement. ! 127: * ! 128: * Any executes received result in the execute text being shown in ! 129: * the server client area. No real action is taken. ! 130: */ ! 131: if (wType == XTYP_EXECUTE) { ! 132: if (hszTopic == topicList[0].hszTopic) { // must be on system topic ! 133: // Format is assumed to be CF_TEXT. ! 134: DdeGetData(hData, (LPBYTE)szExec, MAX_EXEC, 0); ! 135: szExec[MAX_EXEC - 1] = '\0'; ! 136: InvalidateRect(hwndServer, &rcExec, TRUE); ! 137: hDataRet = TRUE; ! 138: goto ReturnSpot; ! 139: } ! 140: pszComment = "Execute received on non-system topic - ignored"; ! 141: InvalidateRect(hwndServer, &rcComment, TRUE); ! 142: return(0); ! 143: } ! 144: ! 145: /* ! 146: * Process wild initiates here ! 147: */ ! 148: if (wType == XTYP_WILDCONNECT) { ! 149: HSZ ahsz[(CTOPICS + 1) * 2]; ! 150: /* ! 151: * He wants a hsz list of all our available app/topic pairs ! 152: * that conform to hszTopic and hszItem(App). ! 153: */ ! 154: ! 155: if (!ValidateContext((PCONVCONTEXT)lData1)) { ! 156: return(FALSE); ! 157: } ! 158: ! 159: if (hszItem != hszAppName && hszItem != 0) { ! 160: // we only support the hszAppName service ! 161: return(0); ! 162: } ! 163: ! 164: // scan the topic table and create hsz pairs ! 165: j = 0; ! 166: for (i = 0; i < CTOPICS; i++) { ! 167: if (hszTopic == 0 || hszTopic == topicList[i].hszTopic) { ! 168: ahsz[j++] = hszAppName; ! 169: ahsz[j++] = topicList[i].hszTopic; ! 170: } ! 171: } ! 172: ! 173: // cap off the list with 0s ! 174: ahsz[j++] = ahsz[j++] = 0L; ! 175: ! 176: // send it back ! 177: return(DdeCreateDataHandle(idInst, (LPBYTE)&ahsz[0], sizeof(HSZ) * j, 0L, 0, wFmt, 0)); ! 178: } ! 179: ! 180: /* ! 181: * Check our hsz tables and send to the apropriate proc. to process. ! 182: * We use DdeCmpStringHandles() which is the portable case-insensitive ! 183: * method of comparing string handles. (this is a macro on windows so ! 184: * there is no real speed hit.) On WINDOWS, HSZs are case-insensitive ! 185: * anyway, but this may not be the case on other platforms. ! 186: */ ! 187: for (i = 0; i < CTOPICS; i++) { ! 188: if (DdeCmpStringHandles(topicList[i].hszTopic, hszTopic) == 0) { ! 189: ! 190: /* ! 191: * connections must be on a topic we support. ! 192: */ ! 193: if (wType == XTYP_CONNECT) { ! 194: return(ValidateContext((PCONVCONTEXT)lData1)); ! 195: } ! 196: ! 197: pItemList = topicList[i].pItemList; ! 198: cItems = topicList[i].cItems; ! 199: for (j = 0; j < cItems; j++) { ! 200: if (DdeCmpStringHandles(pItemList[j].hszItem, hszItem) == 0) { ! 201: XFERINFO xi; ! 202: /* ! 203: * Make call to worker function here... ! 204: */ ! 205: xi.wType = wType; ! 206: xi.wFmt = wFmt; ! 207: xi.hConv = hConv; ! 208: xi.hszTopic = hszTopic; ! 209: xi.hszItem = hszItem; ! 210: xi.hData = hData; ! 211: xi.lData1 = lData1; ! 212: xi.lData2 = lData2; ! 213: hDataRet = (*pItemList[j].npfnCallback)(&xi, iFmt); ! 214: ! 215: ReturnSpot: ! 216: /* ! 217: * The table functions return a boolean or data. ! 218: * It gets translated here. ! 219: */ ! 220: switch (wType & XCLASS_MASK) { ! 221: case XCLASS_DATA: ! 222: return(hDataRet); ! 223: break; ! 224: case XCLASS_FLAGS: ! 225: return(hDataRet ? DDE_FACK : DDE_FNOTPROCESSED); ! 226: break; ! 227: case XCLASS_BOOL: ! 228: return(TRUE); ! 229: default: // XCLASS_NOTIFICATION ! 230: return(0); ! 231: break; ! 232: } ! 233: break; ! 234: } ! 235: } ! 236: break; ! 237: } ! 238: } ! 239: ! 240: /* ! 241: * anything else fails - DDEML is designed so that a 0 return is ALWAYS ok. ! 242: */ ! 243: return(0); ! 244: } ! 245: ! 246: ! 247: ! 248: ! 249: ! 250: /***************************** Private Function ****************************\ ! 251: * This passes out a standard tab-delimited list of topic names for this ! 252: * application. ! 253: * ! 254: * This support is required for other apps to be able to ! 255: * find out about us. This kind of support should be in every DDE ! 256: * application. ! 257: * ! 258: \***************************************************************************/ ! 259: HDDEDATA TopicListXfer( ! 260: PXFERINFO pXferInfo, ! 261: WORD iFmt) ! 262: { ! 263: WORD cbAlloc, i; ! 264: LPSTR pszTopicList; ! 265: HDDEDATA hData; ! 266: ! 267: if (pXferInfo->wType == XTYP_ADVSTART) ! 268: return(TRUE); ! 269: ! 270: if (pXferInfo->wType != XTYP_REQUEST && ! 271: pXferInfo->wType != XTYP_ADVREQ) ! 272: return(0); ! 273: /* ! 274: * construct the list of topics we have ! 275: */ ! 276: cbAlloc = 0; ! 277: for (i = 0; i < CTOPICS; i++) ! 278: cbAlloc += lstrlen(topicList[i].pszTopic) + 1; // 1 for tab ! 279: ! 280: // allocate a data handle big enough for the list. ! 281: hData = DdeCreateDataHandle(idInst, NULL, 0, cbAlloc, pXferInfo->hszItem, ! 282: pXferInfo->wFmt, 0); ! 283: pszTopicList = (LPSTR)DdeAccessData(hData, NULL); ! 284: if (pszTopicList) { ! 285: for (i = 0; i < CTOPICS; i++) { ! 286: _fstrcpy(pszTopicList, topicList[i].pszTopic); ! 287: pszTopicList += strlen(topicList[i].pszTopic); ! 288: *pszTopicList++ = '\t'; ! 289: } ! 290: *--pszTopicList = '\0'; ! 291: DdeUnaccessData(hData); ! 292: return(hData); ! 293: } ! 294: return(0); ! 295: } ! 296: ! 297: ! 298: ! 299: ! 300: /***************************** Private Function ****************************\ ! 301: * This passes out a standard tab-delimited list of item names for the ! 302: * specified topic. ! 303: * ! 304: * This support is required for other apps to be able to ! 305: * find out about us. This kind of support should be in every DDE ! 306: * application. ! 307: * ! 308: \***************************************************************************/ ! 309: HDDEDATA ItemListXfer( ! 310: PXFERINFO pXferInfo, ! 311: WORD iFmt) ! 312: { ! 313: WORD cbAlloc, i, iItem, cItems; ! 314: ITEMLIST *pItemList = 0; ! 315: LPSTR pszItemList; ! 316: HDDEDATA hData; ! 317: ! 318: if (pXferInfo->wType == XTYP_ADVSTART) ! 319: return(TRUE); ! 320: ! 321: if (pXferInfo->wType != XTYP_REQUEST && ! 322: pXferInfo->wType != XTYP_ADVREQ) ! 323: return(0); ! 324: /* ! 325: * construct the list of items we support for this topic - this supports ! 326: * more than the minimum standard which would support SysItems only on ! 327: * the system topic. ! 328: */ ! 329: ! 330: // locate the requested topic item table ! 331: for (i = 0; i < CTOPICS; i++) { ! 332: if (pXferInfo->hszTopic == topicList[i].hszTopic) { ! 333: pItemList = topicList[i].pItemList; ! 334: cItems = topicList[i].cItems; ! 335: break; ! 336: } ! 337: } ! 338: ! 339: if (!pItemList) ! 340: return(0); // item not found ! 341: ! 342: cbAlloc = 0; ! 343: for (iItem = 0; iItem < cItems; iItem++) ! 344: cbAlloc += lstrlen(pItemList[iItem].pszItem) + 1; // 1 for tab ! 345: ! 346: // allocate a data handle big enough for the list. ! 347: hData = DdeCreateDataHandle(idInst, NULL, 0, cbAlloc, pXferInfo->hszItem, ! 348: pXferInfo->wFmt, 0); ! 349: pszItemList = (LPSTR)DdeAccessData(hData, NULL); ! 350: if (pszItemList) { ! 351: for (i = 0; i < cItems; i++) { ! 352: _fstrcpy(pszItemList, pItemList[i].pszItem); ! 353: pszItemList += strlen(pItemList[i].pszItem); ! 354: *pszItemList++ = '\t'; ! 355: } ! 356: *--pszItemList = '\0'; ! 357: DdeUnaccessData(hData); ! 358: return(hData); ! 359: } ! 360: return(0); ! 361: } ! 362: ! 363: ! 364: ! 365: ! 366: ! 367: /***************************** Private Function ****************************\ ! 368: * Gives out a 0 terminated array of dde format numbers supported by this app. ! 369: * ! 370: * This support is required for other apps to be able to ! 371: * find out about us. This kind of support should be in every DDE ! 372: * application. ! 373: * ! 374: \***************************************************************************/ ! 375: HDDEDATA sysFormatsXfer( ! 376: PXFERINFO pXferInfo, ! 377: WORD iFmt) ! 378: { ! 379: INT i, cb; ! 380: LPSTR psz, pszT; ! 381: HDDEDATA hData; ! 382: ! 383: if (pXferInfo->wType == XTYP_ADVSTART) ! 384: return(TRUE); ! 385: ! 386: if (pXferInfo->wType != XTYP_REQUEST && ! 387: pXferInfo->wType != XTYP_ADVREQ) ! 388: return(0); ! 389: ! 390: for (i = 0, cb = 0; i < CFORMATS; i++) ! 391: cb += strlen(aFormats[i].sz) + 1; ! 392: ! 393: hData = DdeCreateDataHandle(idInst, NULL, (DWORD)cb, ! 394: 0L, pXferInfo->hszItem, pXferInfo->wFmt, 0); ! 395: psz = pszT = DdeAccessData(hData, NULL); ! 396: for (i = 0; i < CFORMATS; i++) { ! 397: _fstrcpy(pszT, aFormats[i].sz); ! 398: pszT += _fstrlen(pszT); ! 399: *pszT++ = '\t'; ! 400: } ! 401: *(--pszT) = '\0'; ! 402: DdeUnaccessData(hData); ! 403: return(hData); ! 404: } ! 405: ! 406: ! 407: ! 408: /* ! 409: * This is a runaway item. Each time it is requested, it changes. ! 410: * pokes just make it change again. ! 411: */ ! 412: HDDEDATA TestRandomXfer( ! 413: PXFERINFO pXferInfo, ! 414: WORD iFmt) ! 415: { ! 416: CHAR szT[10]; // SS==DS! ! 417: LPSTR pszData; ! 418: HDDEDATA hData; ! 419: WORD i; ! 420: ! 421: switch (pXferInfo->wType) { ! 422: case XTYP_POKE: ! 423: // we expect an ascii number to replace the current seed. ! 424: pszComment = "Rand poke received."; ! 425: InvalidateRect(hwndServer, &rcComment, TRUE); ! 426: InvalidateRect(hwndServer, &rcRand, TRUE); ! 427: if (DdeGetData(pXferInfo->hData, szT, 10, 0)) { ! 428: szT[9] = '\0'; // just incase we overran. ! 429: sscanf(szT, "%d", &seed); ! 430: for (i = 0; i < CFORMATS; i++) { ! 431: if (hDataRand[i]) ! 432: DdeFreeDataHandle(hDataRand[i]); ! 433: hDataRand[i] = 0; ! 434: } ! 435: DdePostAdvise(idInst, pXferInfo->hszTopic, pXferInfo->hszItem); ! 436: return(1); ! 437: } ! 438: break; ! 439: ! 440: case XTYP_REQUEST: ! 441: pszComment = "Rand data requested."; ! 442: InvalidateRect(hwndServer, &rcComment, TRUE); ! 443: case XTYP_ADVREQ: ! 444: Delay(RenderDelay, FALSE); ! 445: if (!hDataRand[iFmt]) { ! 446: hDataRand[iFmt] = DdeCreateDataHandle(idInst, NULL, 0, 10, pXferInfo->hszItem, ! 447: pXferInfo->wFmt, fAppowned ? HDATA_APPOWNED : 0); ! 448: if (pszData = DdeAccessData(hDataRand[iFmt], NULL)) { ! 449: wsprintf(pszData, "%d", seed); ! 450: DdeUnaccessData(hDataRand[iFmt]); ! 451: } ! 452: } ! 453: hData = hDataRand[iFmt]; ! 454: if (!fAppowned) ! 455: hDataRand[iFmt] = 0; ! 456: return(hData); ! 457: break; ! 458: ! 459: case XTYP_ADVSTART: ! 460: return(1); ! 461: } ! 462: return(0); ! 463: } ! 464: ! 465: /* ! 466: * This is a runaway item. Each time it is requested, it changes. ! 467: * pokes just make it change again. ! 468: */ ! 469: HDDEDATA TestCountXfer( ! 470: PXFERINFO pXferInfo, ! 471: WORD iFmt) ! 472: { ! 473: CHAR szT[16]; // SS==DS! ! 474: LPSTR pszData; ! 475: HDDEDATA hData; ! 476: WORD i; ! 477: ! 478: switch (pXferInfo->wType) { ! 479: case XTYP_POKE: ! 480: // we expect an ascii number to replace the current count. ! 481: pszComment = "Count poke received"; ! 482: InvalidateRect(hwndServer, &rcComment, TRUE); ! 483: InvalidateRect(hwndServer, &rcCount, TRUE); ! 484: if (DdeGetData(pXferInfo->hData, szT, 10, 0)) { ! 485: szT[9] = '\0'; // just incase we overran. ! 486: sscanf(szT, "%ld", &count); ! 487: for (i = 0; i < CFORMATS; i++) { ! 488: if (hDataCount[i]) ! 489: DdeFreeDataHandle(hDataCount[i]); ! 490: hDataCount[i] = 0; ! 491: } ! 492: DdePostAdvise(idInst, pXferInfo->hszTopic, pXferInfo->hszItem); ! 493: return(1); ! 494: } ! 495: break; ! 496: ! 497: case XTYP_REQUEST: ! 498: pszComment = "Count data requested."; ! 499: InvalidateRect(hwndServer, &rcComment, TRUE); ! 500: case XTYP_ADVREQ: ! 501: Delay(RenderDelay, FALSE); ! 502: if (!hDataCount[iFmt]) { ! 503: hDataCount[iFmt] = DdeCreateDataHandle(idInst, NULL, 0, 10, pXferInfo->hszItem, ! 504: pXferInfo->wFmt, fAppowned ? HDATA_APPOWNED : 0); ! 505: if (pszData = DdeAccessData(hDataCount[iFmt], NULL)) { ! 506: wsprintf(pszData, "%ld", count); ! 507: DdeUnaccessData(hDataCount[iFmt]); ! 508: } ! 509: } ! 510: hData = hDataCount[iFmt]; ! 511: if (!fAppowned) ! 512: hDataCount[iFmt] = 0; ! 513: return(hData); ! 514: break; ! 515: ! 516: case XTYP_ADVSTART: ! 517: return(1); ! 518: } ! 519: return(0); ! 520: } ! 521: ! 522: ! 523: /* ! 524: * This is not a runaway item. Only Pokes make it change. ! 525: */ ! 526: HDDEDATA TestHugeXfer( ! 527: PXFERINFO pXferInfo, ! 528: WORD iFmt) ! 529: { ! 530: BOOL fSuccess; ! 531: DWORD ulcb; ! 532: LPBYTE lpData; ! 533: WORD i; ! 534: HDDEDATA hData; ! 535: ! 536: switch (pXferInfo->wType) { ! 537: case XTYP_POKE: ! 538: ulcb = DdeGetData(pXferInfo->hData, NULL, 0, 0); ! 539: fSuccess = CheckHugeData(pXferInfo->hData); ! 540: if (fSuccess) { ! 541: pszComment = "Huge poke data successfully received."; ! 542: } else { ! 543: wsprintf(szComment, "%ld bytes of invalid Huge data received.", ulcb); ! 544: pszComment = szComment; ! 545: } ! 546: InvalidateRect(hwndServer, &rcComment, TRUE); ! 547: InvalidateRect(hwndServer, &rcHugeSize, TRUE); ! 548: if (fSuccess) { ! 549: for (i = 0; i < CFORMATS; i++) { ! 550: if (hDataHuge[i]) { ! 551: DdeFreeDataHandle(hDataHuge[i]); ! 552: hDataHuge[i] = 0; ! 553: } ! 554: } ! 555: /* ! 556: * Since callback data handles are only good for the duration of ! 557: * the callback, we must copy the data to our own data handle. ! 558: */ ! 559: lpData = DdeAccessData(pXferInfo->hData, &cbHuge); ! 560: hDataHuge[iFmt] = DdeCreateDataHandle(idInst, lpData, cbHuge, 0, ! 561: pXferInfo->hszItem, pXferInfo->wFmt, fAppowned ? HDATA_APPOWNED : 0); ! 562: DdeUnaccessData(pXferInfo->hData); ! 563: DdePostAdvise(idInst, pXferInfo->hszTopic, pXferInfo->hszItem); ! 564: } ! 565: return(fSuccess); ! 566: break; ! 567: ! 568: case XTYP_REQUEST: ! 569: pszComment = "Huge data requested."; ! 570: InvalidateRect(hwndServer, &rcComment, TRUE); ! 571: case XTYP_ADVREQ: ! 572: Delay(RenderDelay, FALSE); ! 573: if (!hDataHuge[iFmt]) { ! 574: cbHuge = (DWORD)rand() * 64L + 0x10000L; ! 575: wsprintf(szComment, "Generating huge data - length=%ld...", cbHuge); ! 576: pszComment = szComment; ! 577: InvalidateRect(hwndServer, &rcComment, TRUE); ! 578: UpdateWindow(hwndServer); ! 579: hDataHuge[iFmt] = CreateHugeDataHandle(cbHuge, 4325, 345, 5, ! 580: pXferInfo->hszItem, ! 581: pXferInfo->wFmt, fAppowned ? HDATA_APPOWNED : 0); ! 582: pszComment = ""; ! 583: InvalidateRect(hwndServer, &rcComment, TRUE); ! 584: InvalidateRect(hwndServer, &rcHugeSize, TRUE); ! 585: } ! 586: hData = hDataHuge[iFmt]; ! 587: if (!fAppowned) ! 588: hDataHuge[iFmt] = 0; ! 589: return(hData); ! 590: break; ! 591: ! 592: case XTYP_ADVSTART: ! 593: return(1); ! 594: } ! 595: return(0); ! 596: } ! 597: ! 598: ! 599: HDDEDATA HelpXfer( ! 600: PXFERINFO pXferInfo, ! 601: WORD iFmt) ! 602: { ! 603: HDDEDATA hData; ! 604: ! 605: switch (pXferInfo->wType) { ! 606: case XTYP_REQUEST: ! 607: pszComment = "Help text requested."; ! 608: InvalidateRect(hwndServer, &rcComment, TRUE); ! 609: case XTYP_ADVREQ: ! 610: if (!hDataHelp[iFmt]) { ! 611: hDataHelp[iFmt] = DdeCreateDataHandle(idInst, szDdeHelp, strlen(szDdeHelp) + 1, ! 612: 0, pXferInfo->hszItem, pXferInfo->wFmt, fAppowned ? HDATA_APPOWNED : 0); ! 613: } ! 614: hData = hDataHelp[iFmt]; ! 615: if (!fAppowned) ! 616: hDataHelp[iFmt] = 0; ! 617: return(hData); ! 618: break; ! 619: ! 620: case XTYP_ADVSTART: ! 621: return(1); ! 622: } ! 623: return(0); ! 624: } ! 625: ! 626: ! 627: /***************************** Private Function ****************************\ ! 628: * This creates often used global hszs from standard global strings. ! 629: * It also fills the hsz fields of the topic and item tables. ! 630: * ! 631: \***************************************************************************/ ! 632: VOID Hszize() ! 633: { ! 634: register ITEMLIST *pItemList; ! 635: WORD iTopic, iItem; ! 636: ! 637: hszAppName = DdeCreateStringHandle(idInst, szServer, 0); ! 638: ! 639: for (iTopic = 0; iTopic < CTOPICS; iTopic++) { ! 640: topicList[iTopic].hszTopic = ! 641: DdeCreateStringHandle(idInst, topicList[iTopic].pszTopic, 0); ! 642: pItemList = topicList[iTopic].pItemList; ! 643: for (iItem = 0; iItem < topicList[iTopic].cItems; iItem++) { ! 644: pItemList[iItem].hszItem = ! 645: DdeCreateStringHandle(idInst, pItemList[iItem].pszItem, 0); ! 646: } ! 647: } ! 648: } ! 649: ! 650: ! 651: ! 652: ! 653: ! 654: /***************************** Private Function ****************************\ ! 655: * This destroys often used global hszs from standard global strings. ! 656: * ! 657: \***************************************************************************/ ! 658: VOID UnHszize() ! 659: { ! 660: register ITEMLIST *pItemList; ! 661: WORD iTopic, iItem; ! 662: ! 663: DdeFreeStringHandle(idInst, hszAppName); ! 664: ! 665: for (iTopic = 0; iTopic < CTOPICS; iTopic++) { ! 666: DdeFreeStringHandle(idInst, topicList[iTopic].hszTopic); ! 667: pItemList = topicList[iTopic].pItemList; ! 668: for (iItem = 0; iItem < topicList[iTopic].cItems; iItem++) { ! 669: DdeFreeStringHandle(idInst, pItemList[iItem].hszItem); ! 670: } ! 671: } ! 672: } ! 673: ! 674:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.