Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

793 lines
21 KiB

  1. /***************************************************************************\
  2. PROGRAM : wrapper.c
  3. PURPOSE : This is not a full program but a module you can include
  4. in your code. It implements a standard DDEML callback
  5. function that allows you to have most of your DDE table
  6. driven. The default callback function handles all basic
  7. System Topic information based on the tables you give
  8. to this app.
  9. LIMITATIONS : This only supports servers that:
  10. have only one service name
  11. have enumerable topics and items
  12. do not change the topics or items they support over time.
  13. EXPORTED ROUTINES:
  14. InitializeDDE()
  15. Use this to initialize the callback function tables and the DDEML
  16. UninitializeDDE()
  17. Use this to cleanup this module and uninitialize the DDEML instance.
  18. \***************************************************************************/
  19. #include <windows.h>
  20. #include <ddeml.h>
  21. #include <string.h>
  22. #include "wrapper.h"
  23. #include <port1632.h>
  24. #include "ddestrs.h"
  25. extern BOOL fServer;
  26. extern LPSTR pszNetName;
  27. extern LONG SetThreadLong(DWORD,INT,LONG);
  28. extern LONG GetThreadLong(DWORD,INT);
  29. extern LPSTR TStrCpy( LPSTR, LPSTR);
  30. BOOL InExit(VOID);
  31. VOID InitHszs(LPDDESERVICETBL psi);
  32. UINT GetFormat(LPSTR pszFormat);
  33. VOID FreeHszs(LPDDESERVICETBL psi);
  34. HDDEDATA APIENTRY WrapperCallback(UINT wType, UINT wFmt, HCONV hConv, HSZ hsz1,
  35. HSZ hsz2, HDDEDATA hData, DWORD dwData1, DWORD dwData2);
  36. BOOL DoCallback(HCONV,HSZ,HSZ,UINT,UINT,HDDEDATA,LPDDESERVICETBL,HDDEDATA *);
  37. HDDEDATA ReqItems(HDDEDATA hDataOut, LPDDETOPICTBL ptpc);
  38. HDDEDATA AddReqFormat(HDDEDATA hDataOut, LPSTR pszFmt);
  39. HDDEDATA ReqFormats(HDDEDATA hDataOut, LPDDETOPICTBL ptpc);
  40. HDDEDATA DoWildConnect(HSZ hszTopic);
  41. PFNCALLBACK lpfnUserCallback = NULL;
  42. PFNCALLBACK lpfnWrapperCallback = NULL;
  43. LPDDESERVICETBL pasi = NULL;
  44. char tab[] = "\t";
  45. #define FOR_EACH_TOPIC(psvc, ptpc, i) for (i = 0, ptpc=(psvc)->topic; i < (int)(psvc)->cTopics; i++, ptpc++)
  46. #define FOR_EACH_ITEM(ptpc, pitm, i) for (i = 0, pitm=(ptpc)->item; i < (int)(ptpc)->cItems; i++, pitm++)
  47. #define FOR_EACH_FORMAT(pitm, pfmt, i) for (i = 0, pfmt=(pitm)->fmt; i < (int)(pitm)->cFormats;i++, pfmt++)
  48. /* STANDARD PREDEFINED FORMATS */
  49. #ifdef WIN32
  50. #define CSTDFMTS 14
  51. #else
  52. #define CSTDFMTS 12
  53. #endif
  54. struct {
  55. UINT wFmt;
  56. PSTR pszFmt;
  57. } StdFmts[CSTDFMTS] = {
  58. { CF_TEXT , "TEXT" } ,
  59. { CF_BITMAP , "BITMAP" } ,
  60. { CF_METAFILEPICT, "METAFILEPICT" } ,
  61. { CF_SYLK , "SYLK" } ,
  62. { CF_DIF , "DIF" } ,
  63. { CF_TIFF , "TIFF" } ,
  64. { CF_OEMTEXT , "OEMTEXT" } ,
  65. { CF_DIB , "DIB" } ,
  66. { CF_PALETTE , "PALETTE" } ,
  67. { CF_PENDATA , "PENDATA" } ,
  68. { CF_RIFF , "RIFF" } ,
  69. { CF_WAVE , "WAVE" } ,
  70. #ifdef WIN32
  71. { CF_UNICODETEXT , "UNICODETEXT" } ,
  72. { CF_ENHMETAFILE , "ENHMETAFILE" } ,
  73. #endif
  74. };
  75. HDDEDATA SysReqTopics(HDDEDATA hDataOut);
  76. HDDEDATA SysReqSysItems(HDDEDATA hDataOut);
  77. HDDEDATA SysReqFormats(HDDEDATA hDataOut);
  78. /* STANDARD SERVICE INFO TABLES */
  79. DDEFORMATTBL StdSvcSystopicTopicsFormats[] = {
  80. "TEXT", 0, 0, NULL, SysReqTopics
  81. };
  82. DDEFORMATTBL StdSvcSystopicSysitemsFormats[] = {
  83. "TEXT", 0, 0, NULL, SysReqSysItems
  84. };
  85. DDEFORMATTBL StdSvcSystopicFormatsFormats[] = {
  86. "TEXT", 0, 0, NULL, SysReqFormats
  87. };
  88. #define ITPC_TOPICS 0
  89. #define ITPC_SYSITEMS 1
  90. #define ITPC_FORMATS 2
  91. #define ITPC_ITEMLIST 3
  92. #define ITPC_COUNT 4
  93. DDEITEMTBL StdSvcSystopicItems[] = {
  94. { SZDDESYS_ITEM_TOPICS, 0, 1, 0, StdSvcSystopicTopicsFormats },
  95. { SZDDESYS_ITEM_SYSITEMS, 0, 1, 0, StdSvcSystopicSysitemsFormats },
  96. { SZDDESYS_ITEM_FORMATS, 0, 1, 0, StdSvcSystopicFormatsFormats },
  97. { SZDDE_ITEM_ITEMLIST, 0, 1, 0, StdSvcSystopicSysitemsFormats },
  98. };
  99. DDETOPICTBL StdSvc[] = {
  100. SZDDESYS_TOPIC, 0, ITPC_COUNT, 0, StdSvcSystopicItems
  101. };
  102. DDESERVICETBL SSI = {
  103. NULL, 0, 1, 0, StdSvc
  104. };
  105. /*********************************************************************/
  106. BOOL InitializeDDE(
  107. PFNCALLBACK lpfnCustomCallback,
  108. LPDWORD pidInst,
  109. LPDDESERVICETBL AppSvcInfo,
  110. DWORD dwFilterFlags,
  111. HANDLE hInst)
  112. {
  113. DWORD idI=0;
  114. if (lpfnCustomCallback) {
  115. lpfnUserCallback = (PFNCALLBACK)MakeProcInstance((FARPROC)lpfnCustomCallback, hInst);
  116. }
  117. lpfnWrapperCallback = (PFNCALLBACK)MakeProcInstance((FARPROC)WrapperCallback, hInst);
  118. if (DdeInitialize(&idI, lpfnWrapperCallback, dwFilterFlags, 0)) {
  119. SetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST,idI);
  120. if (lpfnCustomCallback) {
  121. FreeProcInstance((FARPROC)lpfnUserCallback);
  122. }
  123. FreeProcInstance((FARPROC)lpfnWrapperCallback);
  124. return(FALSE);
  125. }
  126. else SetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST,idI);
  127. *pidInst = idI;
  128. InitHszs(AppSvcInfo);
  129. InitHszs(&SSI);
  130. pasi = AppSvcInfo;
  131. if (fServer) {
  132. DdeNameService(idI, pasi->hszService, 0, DNS_REGISTER);
  133. }
  134. return(TRUE);
  135. }
  136. VOID InitHszs(
  137. LPDDESERVICETBL psi)
  138. {
  139. int iTopic, iItem, iFmt;
  140. LPDDETOPICTBL ptpc;
  141. LPDDEITEMTBL pitm;
  142. LPDDEFORMATTBL pfmt;
  143. DWORD idI;
  144. CHAR sz[120];
  145. LPBYTE psz;
  146. LPBYTE pNet;
  147. pNet=pszNetName;
  148. idI=GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST);
  149. if (psi->pszService) {
  150. // This area of code inplements the clients ability
  151. // to see net drives. This is the -n option.
  152. if(pNet)
  153. {
  154. sz[0]='\\';
  155. sz[1]='\\';
  156. psz=&sz[2];
  157. psz=TStrCpy(psz,pNet);
  158. while(*++psz!='\0');
  159. *psz++='\\';
  160. psz=TStrCpy(psz,psi->pszService);
  161. psz=&sz[0];
  162. psi->hszService = DdeCreateStringHandle(idI, psz, 0);
  163. } // pNet
  164. else psi->hszService = DdeCreateStringHandle(idI, psi->pszService, 0);
  165. }
  166. FOR_EACH_TOPIC(psi, ptpc, iTopic) {
  167. ptpc->hszTopic = DdeCreateStringHandle(idI, ptpc->pszTopic, 0);
  168. FOR_EACH_ITEM(ptpc, pitm, iItem) {
  169. pitm->hszItem = DdeCreateStringHandle(idI, pitm->pszItem, 0);
  170. FOR_EACH_FORMAT(pitm, pfmt, iFmt) {
  171. pfmt->wFmt = GetFormat(pfmt->pszFormat);
  172. }
  173. }
  174. }
  175. }
  176. /*
  177. * This function allows apps to use standard CF_ formats. The string
  178. * given may be in the StdFmts[] table.
  179. */
  180. UINT GetFormat(
  181. LPSTR pszFormat)
  182. {
  183. int iFmt;
  184. for (iFmt = 0; iFmt < CSTDFMTS; iFmt++) {
  185. if (!lstrcmp(pszFormat, StdFmts[iFmt].pszFmt)) {
  186. return(StdFmts[iFmt].wFmt);
  187. }
  188. }
  189. return(RegisterClipboardFormat(pszFormat));
  190. }
  191. VOID UninitializeDDE()
  192. {
  193. DWORD idI;
  194. if (pasi == NULL) {
  195. return;
  196. }
  197. idI=GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST);
  198. DdeNameService(idI, pasi->hszService, 0, DNS_UNREGISTER);
  199. FreeHszs(pasi);
  200. FreeHszs(&SSI);
  201. DdeUninitialize(idI);
  202. if (lpfnUserCallback) {
  203. FreeProcInstance((FARPROC)lpfnUserCallback);
  204. }
  205. FreeProcInstance((FARPROC)lpfnWrapperCallback);
  206. }
  207. VOID FreeHszs(
  208. LPDDESERVICETBL psi)
  209. {
  210. int iTopic, iItem;
  211. LPDDETOPICTBL ptpc;
  212. LPDDEITEMTBL pitm;
  213. DWORD idI;
  214. idI=GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST);
  215. DdeFreeStringHandle(idI, psi->hszService);
  216. FOR_EACH_TOPIC(psi, ptpc, iTopic) {
  217. DdeFreeStringHandle(idI, ptpc->hszTopic);
  218. FOR_EACH_ITEM(ptpc, pitm, iItem) {
  219. DdeFreeStringHandle(idI, pitm->hszItem);
  220. }
  221. }
  222. }
  223. BOOL InExit( VOID ) {
  224. LONG l;
  225. if(!IsWindow((HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY))) {
  226. DDEMLERROR("DdeStrs.Exe -- INF:Invalid hwndDisplay, returning NAck!\r\n");
  227. return TRUE;
  228. }
  229. if(!IsWindow(hwndMain)) {
  230. DDEMLERROR("DdeStrs.Exe -- INF:Invalid hwndMain, returning NAck!\r\n");
  231. return TRUE;
  232. }
  233. // No need for error message on this one. This is expected to happen
  234. // when queues fill up under extreme conditions.
  235. l=GetWindowLong(hwndMain,OFFSET_FLAGS);
  236. if(l&FLAG_STOP) {
  237. return TRUE;
  238. }
  239. return FALSE;
  240. }
  241. HDDEDATA APIENTRY WrapperCallback(
  242. UINT wType,
  243. UINT wFmt,
  244. HCONV hConv,
  245. HSZ hsz1,
  246. HSZ hsz2,
  247. HDDEDATA hData,
  248. DWORD dwData1,
  249. DWORD dwData2)
  250. {
  251. HDDEDATA hDataRet;
  252. switch (wType) {
  253. case XTYP_WILDCONNECT:
  254. if (!hsz2 || !DdeCmpStringHandles(hsz2, pasi->hszService)) {
  255. return(DoWildConnect(hsz1));
  256. }
  257. break;
  258. case XTYP_CONNECT:
  259. if(!fServer) {
  260. DDEMLERROR("DdeStrs.Exe -- Recieved XTYP_CONNECT when client!\r\n");
  261. }
  262. case XTYP_ADVSTART:
  263. case XTYP_EXECUTE:
  264. case XTYP_REQUEST:
  265. case XTYP_ADVREQ:
  266. case XTYP_ADVDATA:
  267. case XTYP_POKE:
  268. if(InExit()) return(0);
  269. if(DoCallback(hConv, hsz1, hsz2, wFmt, wType, hData,
  270. &SSI, &hDataRet))
  271. return(hDataRet);
  272. if (DoCallback(hConv, hsz1, hsz2, wFmt, wType, hData,
  273. pasi, &hDataRet))
  274. return(hDataRet);
  275. /* Fall Through */
  276. default:
  277. if (lpfnUserCallback != NULL) {
  278. return(lpfnUserCallback(wType, wFmt, hConv, hsz1, hsz2, hData,
  279. dwData1, dwData2));
  280. }
  281. }
  282. return(0);
  283. }
  284. BOOL DoCallback(
  285. HCONV hConv,
  286. HSZ hszTopic,
  287. HSZ hszItem,
  288. UINT wFmt,
  289. UINT wType,
  290. HDDEDATA hDataIn,
  291. LPDDESERVICETBL psi,
  292. HDDEDATA *phDataRet)
  293. {
  294. int iTopic, iItem, iFmt;
  295. LPDDEFORMATTBL pfmt;
  296. LPDDEITEMTBL pitm;
  297. LPDDETOPICTBL ptpc;
  298. #ifdef WIN32
  299. CONVINFO ci;
  300. #endif
  301. LONG l;
  302. BOOL fCreate=FALSE;
  303. HANDLE hmem;
  304. HDDEDATA FAR *hAppOwned;
  305. FOR_EACH_TOPIC(psi, ptpc, iTopic) {
  306. if (DdeCmpStringHandles(ptpc->hszTopic, hszTopic))
  307. continue;
  308. if (wType == XTYP_EXECUTE) {
  309. if (ptpc->lpfnExecute) {
  310. if ((*ptpc->lpfnExecute)(hDataIn))
  311. *phDataRet = (HDDEDATA)DDE_FACK;
  312. } else {
  313. *phDataRet = (HDDEDATA)DDE_FNOTPROCESSED;
  314. }
  315. return(TRUE);
  316. }
  317. if (wType == XTYP_CONNECT) {
  318. *phDataRet = (HDDEDATA)TRUE;
  319. return(TRUE);
  320. }
  321. FOR_EACH_ITEM(ptpc, pitm, iItem) {
  322. if (DdeCmpStringHandles(pitm->hszItem, hszItem))
  323. continue;
  324. FOR_EACH_FORMAT(pitm, pfmt, iFmt) {
  325. if (pfmt->wFmt != wFmt)
  326. continue;
  327. switch (wType) {
  328. case XTYP_ADVSTART:
  329. *phDataRet = (HDDEDATA)TRUE;
  330. break;
  331. // XTYP_POKE CHANGE
  332. #if 0
  333. case XTYP_POKE:
  334. #endif
  335. case XTYP_ADVDATA:
  336. if (pfmt->lpfnPoke) {
  337. if ((*pfmt->lpfnPoke)(hDataIn))
  338. {
  339. *phDataRet = (HDDEDATA)DDE_FACK;
  340. break;
  341. }
  342. } else {
  343. *phDataRet = (HDDEDATA)DDE_FNOTPROCESSED;
  344. }
  345. break;
  346. // XTYP_POKE CHANGE
  347. #ifdef WIN32 // TURNED BACK ON
  348. case XTYP_POKE:
  349. *phDataRet = (HDDEDATA)DDE_FACK;
  350. ci.cb = sizeof(CONVINFO);
  351. if (DdeQueryConvInfo(hConv, QID_SYNC, &ci))
  352. {
  353. if (!(ci.wStatus & ST_ISSELF)) {
  354. DdePostAdvise(GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST), hszTopic, hszItem);
  355. }
  356. }
  357. else
  358. {
  359. *phDataRet = (HDDEDATA)DDE_FNOTPROCESSED;
  360. }
  361. break;
  362. #endif
  363. case XTYP_REQUEST:
  364. case XTYP_ADVREQ:
  365. if (pfmt->lpfnRequest) {
  366. HDDEDATA hDataOut;
  367. l=GetWindowLong(hwndMain,OFFSET_FLAGS);
  368. if(l&FLAG_APPOWNED) {
  369. hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HAPPOWNED);
  370. hAppOwned=(HDDEDATA FAR *)GlobalLock(hmem);
  371. switch (pfmt->wFmt) {
  372. case CF_TEXT: if(hAppOwned[TXT]==0L) fCreate=TRUE;
  373. break;
  374. case CF_DIB: if(hAppOwned[DIB]==0L) fCreate=TRUE;
  375. break;
  376. case CF_BITMAP: if(hAppOwned[BITMAP]==0L) fCreate=TRUE;
  377. break;
  378. #ifdef WIN32
  379. case CF_ENHMETAFILE: if(hAppOwned[ENHMETA]==0L) fCreate=TRUE;
  380. break;
  381. #endif
  382. case CF_METAFILEPICT: if(hAppOwned[METAPICT]==0L) fCreate=TRUE;
  383. break;
  384. case CF_PALETTE: if(hAppOwned[PALETTE]==0L) fCreate=TRUE;
  385. break;
  386. default:
  387. DDEMLERROR("DdeStrs.Exe -- ERR: Unexpected switch constant in DoCallback!\r\n");
  388. break;
  389. } // switch
  390. GlobalUnlock(hmem);
  391. if (fCreate) {
  392. hDataOut = DdeCreateDataHandle( GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST),
  393. NULL,
  394. 0,
  395. 0,
  396. pitm->hszItem,
  397. pfmt->wFmt,
  398. HDATA_APPOWNED);
  399. } // fCreate
  400. } // l&FLAG_APPOWNED
  401. else {
  402. hDataOut = DdeCreateDataHandle( GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST),
  403. NULL,
  404. 0,
  405. 0,
  406. pitm->hszItem,
  407. pfmt->wFmt,
  408. 0);
  409. } // else l&FLAG_APPOWNED
  410. *phDataRet = (HDDEDATA)(*pfmt->lpfnRequest)(hDataOut);
  411. if (!*phDataRet) {
  412. DdeFreeDataHandle(hDataOut);
  413. }
  414. } else {
  415. *phDataRet = 0;
  416. }
  417. break;
  418. }
  419. return(TRUE);
  420. }
  421. }
  422. /* item not found in tables */
  423. if (wFmt == CF_TEXT && (wType == XTYP_REQUEST || wType == XTYP_ADVREQ)) {
  424. /*
  425. * If formats item was requested and not found in the tables,
  426. * return a list of formats supported under this topic.
  427. */
  428. if (!DdeCmpStringHandles(hszItem, SSI.topic[0].item[ITPC_FORMATS].hszItem)) {
  429. *phDataRet = DdeCreateDataHandle(GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST),
  430. NULL,
  431. 0,
  432. 0,
  433. hszItem,
  434. wFmt,
  435. 0);
  436. *phDataRet = ReqFormats(*phDataRet, ptpc);
  437. return(TRUE);
  438. }
  439. /*
  440. * If sysitems or topicitemlist item was requested and not found,
  441. * return a list of items supported under this topic.
  442. */
  443. if (!DdeCmpStringHandles(hszItem, SSI.topic[0].item[ITPC_SYSITEMS].hszItem) ||
  444. !DdeCmpStringHandles(hszItem, SSI.topic[0].item[ITPC_ITEMLIST].hszItem)) {
  445. *phDataRet = ReqItems(DdeCreateDataHandle(GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST),
  446. NULL,
  447. 0,
  448. 0,
  449. hszItem,
  450. wFmt,
  451. 0),
  452. ptpc);
  453. return(TRUE);
  454. }
  455. }
  456. }
  457. /* no topics fit */
  458. return(FALSE);
  459. }
  460. /*
  461. * These are Request routines for supporting the system topic.
  462. * Their behavior depends on the table contents.
  463. */
  464. HDDEDATA SysReqTopics(
  465. HDDEDATA hDataOut) // data handle to add output data to.
  466. {
  467. int iTopic, cb, cbOff;
  468. LPDDETOPICTBL ptpc;
  469. /*
  470. * This code assumes SSI only contains the system topic.
  471. */
  472. cbOff = 0;
  473. FOR_EACH_TOPIC(pasi, ptpc, iTopic) {
  474. if (!DdeCmpStringHandles(ptpc->hszTopic, SSI.topic[0].hszTopic)) {
  475. continue; // don't add systopic twice.
  476. }
  477. cb = lstrlen(ptpc->pszTopic);
  478. hDataOut = DdeAddData(hDataOut, ptpc->pszTopic, (DWORD)cb, (DWORD)cbOff);
  479. cbOff += cb;
  480. hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
  481. cbOff++;
  482. }
  483. hDataOut = DdeAddData(hDataOut, SSI.topic[0].pszTopic,
  484. (DWORD)lstrlen(SSI.topic[0].pszTopic) + 1, (DWORD)cbOff);
  485. return(hDataOut);
  486. }
  487. HDDEDATA SysReqSysItems(
  488. HDDEDATA hDataOut)
  489. {
  490. return(ReqItems(hDataOut, &SSI.topic[ITPC_SYSITEMS]));
  491. }
  492. /*
  493. * Given a topic table, this function returns a tab delimited list of
  494. * items supported under that topic.
  495. */
  496. HDDEDATA ReqItems(
  497. HDDEDATA hDataOut,
  498. LPDDETOPICTBL ptpc)
  499. {
  500. int cb, iItem, cbOff = 0;
  501. LPDDEITEMTBL pitm;
  502. /*
  503. * return a list of all the items within this topic
  504. */
  505. FOR_EACH_ITEM(ptpc, pitm, iItem) {
  506. cb = lstrlen(pitm->pszItem);
  507. hDataOut = DdeAddData(hDataOut, pitm->pszItem, (DWORD)cb, (DWORD)cbOff);
  508. cbOff += cb;
  509. hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
  510. cbOff++;
  511. }
  512. /*
  513. * if this is for the System Topic, add to the list our default items.
  514. */
  515. if (!DdeCmpStringHandles(ptpc->hszTopic, SSI.topic[0].hszTopic)) {
  516. ptpc = &SSI.topic[0];
  517. FOR_EACH_ITEM(ptpc, pitm, iItem) {
  518. cb = lstrlen(pitm->pszItem);
  519. hDataOut = DdeAddData(hDataOut, pitm->pszItem, (DWORD)cb, (DWORD)cbOff);
  520. cbOff += cb;
  521. hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
  522. cbOff++;
  523. }
  524. } else {
  525. /*
  526. * Add the standard TopicListItems and SysItem items.
  527. */
  528. cb = lstrlen(SSI.topic[0].item[ITPC_SYSITEMS].pszItem);
  529. hDataOut = DdeAddData(hDataOut,
  530. SSI.topic[0].item[ITPC_SYSITEMS].pszItem, (DWORD)cb, (DWORD)cbOff);
  531. cbOff += cb;
  532. hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
  533. cbOff++;
  534. cb = lstrlen(SSI.topic[0].item[ITPC_ITEMLIST].pszItem);
  535. hDataOut = DdeAddData(hDataOut,
  536. SSI.topic[0].item[ITPC_ITEMLIST].pszItem, (DWORD)cb, (DWORD)cbOff);
  537. cbOff += cb;
  538. hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
  539. cbOff++;
  540. cb = lstrlen(SSI.topic[0].item[ITPC_FORMATS].pszItem);
  541. hDataOut = DdeAddData(hDataOut,
  542. SSI.topic[0].item[ITPC_FORMATS].pszItem, (DWORD)cb, (DWORD)cbOff);
  543. cbOff += cb;
  544. hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
  545. cbOff++;
  546. }
  547. hDataOut = DdeAddData(hDataOut, '\0', (DWORD)1, (DWORD)--cbOff);
  548. return(hDataOut);
  549. }
  550. HDDEDATA SysReqFormats(
  551. HDDEDATA hDataOut)
  552. {
  553. int iTopic, iItem, iFmt;
  554. LPDDETOPICTBL ptpc;
  555. LPDDEITEMTBL pitm;
  556. LPDDEFORMATTBL pfmt;
  557. hDataOut = DdeAddData(hDataOut, (LPBYTE)"TEXT", 5, 0);
  558. FOR_EACH_TOPIC(pasi, ptpc, iTopic) {
  559. FOR_EACH_ITEM(ptpc, pitm, iItem) {
  560. FOR_EACH_FORMAT(pitm, pfmt, iFmt) {
  561. hDataOut = AddReqFormat(hDataOut, pfmt->pszFormat);
  562. }
  563. }
  564. }
  565. return(hDataOut);
  566. }
  567. HDDEDATA AddReqFormat(
  568. HDDEDATA hDataOut,
  569. LPSTR pszFmt)
  570. {
  571. LPSTR pszList;
  572. DWORD cbOff;
  573. pszList = DdeAccessData(hDataOut, NULL);
  574. #if WIN16
  575. if (_fstrstr(pszList, pszFmt) == NULL) {
  576. #else
  577. if (strstr(pszList, pszFmt) == NULL) {
  578. #endif
  579. cbOff = lstrlen(pszList);
  580. DdeUnaccessData(hDataOut);
  581. hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, 1, cbOff++);
  582. hDataOut = DdeAddData(hDataOut, (LPBYTE)pszFmt, lstrlen(pszFmt) + 1, cbOff);
  583. } else {
  584. DdeUnaccessData(hDataOut);
  585. }
  586. return(hDataOut);
  587. }
  588. HDDEDATA ReqFormats(
  589. HDDEDATA hDataOut,
  590. LPDDETOPICTBL ptpc)
  591. {
  592. int iItem, iFmt;
  593. LPDDEITEMTBL pitm;
  594. LPDDEFORMATTBL pfmt;
  595. hDataOut = DdeAddData(hDataOut, "", 1, 0);
  596. FOR_EACH_ITEM(ptpc, pitm, iItem) {
  597. FOR_EACH_FORMAT(pitm, pfmt, iFmt) {
  598. hDataOut = AddReqFormat(hDataOut, pfmt->pszFormat);
  599. }
  600. }
  601. return(hDataOut);
  602. }
  603. HDDEDATA DoWildConnect(
  604. HSZ hszTopic)
  605. {
  606. LPDDETOPICTBL ptpc;
  607. HDDEDATA hData;
  608. PHSZPAIR pHszPair;
  609. int iTopic, cTopics = 2;
  610. if (!hszTopic) {
  611. cTopics += pasi->cTopics;
  612. }
  613. hData = DdeCreateDataHandle(GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST),
  614. NULL,
  615. cTopics * sizeof(HSZPAIR),
  616. 0,
  617. 0,
  618. 0,
  619. 0);
  620. pHszPair = (HSZPAIR FAR *)DdeAccessData(hData, NULL);
  621. pHszPair->hszSvc = pasi->hszService;
  622. pHszPair->hszTopic = SSI.topic[0].hszTopic; // always support systopic.
  623. pHszPair++;
  624. ptpc = &pasi->topic[0];
  625. FOR_EACH_TOPIC(pasi, ptpc, iTopic) {
  626. if (hszTopic && DdeCmpStringHandles(hszTopic, ptpc->hszTopic)) {
  627. continue;
  628. }
  629. if (!DdeCmpStringHandles(ptpc->hszTopic, SSI.topic[0].hszTopic)) {
  630. continue; // don't enter systopic twice.
  631. }
  632. pHszPair->hszSvc = pasi->hszService;
  633. pHszPair->hszTopic = ptpc->hszTopic;
  634. pHszPair++;
  635. }
  636. pHszPair->hszSvc = 0;
  637. pHszPair->hszTopic = 0;
  638. DdeUnaccessData(hData);
  639. return(hData);
  640. }