home *** CD-ROM | disk | FTP | other *** search
/ BUG 4 / BUGCD1997_05.BIN / aplic / clip4win / clip4win.exe / C4W30E.HUF / SOURCE / DDE.PRG < prev    next >
Text File  |  1996-03-06  |  20KB  |  632 lines

  1. ////////////////////////////
  2. //
  3. //    Clip-4-Win sample source
  4. //
  5. //    Copyright (C) 1993 Skelton Software, Kendal Cottage, Hillam, Leeds, UK.
  6. //    All Rights Reserved.
  7. //
  8. //    Written by:    John M. Skelton, Jan. 93.
  9. //
  10. //    Compile:    dde /n /w
  11. //    Link:        /se:600 dde,,,clip4win,clip4win.def
  12. //
  13. ////////////////////////////
  14.  
  15. #define    WIN_WANT_CLIPBOARD
  16. #include "windows.ch"
  17. #include "dde.ch"
  18.  
  19. #define    CR    chr(13)
  20. #define    MAKELONG(low, high)    (low + (high * 65536))
  21. #define    MAKELPARAM(low, high)    (low + (high * 65536))
  22. #define    GMEM_DDESHARE    8192        // magic number for Windows
  23. #define    GMEM_MOVEABLE    2        // magic number for Windows
  24.  
  25.  
  26. #ifndef    LIB_ONLY            // for clip4win.lib use
  27.  
  28.  
  29.  
  30. static    cAppName := "Clip-4-Win"
  31. static    hWnd, hInst, hPrevInst, nCmdShow
  32. static    cText := ""
  33.  
  34.  
  35. function main()
  36. local hMenu, nEvent
  37. set scoreboard off
  38. setcolor("n/w,w/n,w,w,w/n")
  39. hWnd = WinSetup(cAppName, "Clip-4-Win Demo")
  40. hMenu = MenuSetup()
  41. HideCaret(hWnd)
  42. do while .t.
  43.    do while (nEvent := ChkEvent()) == EVENT_NONE
  44.       // "background" processing could go here
  45.    enddo
  46.    HandleEvent(nEvent)
  47.    do case
  48.    case nEvent == EVENT_QUIT
  49.         DoExit()
  50.    endcase
  51. enddo
  52. return nil
  53.  
  54.  
  55. procedure DoAbout()
  56. MessageBox( , "Demo written by John Skelton", "About", ;
  57.                MB_ICONEXCLAMATION + MB_OK)
  58. return
  59.  
  60.  
  61. procedure DoExit()
  62. quit
  63. return
  64.  
  65.  
  66. procedure DoServers()
  67. static    nX := 20, nY := 50
  68. local    nEvent, aDDE := {}, hWndProgMan, hWndPMClient
  69. local    hWndServer, hWndClient, hItem, i, s := "", hDC, aTM
  70.  
  71. // Broadcast to all DDE servers, asking for information (just to show how)
  72. // (Note: Program Manager does not reply, for no apparent reason)
  73. aDDE = DDEGetTopics(hWnd)
  74. //MessageBox( , nstr(len(aDDE)), "DDEGetTopics length", MB_OK)
  75. for i = 1 to len(aDDE)
  76.     s += aDDE[i, 1] + "|" + aDDE[i, 2] + CR
  77. next i
  78. MessageBox( , s, "DDE Servers and Topics", MB_OK)
  79. return
  80.  
  81.  
  82. procedure DoProgMan()
  83. static    nX := 20, nY := 50
  84. local    nEvent, aDDE := {}, hWndProgMan, hWndPMClient
  85. local    hWndServer, hWndClient, hItem, i, s := "", hDC, aTM
  86.  
  87. // Arrange to talk to Program Manager.
  88. //
  89. // Note: Both App and Topic need to be PROGMAN, rather surprisingly.
  90. hWndPMClient = WinNew(cAppName, "DDE Client", nX += 40, nY += 60, 150, 100)
  91. hWndProgMan = DDEStart(hWndPMClient, "PROGMAN", "PROGMAN")
  92. if hWndProgMan != nil
  93.     // Program Manager responded, and the conversation is on-going
  94.  
  95.     // let's get a Group list
  96.     // (Which arrives asynchronously, just to make things a pain)
  97.     AddHandler(hWndPMClient, {|nEvent| DDEPMgrEvent(nEvent, hWndPMClient, hWndProgMan)})
  98.     DDERequest(hWndProgMan, hWndPMClient, CF_TEXT)
  99. else
  100.     // no response
  101.     DestroyWindow(hWndPMClient)
  102. endif
  103. return
  104.  
  105.  
  106. procedure DDEPMgrEvent(nEvent, hWnd, hWndServer)
  107. static    lTerm := .f.
  108. local    nMsg := _LastMsg()        // Windows message
  109. local    cData
  110. if nEvent == EVENT_OTHER
  111. //    MessageBox( , nstr(nMsg), "DDEPMgrEvent", MB_OK)
  112. endif
  113. do case
  114. case nMsg == WM_DDE_DATA
  115.     // here's the data
  116.     cData = DDEGetData()
  117.     MessageBox( , cData, "DDEPMgrEvent: WM_DDE_DATA", MB_OK)
  118.  
  119.     // this example now terminates the conversation
  120.     lTerm = .t.
  121.     PostMessage(hWndServer, WM_DDE_TERMINATE, hWnd, 0)
  122. case nMsg == WM_DDE_ACK
  123.     // must be a negative ack., but shouldn't happen at all
  124. case nMsg == WM_DDE_TERMINATE
  125.     if !lTerm
  126.         // server wants to terminate, confirm by posting the msg back
  127.         PostMessage(hWndServer, WM_DDE_TERMINATE, hWnd, 0)
  128.     // else this is the reply from the server, confirming termination
  129.     endif
  130.     lTerm = .f.
  131.     DestroyWindow(hWnd)
  132. endcase
  133. return
  134.  
  135.  
  136.  
  137. // This shows how to use DDE Advise, with the SDK sample DDE server
  138. // (if you have it).
  139.  
  140. procedure DoSDK()
  141. static    nX := 20, nY := 50
  142. local    nEvent, aDDE := {}, hWndProgMan, hWndPMClient
  143. local    hWndServer, hWndClient, hItem, i, s := "", hDC, aTM
  144.  
  145. // Arrange to talk to SDK sample server.
  146. hWndClient = WinNew(cAppName, "DDE Client", nX += 40, nY += 60, 150, 100)
  147. hWndServer = DDEStart(hWndClient, "Server", "File1")
  148. if hWndServer != nil
  149.     // server responded, and the conversation is on-going
  150.  
  151.     // let's get an item
  152.     // (which arrives asynchronously, just to make things a pain)
  153.     AddHandler(hWndClient, {|nEvent| DDEEvent(nEvent, hWndClient, hWndServer)})
  154.     DDEAdvise(hWndServer, hWndClient, CF_TEXT, "Item1")
  155. else
  156.     // no response
  157.     DestroyWindow(hWndClient)
  158.     MessageBox( , "SDK Server not responding", "ERROR", MB_OK)
  159. endif
  160. return
  161.  
  162.  
  163. procedure DDEEvent(nEvent, hWnd, hWndServer)
  164. //static    aConv := {}            // active conversations
  165. static    lTerm := .f.
  166. static    nChg := 0
  167. local    nMsg := _LastMsg()        // Windows message
  168. local    cData
  169. if nEvent == EVENT_OTHER
  170. //    MessageBox( , nstr(nMsg), "DDE Event", MB_OK)
  171. endif
  172. do case
  173. case nMsg == WM_DDE_DATA
  174.     // here's the data
  175.     cData = DDEGetData()
  176.     MessageBox( , cData, "DDE Event: WM_DDE_DATA", MB_OK)
  177.     if ++nChg > 2
  178.         DDEUnAdvise(hWndServer, hWnd)
  179.     endif
  180.  
  181. //    // this example now terminates the conversation
  182. //    lTerm = .t.
  183. //    PostMessage(hWndServer, WM_DDE_TERMINATE, hWnd, 0)
  184. case nMsg == WM_DDE_ACK
  185.     // may be a negative ack., but shouldn't happen
  186. case nMsg == WM_CLOSE
  187. //    MessageBox( , "", "DDE Event: WM_CLOSE", MB_OK)
  188. #define    WM_QUIT    18
  189. case nMsg == WM_QUIT
  190. //    MessageBox( , "", "DDE Event: WM_QUIT", MB_OK)
  191. case nMsg == WM_DDE_TERMINATE
  192.     if !lTerm
  193.         // server wants to terminate, confirm by posting the msg back
  194.         if IsWindow(hWndServer)
  195.             PostMessage(hWndServer, WM_DDE_TERMINATE, hWnd, 0)
  196. //        else
  197. //            MessageBox( , "!IsWindow(hWndServer)", "DDE Event", MB_OK)
  198.         endif
  199.     // else this is the reply from the server, confirming termination
  200.     endif
  201.     lTerm = .f.
  202.     DestroyWindow(hWnd)
  203. endcase
  204. return
  205.  
  206.  
  207.  
  208. #endif // !LIB_ONLY
  209.  
  210.  
  211.  
  212. // Get all DDE Topics for cApp, or all Apps and Topics (if cApp is NIL)
  213.  
  214. function DDEGetTopics(hWnd, cApp)
  215. // you may prefer to change nAppAtom to hAppAtom (or not)
  216. local    nAppAtom := iif(cApp == nil, 0, GlobalAddAtom(cApp))    // 0 means all
  217. local    nEvent, aDDE := {}, hWndServer, hServer, hTopic, cServer, cTopic
  218.  
  219. // Broadcast to all DDE servers (apps), asking for information
  220. SendMessage(-1, WM_DDE_INITIATE, hWnd, nAppAtom)
  221. // any replies come straight back, and will be in the event queue
  222.  
  223. // Process the replies (Shell is usually there, but PROGMAN does not
  224. // reply even though you'd expect it to do so)
  225. do while (nEvent := ChkEvent()) != EVENT_NONE
  226.     if _LastMsg() == WM_DDE_ACK .and. _LasthWnd() == hWnd
  227.         hWndServer = _LastwParam()    // hWnd of server
  228.         hServer = _LastLolParam()    // server atom
  229.         hTopic = _LastHilParam()    // topic atom
  230.         cServer = GlobalGetAtomName(hServer)
  231.         cTopic = GlobalGetAtomName(hTopic)
  232.         aadd(aDDE, {cServer, cTopic, hWndServer})
  233.         // we're supposed to delete the atoms, even though we didn't
  234.         // create them...
  235.         GlobalDeleteAtom(hServer)
  236.         GlobalDeleteAtom(hTopic)
  237.         // it is not clear whether the following PostMessage()
  238.         // is required, not required, or redundant
  239.         PostMessage(hWndServer, WM_DDE_TERMINATE, hWnd, 0)
  240. //        MessageBox( , cServer + ":" + cTopic, "DDE Server:Topic", MB_OK)
  241.         loop
  242.     endif
  243.     HandleEvent(nEvent)
  244. enddo
  245. // all the replies have been processed
  246. if nAppAtom != 0
  247.     GlobalDeleteAtom(nAppAtom)    // clean up, if we added the atom
  248. endif
  249. return aDDE
  250.  
  251.  
  252.  
  253. // Start a DDE conversation from window hWnd to cApp about cTopic
  254.  
  255. function DDEStart(hWnd, cApp, cTopic)
  256. local    nAppAtom := iif(cApp == nil, 0, GlobalAddAtom(cApp))    // 0 means all
  257. local    nTopicAtom := iif(cTopic == nil, 0, GlobalAddAtom(cTopic))  // 0 means all
  258. local    nEvent, hWndServer, hServer, hTopic, cServer
  259.  
  260. // Broadcast to the DDE server (app), to start a conversation
  261. SendMessage(-1, WM_DDE_INITIATE, hWnd, MAKELONG(nAppAtom, nTopicAtom))
  262. // any replies come straight back, and will be in the event queue
  263. //
  264. // process the replies (we only want ONE, of course)
  265. do while (nEvent := ChkEvent()) != EVENT_NONE
  266.     if _LastMsg() == WM_DDE_ACK .and. _LasthWnd() == hWnd
  267.         if hWndServer != nil
  268.             MessageBox( , ltrim(str(hWndServer)), "DDEStart: another reply", MB_OK)
  269.         endif
  270.         hWndServer = _LastwParam()    // hWnd of server
  271.         hServer = _LastLolParam()    // server atom
  272.         hTopic = _LastHilParam()    // topic atom
  273. //        cServer = GlobalGetAtomName(hServer)
  274. //        cTopic = GlobalGetAtomName(hTopic)
  275.         GlobalDeleteAtom(hServer)
  276.         GlobalDeleteAtom(hTopic)
  277. //        MessageBox( , cServer + ":" + cTopic, "DDE Server:Topic", MB_OK)
  278.         loop
  279.     endif
  280.     HandleEvent(nEvent)
  281. enddo
  282. // all the replies have been processed
  283. if nAppAtom != 0
  284.     GlobalDeleteAtom(nAppAtom)    // clean up, if we added the atom
  285. endif
  286. if nTopicAtom != 0
  287.     GlobalDeleteAtom(nTopicAtom)    // clean up, if we added the atom
  288. endif
  289. return hWndServer
  290.  
  291.  
  292.  
  293. // Post a message to stop the DDE conversation to hWndServer from hWndClient
  294.  
  295. procedure DDEStop(hWndServer, hWndClient)
  296. PostMessage(hWndServer, WM_DDE_TERMINATE, hWndClient, 0)
  297. return
  298.  
  299.  
  300.  
  301. // Request the current value of item cItem in format nFmt
  302. // (the data comes back with a WM_DDE_DATA message).
  303.  
  304. procedure DDERequest(hWndServer, hWndClient, nFmt, cItem)
  305. local    nAtom := iif(cItem == nil, 0,        ; // 0 means all or default
  306.              GlobalAddAtom(cItem))
  307. if nFmt == nil
  308.     nFmt = CF_TEXT
  309. endif
  310. PostMessage(hWndServer, WM_DDE_REQUEST, hWndClient, MAKELPARAM(nFmt, nAtom))
  311. return
  312.  
  313.  
  314.  
  315. // Get the DDE data corresponding to a WM_DDE_DATA message
  316. // (which must be the most recent message).
  317. //
  318. // hWndServer defaults to the sender of the WM_DDE_DATA message,
  319. // hWndClient defaults to the receiver of the WM_DDE_DATA message.
  320.  
  321. function DDEGetData(hWndServer, hWndClient)
  322. local    hData, cData, nAtom, cAtom, nFlags, nFmt
  323. hData = _LastLolParam()
  324. nAtom = _LastHilParam()
  325. cAtom = iif(nAtom == 0, "<none>", GlobalGetAtomName(nAtom))
  326. cData = GlobalData(hData)
  327. nFlags = c4w_bin2i(cData)
  328. nFmt = c4w_bin2i(substr(cData, 3, 2))
  329. //MessageBox( , nstr(nFlags) + nstr(nFmt), "DDE Data flags + fmt", MB_OK)
  330. cData = substr(cData, 5)
  331. //MessageBox( , cAtom + " = " + cData, "DDE Atom + Data", MB_OK)
  332. if c4w_and(nFlags, 32768) != 0
  333.     // ack requested
  334.     if hWndServer == nil
  335.         hWndServer = _LastwParam()
  336.     endif
  337.     if hWndClient == nil
  338.         hWndClient = _LasthWnd()
  339.     endif
  340.     PostMessage(hWndServer, WM_DDE_ACK, hWndClient, MAKELONG(32768, nAtom))
  341. endif
  342. if c4w_and(nFlags, 8192) != 0
  343.     // need to release the data
  344.     GlobalFree(hData)
  345. endif
  346. return cData
  347.  
  348.  
  349.  
  350. // Modified from a function kindly donated by Hugh Lokey.
  351. //
  352. // This function does a lot of grunt work.  It issues the DDE
  353. // EXECUTE commands and if a reply is required waits for the reply.
  354. //
  355. // Calling conventions:
  356. //
  357. //   hServerWnd - handle/channel of DDE server.  Obtained
  358. //                from DDEStart() command.
  359. //   hClientWnd - handle of client window.
  360. //   cItem      - Execute command item.
  361. //   lReply     - .T. if a reply is required, .F. if not, defaults to .F.
  362. //                (the reply is in the form of a WM_DDE_DATA message).
  363. //   NOTE: All servers are supposed to send a positive/negative
  364. //         acknowledgement in the form of a WM_DDE_ACK message, so this
  365. //         is waited for in any case.  lReply determines whether the
  366. //         WM_DDE_ACK is also followed by WM_DDE_DATA.
  367. //   cMsg       - Required response from DDE server.
  368. //   cExit      - an optional string the server might send to say it is
  369. //                shutting down (you'd really expect WM_DDE_TERMINATE).
  370.  
  371. // Advanced use only:
  372. // =================
  373. // For a true "generic" DDEExecute() you would NOT do any message
  374. // handling, just send the command and handle what happens elsewhere.
  375. // The easiest way to do this would be to remove lReply, cMsg and cExit,
  376. // delete the DO WHILE .T. loop, and also delete the GlobalFree().
  377. // Returning the hExecute would allow you to keep track of it so it
  378. // could be GlobalFree()'ed later.
  379. // You'd probably want to use something like a state machine to control
  380. // each step of the DDE conversation.  If you do this, you need to keep
  381. // in mind that YOU MUST free the global memory allocated by the
  382. // GlobalAlloc() call after you have processed the results of the command.
  383.  
  384. // If you really want, you can leave out the HandleEvent()
  385. // and restrict the user to not being able to do anything funny
  386. // while the command is being processed by the DDE server.
  387.  
  388. FUNCTION DDEExecute(hServerWnd, hClientWnd,  cItem, lReply, cMsg, cExit)
  389.        LOCAL  hExecute := GlobalAlloc(GMEM_MOVEABLE+GMEM_DDESHARE,   ;
  390.                                       LEN(cItem)+1)
  391.        LOCAL  nMsg, nEvent, cData
  392.        LOCAL  nStatus
  393.  
  394.        GlobalData(hExecute,cItem+CHR(0))
  395.        PostMessage(hServerWnd,;
  396.                    WM_DDE_EXECUTE,;
  397.                    hClientWnd,;
  398.                    MAKELPARAM(0, hExecute))
  399.        if lReply == nil
  400.           lReply := .f.
  401.        endif
  402.        DO WHILE .T.
  403.           DO WHILE (nEvent := ChkEvent()) != EVENT_OTHER
  404.              HandleEvent(nEvent)
  405.           ENDDO
  406.           nMsg := _LastMsg()
  407.           IF nMsg = WM_DDE_ACK
  408.              nStatus := _LastLolParam()
  409.              if c4w_and(nStatus, 32768) == 0
  410.                 EXIT            // server rejected the WM_DDE_EXECUTE
  411.              endif
  412.              IF !lReply
  413.                 EXIT            // seen the ACK, and don't want DATA
  414.              ENDIF
  415.           ENDIF
  416.           IF nMsg = WM_DDE_DATA
  417.              cData := DDEGetData(hServerWnd,hClientWnd)
  418.              IF cMsg == nil .or. UPPER(cData) = UPPER(cMsg)
  419.                 EXIT
  420.              ENDIF
  421.           ENDIF
  422.           IF nMsg = WM_DDE_TERMINATE .OR. cData == cExit
  423.              DDEStop(hServerWnd,hClientWnd)
  424.              EXIT
  425.           ENDIF
  426.        ENDDO
  427.        GlobalFree(hExecute)
  428. RETURN nil
  429.  
  430.  
  431.  
  432. // Post data to a server.  Any well-behaved server will reply with
  433. // a WM_DDE_ACK message containing an indication of whether the server
  434. // accepted the WM_DDE_POKE.
  435. //
  436. // nFmt is the format of the data (default CF_TEXT).
  437. // cItem identifies the data.
  438. // cData is the data itself.
  439. // lRelease should be .t. if the server should release the memory allocated
  440. //          to contain the cData, .f. if this function should release it
  441. //          (default is .t.).
  442. // lWait can be .f. to NOT wait for the server's WM_DDE_ACK message
  443. //          (default is .t., because the server should respond).
  444. //
  445. // Returns:
  446. //         if lWait was .f., handle to memory
  447. //         otherwise, .t. if server accepted the POKE, .f. if it rejected it
  448.  
  449. function DDEPoke(hWndServer, hWndClient, nFmt, cItem, cData, lRelease, lWait)
  450. local    nAtom := iif(cItem == nil, 0, GlobalAddAtom(cItem))
  451. local    nFlags, hData, nEvent, nMsg, nStatus, xRet
  452. if nFmt == nil
  453.     nFmt = CF_TEXT
  454. endif
  455. if lRelease == nil
  456.     lRelease = .t.
  457. endif
  458. nFlags = iif(lRelease, 8192, 0)
  459. // need hData for DDEPOKE structure
  460. hData = GlobalAlloc(GMEM_MOVEABLE + GMEM_DDESHARE, 4 + len(cData))
  461. GlobalData(hData, c4w_i2bin(nFlags) + c4w_i2bin(nFmt) + cData)
  462. //MessageBox( , nstr(hWndServer) + nstr(hWndClient) + nstr(hData) + nstr(nAtom), "srv cli data atom", MB_OK)
  463. PostMessage(hWndServer, WM_DDE_POKE, hWndClient, MAKELPARAM(hData, nAtom))
  464. if lWait == .f.
  465.    xRet = hData
  466. else
  467.    DO WHILE .T.
  468.       DO WHILE (nEvent := ChkEvent()) != EVENT_OTHER
  469.          HandleEvent(nEvent)
  470.       ENDDO
  471.       nMsg := _LastMsg()
  472.       IF nMsg = WM_DDE_ACK
  473.          nStatus := _LastLolParam()
  474.          if c4w_and(nStatus, 32768) == 0
  475.             xRet = .f.        // server rejected the WM_DDE_EXECUTE
  476.             GlobalFree(hData)
  477.          else
  478.             xRet = .t.        // normal exit
  479.             if lRelease
  480.                GlobalFree(hData)
  481.             endif
  482.          endif
  483.          GlobalDeleteAtom(_LastHilParam())
  484.          EXIT
  485.       ENDIF
  486.       IF nMsg = WM_DDE_TERMINATE
  487.          DDEStop(hWndServer,hWndClient)
  488.          GlobalFree(hData)
  489.          EXIT
  490.       ENDIF
  491.    ENDDO
  492. endif
  493. RETURN xRet                // .t. or .f. or hData
  494.  
  495.  
  496.  
  497. // Ask to be kept informed of changes to the item cItem; the server will
  498. // automatically send WM_DDE_DATA messages whenever the data changes.
  499. // Usually you will not specify lDeferUpd or lAckReq.
  500. // If lDeferUpd is .t., these data messages will not contain the actual
  501. // data, which must be requested when it is actually needed.
  502. // If lAckReq is .t., these data messages sent by the server will specify
  503. // that a WM_DDE_ACK message is wanted.
  504.  
  505. procedure DDEAdvise(hWndServer, hWndClient, nFmt, cItem, lDeferUpd, lAckReq)
  506. local    nAtom := iif(cItem == nil, 0, GlobalAddAtom(cItem))
  507. local    nFlags, hOptions
  508. if nFmt == nil
  509.     nFmt = CF_TEXT
  510. endif
  511. nFlags = iif(lDeferUpd != nil .and. lDeferUpd, 16384, 0)
  512. nFlags += iif(lAckReq != nil .and. lAckReq, 32768, 0)
  513. // need hData for DDEADVISE struct
  514. hOptions = GlobalAlloc(GMEM_MOVEABLE + GMEM_DDESHARE, 4)
  515. GlobalData(hOptions, c4w_i2bin(nFlags) + c4w_i2bin(nFmt))
  516. //MessageBox( , nstr(hWndServer) + nstr(hWndClient) + nstr(hOptions) + nstr(nAtom), "srv cli opt atom", MB_OK)
  517. PostMessage(hWndServer, WM_DDE_ADVISE, hWndClient, MAKELPARAM(hOptions, nAtom))
  518. return
  519.  
  520.  
  521.  
  522. // Turn off being advised about changes to data item(s)
  523.  
  524. procedure DDEUnAdvise(hWndServer, hWndClient, nFmt, cItem)
  525. local    nAtom := iif(cItem == nil, 0, GlobalAddAtom(cItem))  // 0 means all
  526. if nFmt == nil
  527.     nFmt = 0            // means all formats
  528. endif
  529. PostMessage(hWndServer, WM_DDE_UNADVISE, hWndClient, MAKELPARAM(nFmt, nAtom))
  530. return
  531.  
  532.  
  533.  
  534.  
  535. #ifndef    LIB_ONLY            // for clip4win.lib use
  536.  
  537.  
  538. function nstr(n)
  539. return alltrim(str(n)) + " "
  540.  
  541.  
  542.  
  543. function asString(x)
  544. local    v := valtype(x)
  545. do case
  546.    case v == "C"
  547.    case v == "N"
  548.       return nstr(x)
  549.    case v == "L"
  550.       if x
  551.          return ".T."
  552.       else
  553.          return ".F."
  554.       endif
  555.    case v == "D"
  556.       return "date"
  557.    case v == "U"
  558.       return "NIL"
  559.    case v $ "AOB"
  560.       return ""
  561.    otherwise
  562.       return ""
  563. end case
  564. return x
  565.  
  566.  
  567. function MenuSetup()
  568. local    hWnd := SelectWindow(), hMenu, hPopupMenu
  569.  
  570. if (hMenu := GetMenu(hWnd)) != nil
  571.     DestroyMenu(hMenu)
  572. endif
  573.  
  574. // do new one (forget old value)
  575. hMenu = CreateMenu()
  576. hPopupMenu = CreatePopupMenu()
  577. AppendMenu(hMenu, "dde", MF_ENABLED + MF_POPUP, "&DDE", hPopupMenu)
  578. AppendMenu(hPopupMenu, "servers", MF_ENABLED + MF_STRING, "&All Servers", {|| DoServers()})
  579. AppendMenu(hPopupMenu, "progman", MF_ENABLED + MF_STRING, "&ProgMan Groups", {|| DoProgMan()})
  580. AppendMenu(hPopupMenu, "sdk", MF_ENABLED + MF_STRING, "&SDK", {|| DoSDK()})
  581. AppendMenu(hPopupMenu, "", MF_SEPARATOR)
  582. AppendMenu(hPopupMenu, "exit", MF_ENABLED + MF_STRING, "E&xit", {|| DoExit() })
  583. hPopupMenu = CreatePopupMenu()
  584. AppendMenu(hMenu, "help", MF_ENABLED + MF_POPUP, "&Help", hPopupMenu)
  585. AppendMenu(hPopupMenu, "about", MF_ENABLED + MF_STRING, "&About", {|| DoAbout()})
  586. SetMenu(hWnd, hMenu)
  587. return hMenu
  588.  
  589.  
  590. // function AddHandler(hWnd, bAction)  // --> nId  (for use with DelHandler)
  591. // see: evhand.prg
  592.  
  593.  
  594. // procedure DelHandler(nId)
  595. // see: evhand.prg
  596.  
  597.  
  598. // procedure HandleEvent(nEvent)
  599. // see: evhand.prg
  600.  
  601.  
  602.  
  603. function WinNew(cAppName, cTitle, nX, nY, nWidth, nHeight)
  604. local    hWin, hInst, nCmdShow
  605. hInst = _GetInstance()
  606. nCmdShow = _GetnCmdShow()
  607. hWin = CreateWindow(cAppName,        ;    // window class
  608.             cTitle,         ;    // caption for title bar
  609.             WS_OVERLAPPEDWINDOW,;    // window style
  610.             nX,            ;    // x co-ordinate
  611.             nY,            ;    // y co-ordinate
  612.             nWidth,        ;    // width
  613.             nHeight,        ;    // height
  614.             hWnd,        ;    // hWnd of parent
  615.             0,            ;    // hMenu of menu (none yet)
  616.             hInst)            // our own app instance
  617. if hWin == 0
  618.    // probably out of resources
  619.    MessageBox( , "Can't create window", "Error", MB_ICONEXCLAMATION + MB_OK)
  620.    return nil
  621. endif
  622. HideCaret(hWin)
  623. // make sure it's displayed ...
  624. ShowWindow(hWin, nCmdShow)
  625. // ... and up to date
  626. UpdateWindow(hWin)
  627. return hWin
  628.  
  629.  
  630. #endif // !LIB_ONLY
  631.  
  632.