Announcement

Collapse
No announcement yet.

A simple DDE client example

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    A simple DDE client example

    this code was originally in the thread "dde client - how to simply send a message to
    another app" at http://www.powerbasic.com/support/pb...ead.php?t=3762

    Code:
    ' a very basic example connecting to pegasus mail with dde and sending a test message
     
    type security_quality_of_service
      length as dword
      impersonationlevel as long
      contexttrackingmode as byte
      effectiveonly as byte
    end type
     
    type convcontext
      cb as dword
      wflags as dword      ' yes, this is supposed to be a dword
      wcountryid as dword  ' yes, this is supposed to be a dword
      icodepage as long
      dwlangid as dword
      dwsecurity as dword
      qos as security_quality_of_service
    end type
     
    type convinfo
      cb as dword
      huser as dword
      hconvpartner as long
      hszsvcpartner as long
      hszservicereq as long
      hsztopic as dword
      hszitem as dword
      wfmt as dword
      wtype as dword
      wstatus as dword
      wconvst as dword
      wlasterror as dword
      hconvlist as dword
      convctxt as convcontext
      hwnd as dword
      hwndpartner as long
    end type
     
    %cf_text            =  1
     
    %cbf_fail_selfconnections   = &h1000
    %cbf_fail_connections       = &h2000
    %cbf_fail_advises           = &h4000
    %cbf_fail_executes          = &h8000
    %cbf_fail_pokes             = &h10000
    %cbf_fail_requests          = &h20000
    %cbf_fail_allsvrxactions    = &h3f000
     
    %cbf_skip_connect_confirms  = &h40000
    %cbf_skip_registrations     = &h80000
    %cbf_skip_unregistrations   = &h100000
    %cbf_skip_disconnects       = &h200000
    %cbf_skip_allnotifications  = &h3c0000
     
    ' application command flags
    %appcmd_clientonly  = &h10&
    %appcmd_filterinits = &h20&
    %appcmd_mask        = &hff0&
     
    ' application classification flags
    %appclass_standard  = &h0&
    %appclass_mask      = &hf&
     
    %dmlerr_no_error            = 0      '  must be 0
     
    %dmlerr_first               = &h4000
     
    %dmlerr_advacktimeout       = &h4000
    %dmlerr_busy                = &h4001
    %dmlerr_dataacktimeout      = &h4002
    %dmlerr_dll_not_initialized = &h4003
    %dmlerr_dll_usage           = &h4004
    %dmlerr_execacktimeout      = &h4005
    %dmlerr_invalidparameter    = &h4006
    %dmlerr_low_memory          = &h4007
    %dmlerr_memory_error        = &h4008
    %dmlerr_notprocessed        = &h4009
    %dmlerr_no_conv_established = &h400a
    %dmlerr_pokeacktimeout      = &h400b
    %dmlerr_postmsg_failed      = &h400c
    %dmlerr_reentrancy          = &h400d
    %dmlerr_server_died         = &h400e
    %dmlerr_sys_error           = &h400f
    %dmlerr_unadvacktimeout     = &h4010
    %dmlerr_unfound_queue_id    = &h4011
     
    %dmlerr_last                = &h4011
     
    %dde_fack         = &h8000
    %dde_fbusy        = &h4000
    %dde_fdeferupd    = &h4000
    %dde_fackreq      = &h8000
    %dde_frelease     = &h2000
    %dde_frequested   = &h1000
    %dde_fappstatus   = &hff
    %dde_fnotprocessed= &h0
     
    %dde_fackreserved = not (%dde_fack or %dde_fbusy or %dde_fappstatus)
    %dde_fadvreserved = not (%dde_fackreq or %dde_fdeferupd)
    %dde_fdatreserved = not (%dde_fackreq or %dde_frelease or %dde_frequested)
    %dde_fpokreserved = not (%dde_frelease)
     
    %mh_create  = 1
    %mh_keep    = 2
    %mh_delete  = 3
    %mh_cleanup = 4
     
    %max_monitors     = 4
    '  transaction types
    %xtypf_noblock = &h2???     '  cbr_block will not work
    %xtypf_nodata  = &h4???     '  dde_fdeferupd
    %xtypf_ackreq  = &h8???     '  dde_fackreq
     
    %xclass_mask         = &hfc00???
    %xclass_bool         = &h1000???
    %xclass_data         = &h2000???
    %xclass_flags        = &h4000???
    %xclass_notification = &h8000???
     
    %xtyp_error           = &h0 or %xclass_notification or %xtypf_noblock
    %xtyp_advdata         = &h10 or %xclass_flags
    %xtyp_advreq          = &h20 or %xclass_data or %xtypf_noblock
    %xtyp_advstart        = &h30 or %xclass_bool
    %xtyp_advstop         = &h40 or %xclass_notification
    %xtyp_execute         = &h50 or %xclass_flags
    %xtyp_connect         = &h60 or %xclass_bool or %xtypf_noblock
    %xtyp_connect_confirm = &h70 or %xclass_notification or %xtypf_noblock
    %xtyp_xact_complete   = &h80 or %xclass_notification
    %xtyp_poke            = &h90 or %xclass_flags
    %xtyp_register        = &ha0 or %xclass_notification or %xtypf_noblock
    %xtyp_request         = &hb0 or %xclass_data
    %xtyp_disconnect      = &hc0 or %xclass_notification or %xtypf_noblock
    %xtyp_unregister      = &hd0 or %xclass_notification or %xtypf_noblock
    %xtyp_wildconnect     = &he0 or %xclass_data or %xtypf_noblock
     
    %xtyp_mask            = &hf0
    %xtyp_shift           = 4  '  shift to turn xtyp_ into an index
     
    %appclass_monitor = &h1&
    %xtyp_monitor     = &hf0 or %xclass_notification or %xtypf_noblock
     
    ' callback filter flags for use with monitor apps - 0 implies no monitor callbacks
    %mf_hsz_info  = &h1000000
    %mf_sendmsgs  = &h2000000
    %mf_postmsgs  = &h4000000
    %mf_callbacks = &h8000000
    %mf_errors    = &h10000000
    %mf_links     = &h20000000
    %mf_conv      = &h40000000
    %mf_mask      = &hff000000
     
    %cp_winansi    = 1004  '  default codepage for windows old dde convs.
    %cp_winunicode = 1200
     
    %true = 1
    %false = 0
      
    declare function ddeabandontransaction lib "user32.dll" alias "ddeabandontransaction" (byval idinst as long, byval hconv as long, byval idtransaction as long) as long
    declare function ddeaccessdata lib "user32.dll" alias "ddeaccessdata" (byval hdata as long, pcbdatasize as long) as long
    declare function ddeadddata lib "user32.dll" alias "ddeadddata" (byval hdata as long, psrc as byte, byval cb as long, byval cboff as long) as long
    declare function ddeclienttransaction lib "user32.dll" alias "ddeclienttransaction" ( byval pdata as byte ptr, byval cbdata as long, byval hconv as long, byval hszitem as long, byval wfmt as long, byval wtype as long, byval dwtimeout as long, _
                     pdwresult as long) as long
    declare function ddecmpstringhandles lib "user32.dll" alias "ddecmpstringhandles" (byval hsz1 as long, byval hsz2 as long) as long
    declare function ddeconnect lib "user32.dll" alias "ddeconnect" (byval idinst as long, byval hszservice as long, byval hsztopic as long, pcc as convcontext) as long
    declare function ddeconnectlist lib "user32.dll" alias "ddeconnectlist" (byval idinst as long, byval hszservice as long, byval hsztopic as long, byval hconvlist as long, pcc as convcontext) as long
    declare function ddecreatedatahandle lib "user32.dll" alias "ddecreatedatahandle" (byval idinst as long, psrc as byte, byval cb as long, byval cboff as long, byval hszitem as long, byval wfmt as long, byval afcmd as long) as long
    declare function ddecreatestringhandle lib "user32.dll" alias "ddecreatestringhandlea" (byval idinst as long, psz as asciiz, byval icodepage as long) as long
    declare function ddedisconnect lib "user32.dll" alias "ddedisconnect" (byval hconv as long) as long
    declare function ddedisconnectlist lib "user32.dll" alias "ddedisconnectlist" (byval hconvlist as long) as long
    declare function ddeenablecallback lib "user32.dll" alias "ddeenablecallback" (byval idinst as long, byval hconv as long, byval wcmd as long) as long
    declare function ddefreedatahandle lib "user32.dll" alias "ddefreedatahandle" (byval hdata as long) as long
    declare function ddefreestringhandle lib "user32.dll" alias "ddefreestringhandle" (byval idinst as long, byval hsz as long) as long
    declare function ddegetdata lib "user32.dll" alias "ddegetdata" (byval hdata as long, pdst as byte, byval cbmax as long, byval cboff as long) as long
    declare function ddegetlasterror lib "user32.dll" alias "ddegetlasterror" (byval idinst as long) as long
    declare function ddeimpersonateclient lib "user32.dll" alias "ddeimpersonateclient" (byval hconv as long) as long
    declare function ddeinitialize lib "user32.dll" alias "ddeinitializea" (pidinst as long, byval pfncallback as long, byval afcmd as long, byval ulres as long) as long
    declare function ddekeepstringhandle lib "user32.dll" alias "ddekeepstringhandle" (byval idinst as long, byval hsz as long) as long
    declare function ddenameservice lib "user32.dll" alias "ddenameservice" (byval idinst as long, byval hsz1 as long, byval hsz2 as long, byval afcmd as long) as long
    declare function ddepostadvise lib "user32.dll" alias "ddepostadvise" (byval idinst as long, byval hsztopic as long, byval hszitem as long) as long
    declare function ddequeryconvinfo lib "user32.dll" alias "ddequeryconvinfo" (byval hconv as long, byval idtransaction as long, pconvinfo as convinfo) as long
    declare function ddequerynextserver lib "user32.dll" alias "ddequerynextserver" (byval hconvlist as long, byval hconvprev as long) as long
    declare function ddequerystring lib "user32.dll" alias "ddequerystring" (byval idinst as long, byval hsz as long, psz as asciiz, byval cchmax as long, byval icodepage as long) as long
    declare function ddereconnect lib "user32.dll" alias "ddereconnect" (byval hconv as long) as long
    declare function ddesetqualityofservice lib "user32.dll" alias "ddesetqualityofservice" (byval hwndclient as long, pqosnew as security_quality_of_service, pqosprev as security_quality_of_service) as long
    declare function ddesetuserhandle lib "user32.dll" alias "ddesetuserhandle" (byval hconv as long, byval id as long, byval huser as long) as long
    declare function ddeunaccessdata lib "user32.dll" alias "ddeunaccessdata" (byval hdata as long) as long
    declare function ddeuninitialize lib "user32.dll" alias "ddeuninitialize" (byval idinst as long) as long
    
     
    function dde_callbackfunc(byval utype as dword, byval ufmt as long, byval hconv as long, byval hsztopic as long, byval hszitem as long, byval hdata as long, byval dwdata1 as dword, byval dwdata2 as dword) as long
        'for monitoring and server apps
    end function
      
    function pbmain() as long
        local i as long
        local lid as long
        local hconvhandle as long
        local hservice as long
        local htopicmessage as long
        local htopictcp as long
        local hitemmessage as long
        local hitemtcp as long
        local lresult as long
        local tddeconv as convcontext
        dim scmd(0:10) as string
     
        'since we are client only we decline to receive callbacks
        if ddeinitialize( lid, codeptr(dde_callbackfunc), %appcmd_clientonly, 0 ) <> 0 then
            stdout "failed to initialize dde - exiting"
            exit function
        end if
     
        'create string handle for the service
        hservice = ddecreatestringhandle( lid, "winpmail", %cp_winansi )
        if hservice = 0 then
            goto clean_up
        end if
     
        'create string handle for the topic
        htopicmessage = ddecreatestringhandle( lid, "message", %cp_winansi )
        if htopicmessage = 0 then
            goto clean_up
        end if
     
        'connect (start conversation)
        tddeconv.cb = sizeof(tddeconv)
        tddeconv.icodepage = %cp_winansi
     
        hconvhandle = ddeconnect( lid, hservice, htopicmessage, tddeconv )
        if hconvhandle = 0 then
            goto clean_up
        end if
     
        'create item string handle for poke request
        hitemmessage = ddecreatestringhandle( lid, "message", %cp_winansi )
        if hitemmessage = 0 then
            goto clean_up
        end if
     
        scmd(0) = "new: message" + chr$(0)
        scmd(1) = "defaults: y" + chr$(0)
        scmd(2) = "to: florent.heywo[email protected]" + chr$(0)
        scmd(3) = "subject: a test message" + chr$(0)
        scmd(4) = "data: here it is" + chr$(0)
        scmd(5) = "data: one line per %xtyp_poke" + chr$(0)
        scmd(6) = "data: is the way that pegasus mail" + chr$(0)
        scmd(7) = "data: processes the message body" + chr$(0)
        scmd(8) = "data: this seems to work ok" + chr$(0)
        scmd(9) = "data: as it is now" + chr$(0)
        scmd(10) = "send" + chr$(0)
     
        do
            lresult = ddeclienttransaction( strptr(scmd(i)), len(scmd(i)), hconvhandle, hitemmessage, %cf_text, %xtyp_poke, 3000, byval 0 )
            if lresult then
                call ddefreedatahandle( lresult )
            end if
            incr i
        loop while i < ubound(scmd(),1)+1
        call ddedisconnect( hconvhandle ): hconvhandle = 0
     
        'create string handle for the topic
        htopictcp = ddecreatestringhandle( lid, "tcp", %cp_winansi )
        if htopictcp = 0 then
            goto clean_up
        end if
     
        'create item string handle for poke request
        hitemtcp = ddecreatestringhandle( lid, "tcp", %cp_winansi )
        if hitemmessage = 0 then
            goto clean_up
        end if
     
        hconvhandle = ddeconnect( lid, hservice, htopictcp, tddeconv )
        if hconvhandle = 0 then
            goto clean_up
        end if
     
        lresult = ddeclienttransaction( strptr(scmd(10)), len(scmd(10)), hconvhandle, hitemtcp, %cf_text, %xtyp_poke, 3000, byval 0 )
        if lresult then
            call ddefreedatahandle( lresult )
        end if
     
    clean_up:
        if hconvhandle then
            call ddedisconnect( hconvhandle )
        end if
     
        if hitemmessage then
            call ddefreestringhandle( lid, hitemmessage )
        end if
     
        if hitemtcp then
            call ddefreestringhandle( lid, hitemtcp )
        end if
     
        if htopicmessage then
            call ddefreestringhandle( lid, htopicmessage )
        end if
     
        if htopictcp then
            call ddefreestringhandle( lid, htopictcp )
        end if
     
        if hservice then
            call ddefreestringhandle( lid, hservice )
        end if
     
        call ddeuninitialize( lid )
     
        print "finished"
        waitkey$
     
    end function
    ------------------

    #2
    pb/cc dde client - using microsoft 'excel' as server

    after exchanging e-mails with mr heyworth, we figured this code belongs as a reply here rather than in a separate message.

    mcm

    update / edit 7/6/01

    added the #if 0 ... #endif block at the end to show the code to update an excel spreadsheet.
    mcm

    Code:
    #if 0
    ' file: ddeclnt2.bas for pb/cc v 2.0
    ' original author: florent heyworth, zurich switzerland, may, 2001
    '  appeared at [url="http://www.powerbasic.com/support/pbforums/showthread.php?t=23058"]http://www.powerbasic.com/support/pbforums/showthread.php?t=23058[/url] 
    ' author, this version: michael mattias, racine wi usa. changed to make this client app do a simple request
    '  for text data from a dde server. added autostart of dde server, extensive commenting, changed
    '  a few datanames for consistency within the application.
    ' copyright/redistribution: placed in the public domain by both authors (june, 2001)
    ' purpose: demonstration of dde client using the ddeml libraries; and how to start the
    '  server if it is not running.
    ' in this case, i used microsoft excel(r) as the dde server.
    ' requesting items from excel:
    '  contents of a single cell:   rncn, where rn = row#, cn = columns number. example: "r2c12" will
    '   retrieve the contents of row 2, column 12
    '  contents of a range of cells: rncn:rmcm returns a range. within a range, column items within a row '
    '   are delimited by tab (ascii x'09'); rows are terminated by crlf.
    '  example: "r1c1:r2c3" returns  r1c1<tab>r1c2<tab>r1c3<crlf>r2c1<tab>r2c2<tab>r2c3<crlf>
    ' requesting other items from excel:
    '  i "believe" there are ways to use excel functions such as lookup and sum, etc, but i was unable
    '  to figure out the 'item' syntax required. (i'm also not an "excel guy" )(mcm).
    '  the excel documentation, both that provided with excel and in the msdn are really weak on the
    '  list of supported dde topics and items. i got the "topic" syntax from the mercator(r) manuals.
    ' what this code does not do, except with brute force:
    '  allow for someone to terminate excel with an open conversation.
    ' self-starting server: tested with excel not running, excel running and target sheet loaded,
    '  excel running but no sheets loaded, excel running with another sheet loaded. all work fine.
    '  the use of waitforinputidle assumes the server is a gui program (which ms excel is). according to
    '  the win32 sdk, it will fail if the "waited for" application is a console program. (not tested).
    ' excel version used for test: "excel 2000 v 9.0.2720"
    ' excel is a registered tradmark of microsoft corporation redmond wa usa
    
    #endif
    
    ' don't allow pb to assign register variables.
    #register none
    #debug error on
    #include "win32api.inc"     ' <<< see notes below, as there are variations in the pb-supplied win32api.inc
    
    ' text messages from getlasterror
    declare function systemerrormessagetext (byval ecode as long) as string
    function systemerrormessagetext (byval ecode as long) as string
      local buffer as asciiz * 255
      formatmessage %format_message_from_system, byval %null, ecode, %null, buffer, sizeof(buffer), byval %null
      function = format$(ecode, "(#####) ") & buffer
    end function
    
    declare function startserver (szfile as asciiz * %max_path) as long
    ' assumes there is an application associated with the extension of file, e.g., ".xls" for an excel spreadsheet
    
    declare function ddeclientcc () as long
    declare function ddeerrortext (byval dmlerr as long) as string
    
    function dde_callbackfunc(byval utype as dword, byval ufmt as long, byval hconv as long, byval hsztopic as long, byval hszitem as long, byval hdata as long, byval dwdata1 as dword, byval dwdata2 as dword) as long
        'for monitoring and server apps
    end function
    ' declare not in my pb/cc win32api.inc file
    declare function shellexecuteex lib "shell32.dll" alias "shellexecuteexa" (lpshellinfo as shellexecuteinfo) as long
    
    function winmain (byval hcurinstance  as long, _
                      byval hprevinstance as long, _
                      lpszcmdline         as asciiz ptr, _
                      byval ncmdshow      as long) export as long
    
       dim thisfile as asciiz * 128
       dim stat as long
       stat = getmodulefilename (hcurinstance, thisfile, sizeof(thisfile) )
       print "hello world from program " & thisfile
    
       stat = ddeclientcc
    
       print "any key to exit...."
       j$ = waitkey$
    
    end function
    
    function ddeclientcc () as long
        local i as long
        local lid as long
        local hddeconv as long
        local hddeservice as long
        local hddetopic as long
        local hddeitem as long
        local lresult as long
        local tddeconv as convcontext
    
        local  szserver as asciiz * 128           ' the executable name of the dde server application
        local  szxls    as asciiz * %max_path     ' the full path of the spreadsheet file
        local  sztopic as asciiz * 128            ' the (string) topic name as expected by the server
        local  szitem  as asciiz * 128            ' the (string) item name for the dde data request
        local  szresponse as asciiz * 4096
        local  ddelasterror as long
        local  hddeinit as long
        local  hinitcode as long
        local  execute_timeout as long
               execute_timeout = 3000&            ' three seconds allowed for a response
               
        dim j as string
        let szserver = "excel"                                                    ' the excel dde server name
        let szxls = "c:\software_development\testdata\excel xls\name_dob.xls"     ' spreadsheet file name
        let sztopic = "[name_dob.xls]sheet1"   ' workbook /sheet . excel does not work with paths in there!
    
        'since we are client only we decline to receive callbacks
        ' i do not understand this, but mr heyworth included it.
        hinitcode = ddeinitialize  (lid, codeptr(dde_callbackfunc), %appcmd_clientonly, 0 )
        if hinitcode <> %dmlerr_no_error then
            print "failed to initialize dde & ddeerrortext (hinitcode)
            exit function
        end if
        
        '======================================================================
        ' as coded, the server and topic must both be defined to connect
        '======================================================================
       
        'create a dde string handle for the service
        hddeservice = ddecreatestringhandle( lid, szserver, %cp_winansi )
        if hddeservice = 0 then
            ddelasterror = ddegetlasterror (lid)
            print "cannot create string handle for service "  & szserver & ". " & ddeerrortext (ddelasterror)
            goto clean_up
        end if
        'create string handle for the topic
        hddetopic = ddecreatestringhandle( lid, sztopic, %cp_winansi )
        if hddetopic = 0 then
            ddelasterror = ddegetlasterror (lid)
            print "cannot create string handle for topic "  & sztopic & ". " & ddeerrortext (ddelasterror)
            goto clean_up
        end if
    
        'connect (start conversation)
        tddeconv.cb = sizeof(tddeconv)
        tddeconv.icodepage = %cp_winansi
        hddeconv = ddeconnect( lid, hddeservice, hddetopic, tddeconv )
       ' will not connect if server is not running. if excel, does not automatically load the correct
       ' speadsheet (connection fails); returns %dmlerr_no_conv_established (&h400a) under these conditions.
       
       ' =========================================================================
       ' if connection failed, start the server ourself and try again
       ' =========================================================================
       
        if hddeconv = 0 then
            ddelasterror = ddegetlasterror (lid)
            if ddelasterror= %dmlerr_no_conv_established  then
               ' start it ourself with the shellexecute open
                 print "server '" & szserver & "' not found. will attempt to start it by association"
                 if isfalse (startserver (szxls)) then  ' the server has been started and
                     ' awaits our next command, so try again..
                      print "server started, attempting dde connection"
                      hddeconv = ddeconnect( lid, hddeservice, hddetopic, tddeconv )
                      if hddeconv = 0 then
                           ddelasterror = ddegetlasterror (lid)
                           print "cannot ddeconnect after starting server. " & ddeerrortext (ddelasterror)
                      end if
                 else
                     print "cound not get server running"
                 end if
           end if
        end if
        ' if hddeconv is still zero, we were unable to find the server.
        if hddeconv = 0 then
            ddelasterror = ddegetlasterror (lid)
            print "cannot ddeconnect. " & ddeerrortext (ddelasterror)
            goto clean_up
        else
            print "established a connection to server " & szserver & " for topic " & sztopic
        end if
        
        ' =====================================================================
        '  enter a prompt/accept loop to test data retrieval
        ' =====================================================================
    
        local hresult as long, getdataresult  as long
    
        do
             szresponse = "
             print "server:" & szserver & "   topic:" & sztopic
             line input "enter the item to retrieve: (cr=quit) ", szitem
             ' see above: for excel, "rncn" retrieves single cell, "rncn:rmcm" retrieves a range of cells
             
             if szitem = " then      ' cannot create a dde string handle for null string
                exit do
             end if
             ' create the dde string handle for the item
             hddeitem = ddecreatestringhandle( lid, szitem, %cp_winansi )
             if hddeitem = 0 then
                ddelasterror = ddegetlasterror (lid)
                print "cannot create string handle for item ==>" & szitem & ". " & ddeerrortext (ddelasterror)
                goto clean_up
             end if
             ' do the dde transaction
             lresult = ddeclienttransaction (0&, 0&,hddeconv,hddeitem,%cf_text, %xtyp_request, execute_timeout, hresult)
             if istrue (lresult) then                        ' the return value is the handle of the return value
                getdataresult = ddegetdata (lresult, byval varptr(szresponse), sizeof(szresponse)-1, 0)
                print "success. data returned===>" & szresponse  & "<=="
             else
                ddelasterror =ddegetlasterror(lid)
                print "ddeclienttransaction failed. " & ddeerrortext(ddelasterror)
             end if
             ' free the string handle (created anew for each request)
             if hddeitem then
                call ddefreestringhandle( lid, hddeitem )
                hddeitem = 0
             end if
        loop
    
    clean_up:
        if hddeconv then
            call ddedisconnect( hddeconv )
        end if
    
        if hddeitem then
            call ddefreestringhandle( lid, hddeitem )
        end if
    
        if hddetopic then
            call ddefreestringhandle( lid, hddetopic )
        end if
    
        if hddeservice then
            call ddefreestringhandle( lid, hddeservice )
        end if
    
        call ddeuninitialize( lid )
    
        print "finished with dde client"
    
    end function
    
    function ddeerrortext (byval dmlerr as long) as string
    
       local w as string
       select case dmlerr
    
          case %dmlerr_advacktimeout
               w = "adv_ack_timeout"
          case  %dmlerr_busy
               w = "busy"
          case %dmlerr_dataacktimeout
               w = "data_ack_timeout"
          case %dmlerr_dll_not_initialized
               w = "dll_not_intialized"
          case %dmlerr_dll_usage
               w = "dll_usage"
          case %dmlerr_execacktimeout
               w = "exec_ack_timeout"
          case  %dmlerr_invalidparameter
               w= "invalid_parameter"
          case  %dmlerr_low_memory
               w = "low_memory"
          case %dmlerr_memory_error
               w = "memory_error"
          case %dmlerr_notprocessed
               w = "not_processed (not found)"
          case %dmlerr_no_conv_established
               w = "no_conv_established"
          case %dmlerr_pokeacktimeout
               w = "poke_ack_timeout"
          case  %dmlerr_postmsg_failed
               w= "postmsg_failed"
          case %dmlerr_reentrancy
               w = "reentrancy error"
          case %dmlerr_server_died
               w = "server_died"
          case %dmlerr_sys_error
               w = "sys_error"
          case %dmlerr_unadvacktimeout
               w = "unadv_ack_timeout"
          case %dmlerr_unfound_queue_id
               w ="unfound_queue_id"
          case else
               w = "no description avaialable"
       end select
    
       function = "(x'" & hex$(dmlerr, 4) & "') " & w
    end function
    
    '===================================================================
    '   start the dde server and await its readiness to accept commands
    '   use shellexecuteex to "open" a file and use the association defined
    '   on the system
    '===================================================================
    
    function startserver (szfile as asciiz * %max_path) as long
       ' returns: 0 = good, server ready; else error...
       ' assumes szfile has an extension with an association; e.g., *.xls ==> excel
    
       local sei as shellexecuteinfo, stat as long, e as long
       local hwnd as long       ' not used in this app, but required
       local waitresult as long
       local lpverb as asciiz * 20, lpparameters as asciiz * 20, lpdirectory as asciiz * 20, lpfile as asciiz * %max_path
       local timeout2 as long   ' "timeout" is another pb un-hilited "reserved" word which is truly only reserved
                                '  in the context of a tcp or udp verb and can only be found with "search."
                                '  the error message if you use 'timeout' as a variable name is
                                '  "statement expected," which is a useless error message.
       hwnd = 0
       lpverb = "open"
       lpparameters   = "
       lpfile = szfile
       timeout2 = 7000          ' how long to wait for the server to complete its initialization (milliseconds).
       sei.cbsize       = sizeof(sei)
       sei.fmask        = %see_mask_nocloseprocess    ' we want a process handle to work with
                                                      ' and will be responsible for closing it ourself.
       sei.hwnd         = hwnd
       sei.lpverb       = varptr(lpverb)
       sei.lpfile       = varptr(lpfile)
       sei.lpparameters = varptr (lpparameters)
       sei.lpdirectory  = %null
       sei.nshow        = %sw_showminimized      ' ms-excel does not seem to care what you put here
                                                   ' sw_hide,sw_show all result in excel as active window.
                                                   '%sw_showminnoactive
       sei.hinstapp     = 0             ' updated by function
       sei.lpidlist     = %null         ' here down to hprocess ignored unless appropriate mask included in fmask
       sei.lpclass      = %null
       sei.hkeyclass    = %null
       sei.dwhotkey     = %null
       sei.hicon        = %null         ' hicon appears here in one version of win32api.inc
    '    sei.item         = %null       ' item appears in another version of win32api.inc
       sei.hprocess     = 0             ' will be updated by shellexecuteex
    
       stat = -1                        ' default = failure  (boy, am i a pessimist or what?)
    
       if istrue shellexecuteex(sei) then       ' function succeeded and returned
           print "shell executeex succeeded, will now wait for server to complete its initialization..."
          ' wait for the server to be ready to accept input
           waitresult = waitforinputidle(sei.hprocess, timeout2)
           select case waitresult
                 case 0&            ' wait was satisfied normally; that is, server is now ready
                      stat = 0      ' so our function succeeds
                 case %wait_timeout
                      print "server timeout"
                 case else            ' -1 means error
                      e = getlasterror
                      print "waitforinputidle error:" & systemerrormessagetext(e)
           end select
          '==================================================================================================
          ' cannot use waitforinput idle with console apps; does that mean the parent or the launched process?
          ' must mean the server applications, because it works from a pb/cc client the server being excel,
          ' which is a gui application.
          ' if the server is a console application you can try this:
          '      sleep timeout2
          '      stat = 0   '     this is optimistic; have not figured out a way to determine if a launched
          '                       'console' application server is, in fact, "ready" to accept dde requests
          '==================================================================================================
          ' regardless, we are done with the launched process's handle, so we should close it...
          ' note that we do not need to have this handle open (see sei.fmask), but the process handle
          ' can be used with other synchronization processes if necessary
            closehandle sei.hprocess
      else                                 ' shell executeex failed
          e = getlasterror
          print "shellexecuteex failed:" & systemerrormessagetext(e)
      end if
      function = stat
    end function
    
    #if 0
    '  7/6/01 addition: update an excel spreadsheet using dde interface
    ' tested and works:
    ' replace single cell contents with text data
    ' replace single cell with a formula (szpokedata= "=sum(d2 [img]http://www.powerbasic.com/support/forums/biggrin.gif[/img]7)" or szpokedata="(d3*d4)"
    ' cells part of a formula are immediately updated in excel.
    ' replace range of cells with new text
    ' if the new data item is a formula, a retrieve of the cell returns the current result
    ' of the calculation, not the formula itself.
    
    ' code changes to make the update:
    
    '  add this line in the appropriate place..
              local  szpokedata as asciiz * 4096
              
    '  replace the do ..loop above with this to the update
      do
             szresponse = "
             print "server:" & szserver & "   topic:" & sztopic
             line input "enter the row:column to update: (cr=quit) ", szitem
             ' format is   "rncm[:rocp]"
    
             if szitem = " then      ' cannot create a dde string handle for null string
                exit do
             else
                 line input "enter the new data string", szpokedata
                ' row data should be tab-delimited, $cr terminated (not $crlf)
                 
                 if szpokedata = " then     '
         ' for testing, since you can't key in tab or cr
         '            szpokedata = "c1" & $tab & "c2" & $tab & "c3" & $tab & $cr  ' <<< works for one row real good
                     szpokedata = "r1c1" & $tab & "r1c2" & $tab & "r1c3" & $cr _
                      & "r2c1" & $tab & "r2c2" & $tab & "r2c3" & $cr             ' <<< works for 2 row x 3 col range real good
                 else
                    szpokedata = szpokedata & $cr
                 end if
                 print "pokedata is==>";szpokedata;"<=="
             end if
    
             ' create the dde string handle for the item
             hddeitem = ddecreatestringhandle( lid, szitem, %cp_winansi )
             if hddeitem = 0 then
                ddelasterror = ddegetlasterror (lid)
                print "cannot create string handle for item ==>" & szitem & ". " & ddeerrortext (ddelasterror)
                goto clean_up
             end if
    
             ' do the dde transaction
             ' xtyp_poke:return value is nonzero for successful transactions in which client does not expect data
             lresult = ddeclienttransaction (byval varptr(szpokedata),len(szpokedata),hddeconv,hddeitem,%cf_text, %xtyp_poke, execute_timeout, hresult)
             print "lresult result code = " & str$(lresult)
            ' success is defined as nonzero for transactions not expecting return data
             if istrue (lresult) then
                print "success. check the spreadsheet to see the change."
             else
                ddelasterror =ddegetlasterror(lid)
                print "ddeclienttransaction failed. " & ddeerrortext(ddelasterror)
             end if
             ' free the string handle (created anew for each request)
             if hddeitem then
                call ddefreestringhandle( lid, hddeitem )
                hddeitem = 0
             end if
        loop
      
    #endif
      ' end of block to use when doing an update of a spreadsheet.
    ' *** end of file ***'

    ------------------
    michael mattias
    racine wi usa
    [email protected]



    [this message has been edited by michael mattias (edited july 06, 2001).]
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


      #3
      DDE client example in PBCC6

      While this code was bona fide some 10 years ago, in PBCC6 it fails during compilation:

      Error 460 in C:\PBCC60\TestCC\DDETest.bas(92:065): Undefined equate
      Line 92: hInitCode = DdeInitialize (lId, CODEPTR(Dde_CallbackFunc), %APPCMD_CLIENTONLY, 0 )


      I suspect it's the %APPCMD_CLIENTONLY equate which is the trouble. Any suggestions as to how we can successfully compile this example in PBCC6?

      (Yes, it's DDE ... but in this case, I simply have no other options).

      Thanks,
      Torkel M. Jodalen, tel. (+47) 69252033 / 92422020
      ++

      Comment


        #4
        Code:
        Error 460 in C:\PBCC60\TestCC\DDETest.bas(92:065): Undefined equate
        >Any suggestions as to how we can successfully compile this example in PBCC6?

        Define the equate?
        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]
        http://www.talsystems.com

        Comment


          #5
          Originally posted by Michael Mattias View Post
          Code:
          Error 460 in C:\PBCC60\TestCC\DDETest.bas(92:065): Undefined equate
          >Any suggestions as to how we can successfully compile this example in PBCC6?

          Define the equate?
          Well, just defining it to anything syntactically acceptable... is that likely to do the trick?


          Regards,
          Torkel M. Jodalen, tel. (+47) 69252033 / 92422020
          ++

          Comment


            #6
            Well, just defining it to anything syntactically acceptable... is that likely to do the trick
            No.

            Frankly, if you asked that question you should not be cutting and pasting and porting anything. You need to crawl before you walk.
            Michael Mattias
            Tal Systems (retired)
            Port Washington WI USA
            [email protected]
            http://www.talsystems.com

            Comment


              #7
              As in "copy the equates from the above Pegasus mail example"?
              Worked like a charm.
              Torkel M. Jodalen, tel. (+47) 69252033 / 92422020
              ++

              Comment


                #8
                Well, in case someone else should stumble upon this code example for a simple DDE client, keep in mind that the ALIASes from the otherwise excellent examples above need proper capitalization in order to work properly.

                Code:
                DECLARE FUNCTION ddeabandontransaction LIB "user32.dll" [B]ALIAS "DdeAbandonTransaction"[/B] (BYVAL idinst AS LONG, BYVAL hconv AS LONG, BYVAL idtransaction AS LONG) AS LONG
                (...)
                Torkel M. Jodalen, tel. (+47) 69252033 / 92422020
                ++

                Comment


                  #9
                  The capitalization was lost when the BBS software changed a couple of years ago. This happened to a couple of my other demos.

                  I can repost it if I can find it...OR SOMEONE ELSE CAN DO IT JUST POST IT AS A 'REPLY' and everyone will be happy.
                  Michael Mattias
                  Tal Systems (retired)
                  Port Washington WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment


                    #10
                    MSQuery and DDE

                    MSQuery is fantastic at helping to write SQL queries. I struggle with DDE and MSQuery.

                    Is there anyone who has written DDE call for MSQuery? It seems to be pretty smart.

                    I try to use MSQuery for creating SQL queries, to control this I use DDE. I can make it listen, but no real control, it makes little as it wants.


                    Know that it is an old technology with DDE, but have not found any other technology to control the MSQuery (MSQry32.EXE).


                    Have been looking in the forum and searched online but nothing has helped me so far.

                    Any guidance


                    Code:
                    #compile exe
                    #INCLUDE "win32api.inc"     
                    
                    Declare Function zTrace Lib "zTrace.DLL" Alias "zTrace" (zMessage As AsciiZ) As Long
                    Declare Function zDebug Lib "zTrace.DLL" Alias "zDebug" (zMessage As AsciiZ) As Long
                    '--------------------------------------------------------------------------------------------------------
                    FUNCTION WINMAIN (BYVAL hCurInstance  AS LONG, _
                                      BYVAL hPrevInstance AS LONG, _
                                      BYVAL lpszCmdLine         AS ASCIIZ PTR, _
                                      BYVAL nCmdShow      AS LONG) EXPORT AS LONG
                    
                        LOCAL i AS LONG
                        LOCAL lId AS LONG
                        LOCAL hDDEConv AS LONG
                        LOCAL hDDEService AS LONG
                        LOCAL hDDETopic AS LONG
                        LOCAL hDDEItem AS LONG
                        LOCAL lResult AS LONG
                        LOCAL tDdeConv AS CONVCONTEXT
                        local Temp as string
                        LOCAL  szServer AS ASCIIZ * %MAX_PATH     ' The executable name of the DDE server application
                        LOCAL  szXls    AS ASCIIZ * %MAX_PATH     ' the full path of the spreadsheet file
                        LOCAL  szTopic AS ASCIIZ * %MAX_PATH      ' the (string) topic name as expected by the server
                        LOCAL  szItem  AS ASCIIZ * %MAX_PATH      ' the (string) item name for the DDE data request
                        LOCAL  szResponse AS ASCIIZ * 4096
                        LOCAL  sResponse AS string 'ASCIIZ * 4096
                        LOCAL  DDELastError AS LONG
                        LOCAL  hDDEInit AS LONG
                        LOCAL  hInitCode AS LONG
                        LOCAL  Execute_Timeout AS LONG
                               Execute_TimeOut = 3000&            ' three seconds allowed for a response
                        local J AS STRING
                        LOCAL hResult AS LONG, GetDataResult  AS LONG
                        LOCAL sYN AS STRING
                            LOCAL lngDataType AS LONG
                          LOCAL strReturn AS STRING
                          LOCAL pdwdValue AS DWORD PTR
                          LOCAL lngReturn AS LONG
                          LOCAL strSection AS STRING
                    
                            'LSET szXLS = "C:\Program Files (x86)\Microsoft Office\Office14\MSQRY32.EXE"
                            '----------------------------Init---------------------------------------------------------
                        hInitCode = DdeInitialize  (lId, CODEPTR(Dde_CallbackFunc), %APPCMD_CLIENTONLY , 0 )     
                                                    IF hInitCode <> %DMLERR_NO_ERROR THEN
                                                            ztrace "Failed to initialize DDE & DDEErrorText (hInitCode)
                                                            EXIT FUNCTION
                                                    END IF
                        '----------------------------create string handle for the server---------------------------
                            hDDEService = DdeCreateStringHandle( lId, "MSQuery", %CP_WINANSI )
                                                        IF hDDEService = 0 THEN
                                                                DDELastError = DDEGetLastError (lID)
                                                                ztrace "Cannot create String Handle for service "  & szServer & ". " & DDEErrorText (DDELastError)
                                                                GOTO Clean_Up
                                                        END IF
                            '----------------------------create string handle for the topic---------------------------
                            hDDETopic = DdeCreateStringHandle( lId, "System", %CP_WINANSI )
                                                    ztrace "Topic " & str$( hDDETopic )
                                                    IF hDDETopic = 0 THEN
                                                            DDELastError = DDEGetLastError (lID)
                                                            ztrace "Cannot create String Handle for topic "  & "System" & ". " & DDEErrorText (DDELastError)
                                                            GOTO Clean_Up
                                                    END IF
                        '---------------------------- Connect to MSQRY32 ---------------------------
                            hDDEConv = DdeConnect( lId, hDDEService, hDDETopic, "" )
                                            ztrace "retur hDDEconv " & str$(hDDEConv)
                                            IF hDDEConv = 0 THEN
                                                    DDELastError = DDEGetLastError (lID)
                                                    ztrace "----Cannot create String Handle for connect "  & "run" & ". " & DDEErrorText (DDELastError)
                                                    ' Problem not started?
                                                    lngReturn = RegRead( "HKLM\SOFTWARE\WOW6432Node\Microsoft\Shared Tools\MSQuery\path", strReturn, lngDataType, strSection )
                                                    IF lngReturn = %ERROR_SUCCESS AND lngDataType = %REG_SZ THEN 
                                                        SHELL("rundll32.exe url.dll,FileProtocolHandler " & (strReturn & "\MSQRY32.EXE"))
                                                    end if 
                                                    GOTO Clean_Up
                                            END IF
                        '------------------------------ RUN ----------------------------------------
                            'LET szTopic = "[UserControl('&Exit Command',3,True)]"
                            ' LET szTopic = "[Open(\""Nr1"")]"
                                     LET szTopic = "[UserControl('',1,True)]"
                                    ' LET szTopic = "[BuildODBC(\""nr1""\)]"
                                    'LET szTopic = "[ViewPane(3)]"
                                    hDDEItem = DdeCreateStringHandle( lId, szTopic, %CP_WINANSI )
                            ztrace "item " & str$( hDDEItem )
                                    IF hDDEItem = 0 THEN
                                            DDELastError = DDEGetLastError (lID)
                                            ztrace "++++Cannot create String Handle for topic "  & szTopic & ". " & DDEErrorText (DDELastError)
                                            GOTO Clean_Up
                                    END IF
                                  sResponse =  STRING$(4096,$SPC)
                                    lresult = DDeClientTransaction ( byref szTopic, len(szTopic),hDDEConv,0&,0&, %XTYP_EXECUTE, Execute_timeout, hResult)
                                    'lresult = DDeClientTransaction (BYVAL 0&, 0&,hDDEConv,hDDEItem,%CF_TEXT, %XTYP_REQUEST, Execute_timeout, hResult)
                                    ztrace "result " & str$( lresult)
                                    IF ISTRUE (lresult) THEN                        ' the return value is the handle of the return value
                                         GetDataResult = DDEGetData (lResult, BYVAL STRPTR(sResponse), LEN(sResponse)-1, 0)
                                         REPLACE $NUL WITH $SPC IN sResponse
                                         sResponse      = RTRIM$(sResponse)
                                         ztrace USING$ ("Success. Returned # bytes value '&'", LEN(sResponse), sResponse)
                              ELSE
                                         DDELastError =DDEGetLastError(lID)
                                         ztrace "DDEClientTransaction Failed. " & DDEErrorText(DDELastError)
                                    END IF
                        '   ' free the string handle (created anew for each request)
                                    IF hDDEItem THEN
                                         CALL DdeFreeStringHandle( lId, hDDEItem )
                                         hDDEItem = 0
                                    END IF
                    
                                    ' create the DDE string handle for the item
                            LET szItem = "[ViewPane(3)]"
                            hDDEItem = DdeCreateStringHandle( lId, szItem, %CP_WINANSI )
                                    IF hDDEItem = 0 THEN
                                         DDELastError = DDEGetLastError (lID)
                                ztrace "Cannot Create String Handle for Item ==>" & szItem & ". " & DDEErrorText (DDELastError)
                                         GOTO Clean_Up
                                    END IF
                    
                                    sResponse =  STRING$(4096,$SPC)
                                    lresult = DDeClientTransaction (BYVAL 0&, 0&,hDDEConv,hDDEItem,%CF_TEXT, %XTYP_REQUEST, Execute_timeout, hResult)
                                    IF ISTRUE (lresult) THEN                        ' the return value is the handle of the return value
                                         GetDataResult = DDEGetData (lResult, BYVAL STRPTR(sResponse), LEN(sResponse)-1, 0)
                                         REPLACE $NUL WITH $SPC IN sResponse
                                         sResponse      = RTRIM$(sResponse)
                                         ztrace USING$ ("Success. Returned # bytes value '&'", LEN(sResponse), sResponse)
                    '                              ELSE
                                         DDELastError =DDEGetLastError(lID)
                                         ztrace "DDEClientTransaction Failed. " & DDEErrorText(DDELastError)
                                    END IF
                    '                              ' free the string handle (created anew for each request)
                                    IF hDDEItem THEN
                                         CALL DdeFreeStringHandle( lId, hDDEItem )
                                         hDDEItem = 0
                                    END IF
                    
                    Clean_Up:
                        IF hDDEConv THEN
                            CALL DdeDisconnect( hDDEConv )
                        END IF
                    
                        IF hDDEItem THEN
                            CALL DdeFreeStringHandle( lId, hDDEItem )
                        END IF
                    
                        IF hDDETopic THEN
                            CALL DdeFreeStringHandle( lId, hDDETopic )
                        END IF
                    
                        IF hDDEService THEN
                            CALL DdeFreeStringHandle( lId, hDDEService )
                        END IF
                    
                        CALL DdeUninitialize( lId )
                    
                        ? "Finished with DDE Client"
                    
                    END FUNCTION
                    '--------------------------------------------------------------------------------------------------------
                    FUNCTION SystemErrorMessageText (BYVAL ECode AS LONG) AS STRING
                      LOCAL Buffer AS ASCIIZ * 255
                      FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL %NULL, ECode, %NULL, buffer, SIZEOF(buffer), BYVAL %NULL
                      FUNCTION = FORMAT$(ECode, "(#####) ") & Buffer
                    END FUNCTION
                    '--------------------------------------------------------------------------------------------------------
                    FUNCTION Dde_CallbackFunc(BYVAL uType AS DWORD, BYVAL uFmt AS LONG, BYVAL hConv AS LONG, _
                                                                      BYVAL hszTopic AS LONG, BYVAL hszItem AS LONG, BYVAL hData AS LONG, _
                                                                      BYVAL dwData1 AS DWORD, BYVAL dwData2 AS DWORD) AS LONG
                    
                         ztrace str$(uType)
                            'for monitoring and server apps
                        ' is the transaction complete
                            select case uType 
                                case %XTYPF_ACKREQ
                    
                                case %XTYP_ADVDATA
                    
                                case %XTYP_XACT_COMPLETE   
                    
                    
                        end select
                    
                    END FUNCTION
                    '--------------------------------------------------------------------------------------------------------
                    FUNCTION DDEErrorText (BYVAL DMLERR AS LONG) AS STRING
                    
                       LOCAL W AS STRING
                       SELECT CASE DMLERR
                    
                          CASE %DMLERR_ADVACKTIMEOUT
                               W = "ADV_ACK_TIMEOUT"
                          CASE  %DMLERR_BUSY
                               W = "BUSY"
                          CASE %DMLERR_DATAACKTIMEOUT
                               W = "DATA_ACK_TIMEOUT"
                          CASE %DMLERR_DLL_NOT_INITIALIZED
                               W = "DLL_NOT_INTIALIZED"
                          CASE %DMLERR_DLL_USAGE
                               W = "DLL_USAGE"
                          CASE %DMLERR_EXECACKTIMEOUT
                               W = "EXEC_ACK_TIMEOUT"
                          CASE  %DMLERR_INVALIDPARAMETER
                               W= "INVALID_PARAMETER"
                          CASE  %DMLERR_LOW_MEMORY
                               W = "LOW_MEMORY"
                          CASE %DMLERR_MEMORY_ERROR
                               W = "MEMORY_ERROR"
                          CASE %DMLERR_NOTPROCESSED
                               W = "NOT_PROCESSED (not found)"
                          CASE %DMLERR_NO_CONV_ESTABLISHED
                               W = "NO_CONV_ESTABLISHED"
                          CASE %DMLERR_POKEACKTIMEOUT
                               W = "POKE_ACK_TIMEOUT"
                          CASE  %DMLERR_POSTMSG_FAILED
                               W= "POSTMSG_FAILED"
                          CASE %DMLERR_REENTRANCY
                               W = "REENTRANCY ERROR"
                          CASE %DMLERR_SERVER_DIED
                               W = "SERVER_DIED"
                          CASE %DMLERR_SYS_ERROR
                               W = "SYS_ERROR"
                          CASE %DMLERR_UNADVACKTIMEOUT
                               W = "UNADV_ACK_TIMEOUT"
                          CASE %DMLERR_UNFOUND_QUEUE_ID
                               W ="UNFOUND_QUEUE_ID"
                          CASE ELSE
                               W = "NO DESCRIPTION AVAIALABLE"
                       END SELECT
                    
                       FUNCTION = "(x'" & HEX$(DMLERR, 4) & "') " & W
                    END FUNCTION
                    '--------------------------------------------------------------------------------------------------------
                    FUNCTION RegRead( BYVAL strSource AS STRING, strRegistryBuffer AS STRING, lngType AS LONG, OPT strSection AS STRING ) EXPORT AS LONG
                     '=======================================================================================================|
                     '                                                                                                       |
                     ' RegRead.inc - Generic registry read function.                                                         |
                     ' Allows you to read any registry data type from a local (or remote) machine in a single function       |
                     '                                                                                                       |
                     ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
                     '                                                                                                       |
                     ' George W. Bleck                                                                                       |
                     ' 2010-01-26 v1 (Original version)                                                                      |
                     '                                                                                                       |
                     ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
                     '                                                                                                       |
                     ' INPUT:                                                                                                |
                     '   [Required] strSource = {\\ComputerName\}Hive\SubKey\{ValueName}                                     |
                     '                                                                                                       |
                     '   ComputerName is optional but if supplied you must include the prefacing "\\"                        |
                     '   Hive (required) can be the short "HKLM" or long "HKEY_LOCAL_MACHINE" version                        |
                     '   SubKey is required, if you want the SubKey default value end with a "\" and leave off the ValueName |
                     '                                                                                                       |
                     '   Remote connection ex.: "\\PCNAME\HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"        |
                     '   Local connection ex.:  "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"   |
                     '                                                                                                       |
                     ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
                     '                                                                                                       |
                     ' OUTPUT:                                                                                               |
                     '   [Required] strRegistryBuffer = returns a buffer which contains the data                             |
                     '   [Required] lngType = returns the data type contained in the buffer                                  |
                     '   [OPTIONAL] strSection = Returns the section of code or registry call related to the function return |
                     '                                                                                                       |
                     '   FUNCTION RETURN = ERROR_SUCCESS or an Windows Error code (use FORMATMESSAGE, see also strSection)   |
                     '                                                                                                       |
                     '=======================================================================================================|
                     LOCAL dwdHive AS DWORD
                     LOCAL hRegistryKey AS DWORD
                     LOCAL hRegistryRoot AS DWORD
                     LOCAL lngBufferLen AS LONG
                     LOCAL lngIndex AS LONG
                     LOCAL lngResult AS LONG
                     LOCAL strComputerName AS STRING
                     LOCAL strHiveAndSubKey AS STRING
                     LOCAL strSubKey AS STRING
                     LOCAL strValueName AS STRING
                     LOCAL lngOptionalPresent AS LONG
                     IF ISMISSING( strSection ) THEN lngOptionalPresent = %FALSE ELSE lngOptionalPresent = %TRUE
                     ' GETCOMPUTERNAME: If a ComputerName is specified break it apart from HiveAndSubKey
                     IF LEFT$( strSource, 2 ) = "\\" THEN
                      lngIndex = INSTR( 3, strSource, "\" )
                      IF lngIndex = 3 OR lngIndex = LEN( strSource ) THEN
                       IF lngOptionalPresent THEN strSection = "GETCOMPUTERNAME"
                       FUNCTION = %ERROR_BADKEY
                       EXIT FUNCTION
                      END IF
                      strComputerName = LEFT$( strSource, lngIndex - 1 )
                      strHiveAndSubKey = MID$( strSource, lngIndex + 1 )
                     ELSE
                      strHiveAndSubKey = strSource
                     END IF
                     ' DETERMINEHIVE: Break apart the Hive and SubKey
                     lngIndex = INSTR( strHiveAndSubKey, "\" )
                     IF ( lngIndex < 2 ) OR ( lngIndex = LEN( strHiveAndSubKey )) THEN
                      FUNCTION = %ERROR_BADKEY
                      EXIT FUNCTION
                     ELSE
                      SELECT CASE UCASE$( LEFT$( strHiveAndSubKey, lngIndex - 1 ))
                       CASE "HKLM", "HKEY_LOCAL_MACHINE"
                        dwdHive = %HKLM
                       CASE "HKCU", "HKEY_CURRENT_USER"
                        dwdHive = %HKCU
                       CASE "HKU", "HKEY_USERS"
                        dwdHive = %HKU
                       CASE "HKCR", "HKEY_CLASSES_ROOT"
                        dwdHive = %HKCR
                       CASE "HKPD", "HKEY_PERFORMANCE_DATA"
                        dwdHive = %HKPD
                       CASE "HKCC", "HKEY_CURRENT_CONFIG"
                        dwdHive = %HKCC
                       CASE "HKDD", "HKEY_DYN_DATA"
                        dwdHive = %HKDD
                       CASE ELSE
                        IF lngOptionalPresent THEN strSection = "DETERMINEHIVE"
                        FUNCTION = %ERROR_BADKEY
                        EXIT FUNCTION
                      END SELECT
                     END IF
                     ' CHECKVALIDREMOTEHIVE: If this is a remote connection check to see if the hive specified is valid
                     IF ( strComputerName <> "" ) AND ( dwdHive <> %HKLM OR dwdHive <> %HKU ) THEN
                      IF lngOptionalPresent THEN strSection = "CHECKVALIDREMOTEHIVE"
                      FUNCTION = %ERROR_BADKEY
                      EXIT FUNCTION
                     END IF
                     ' GETVALUENAME: Break out the value name, also allow for the {Default} entry
                     strSubKey = MID$( strHiveAndSubKey, lngIndex + 1 )
                     lngIndex = INSTR( - 1, strSubKey, "\" )
                     SELECT CASE AS LONG lngIndex
                      CASE < 2
                       ' No subkey was specified
                       IF lngOptionalPresent THEN strSection = "GETVALUENAME"
                       FUNCTION = %ERROR_BADKEY
                       EXIT FUNCTION
                      CASE LEN( strSubKey )
                       ' No Value was specied, must want the Default Entry
                       strValueName = ""
                      CASE ELSE
                       ' We have a value name
                       strValueName = MID$( strSubKey, lngIndex + 1 )
                       strSubKey = LEFT$( strSubKey, lngIndex - 1 )
                     END SELECT
                     ' REGONNECTREGISTRY: If a computer name was specific try to open a connection
                     IF strComputerName = "" THEN
                      hRegistryRoot = dwdHive
                     ELSE
                      lngResult = REGCONNECTREGISTRY( BYVAL STRPTR( strComputerName ), dwdHive, hRegistryRoot )
                      IF lngResult <> %ERROR_SUCCESS THEN
                       IF lngOptionalPresent THEN strSection = "REGCONNECTREGISTRY"
                       FUNCTION = lngResult
                       EXIT FUNCTION
                      END IF
                     END IF
                     ' REGOPENKEYEX: Open the SubKey
                     lngResult = REGOPENKEYEX( hRegistryRoot, BYVAL STRPTR( strSubKey ), BYVAL &0, %KEY_READ, hRegistryKey )
                     IF lngResult <> %ERROR_SUCCESS THEN
                      IF lngOptionalPresent THEN strSection = "REGOPENKEYEX"
                      FUNCTION = lngResult
                     ELSE
                      ' REGQUERYVALUEEX: Get a specific value
                      lngResult = REGQUERYVALUEEX( hRegistryKey, BYVAL STRPTR( strValueName ), BYVAL &0, lngType, BYVAL &0, lngBufferLen )
                      IF lngResult = %ERROR_SUCCESS THEN
                       strRegistryBuffer = SPACE$( lngBufferLen )
                       FUNCTION = REGQUERYVALUEEX( hRegistryKey, BYVAL STRPTR( strValueName ), BYVAL &0, lngType, BYVAL STRPTR( strRegistryBuffer ), lngBufferLen )
                      ELSE
                       IF lngOptionalPresent THEN strSection = "REGQUERYVALUEEX"
                       FUNCTION = lngResult
                      END IF
                      REGCLOSEKEY hRegistryKey
                     END IF
                     REGCLOSEKEY hRegistryRoot
                    END FUNCTION

                    Comment


                      #11
                      I can't find where MSQuery provides a documented DDE interface. I found some references on some user-supported sites (Q&A places) but nothing from the publisher.

                      Undeterred, I tried to compile this. It would not compile with PB/Win 10x, so I tried 9x and it compiled first time (using Windows headers as provided by PB in both cases)

                      Then I had a runtime failure because I have no "ZTRaCE.DLL" so I substituted STDOUT.

                      Then I discovered nothing is going to work because I do not have MSQuery installed. MSQuery has to be running to succesfully execute the DDEConnect.

                      My STDOUT...

                      Code:
                      Open Console                         <<< MCM Line
                      DDEinitialize suceeded           <<<  MCM line
                      Topic  49153
                      retur hDDEconv  0
                      ----Cannot create String Handle for connect run. (x'400A') NO_CONV_ESTABLISHED
                      What are you trying to do? Best guess, you are trying to develop some kind of programmatic interface to MSQUERY from one of your programs so your users can use MSQuery to help them create SQL statements which your program can then use. Is that a good guess?

                      MSQUERY defined from Wikipedia:
                      Microsoft Query is a visual method of creating database queries using examples based on a text string, the name of a document or a list of documents. The QBE system converts the user input into a formal database query using Structured Query Language (SQL) on the backend, allowing the user to perform powerful searches without having to explicitly compose them in SQL, and without even needing to know SQL. It is derived from Moshé M. Zloof's original Query by Example (QBE) implemented in the mid-1970s at IBM's Research Centre in Yorktown, New York.[1]
                      I would think MSQuery, properly installed, could be started using START, as in...

                      Code:
                      scmd = "start  MSQUERY"
                      iPID =  SHELL (sCmd)
                      hProc = OpenProcess (iPID, options)
                      WaitForInputIdle  hProc , %INFINITE    ' wait for it to initialize
                      CloseHandle hProc  ' done with handle
                      ... instead of rummaging around in the registry.

                      My start of code.. (win/9)
                      Code:
                      #COMPILE EXE
                      #INCLUDE "win32api.inc"
                      
                      #INCLUDE "STDOUT_PBWIN.INC"  ' to replace ztrace
                      
                      'DECLARE FUNCTION zTrace LIB "zTrace.DLL" ALIAS "zTrace" (zMessage AS ASCIIZ) AS LONG
                      FUNCTION ZTRace (zMessage AS STRING) AS LONG
                           STDOUT zMessage
                      END FUNCTION
                      FUNCTION zDebug (zMessage AS STRING ) AS LONG
                          STDOUT zMessage
                      END FUNCTION
                      'DECLARE FUNCTION zDebug LIB "zTrace.DLL" ALIAS "zDebug" (zMessage AS ASCIIZ) AS LONG
                      ..
                      STDOUT_PBWIN.INC is available here ==> Simple STDOUT for PB/DLL and PB/Win 2-13-04

                      Sorry, can't go any further on this. Maybe someone with MSQuery installed and PB/Win 9x available to them can help

                      MCM
                      Michael Mattias
                      Tal Systems (retired)
                      Port Washington WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment


                        #12

                        Many thanks Michael, you are always so helpful. As I know, MSQuery always comes free with Office programs and widely used in conjunction with Excel. (If not, you can download for free, a great program). In MSQuery help -> they encourage you to use the DDE It also mentions that you should look in the registry where the program is. Guess that would be easy to do in VB there are lots of examples. An article I tried to assume and translate some code from: cant find any topics in the forum regarding MSQuery, may not be used so extensively?

                        Comment


                          #13
                          >cant find any topics in the forum regarding MSQuery, may not be used so extensively

                          I'm not surprised. DDE is not exactly a "hot topic" here and attempting a programmatic interface to MSQUERY by any means is, as far as I can recall, a virgin topic here.

                          That's a nice piece at the codeguru link; but I see it refers to reader to the MSQUERY help for information regarding how query information may be retrieved using DDE.

                          You never answered my question re what exactly you are trying to accomplish. Maybe there is "another way" although if I made a good guess that you want the SQL statements themselves in some environment where all users are guaranteed to have MSQUERY installed, I have to wonder why you'd need the SQL statements rather than the results of the query. Seems to me it makes no difference if the query is executed by MSQUERY or by your program, as long as the result set is available to your program.

                          It also mentions that you should look in the registry where the program is
                          I still don't believe that. Worst case I think I'd set up an Application Path (https://msdn.microsoft.com/en-us/lib...=vs.85%29.aspx) for the token "MSQUERY" and a corresponding shortcut using the START syntax.

                          MCM
                          Michael Mattias
                          Tal Systems (retired)
                          Port Washington WI USA
                          [email protected]
                          http://www.talsystems.com

                          Comment


                            #14
                            OK, seems like DDE is obsolete and death. Do try to find another method.

                            My colleagues can not write SQL queries, but by graphical "drag" from different tables it works just fine.
                            Often the connection strings or using the DSN that they do not have a clue, because I want to "embed" into everything and make it easy
                            Have you then done a good question shall be saved for later use. All create their own questions.
                            Access has a copy of the Msqery works in his wizard. Since Msquery is free and comes with the office Packets low, it is tempting to use this.

                            It is precisely the graphical select tables, relationships, and the choice I want. Is there any alternative?

                            Comment


                              #15
                              If a third party product will do., there's something called BI QUERY and another called Hummingbird which my clients use. And unless I'm mistaken, Microsoft Access allows you to create a visual representation of a DB and form and execute queries using drag and drop.

                              I suppose you could create the graphical representation of your DB yourself using catalog functions, except that assumes all the info you'd want/need is contained in the catalog. For example, you could only determine that the "part number" in the "sales order line" is in fact an index reference from the sales order line to the parts table if the part number column of the sales order line table specifies a constraint such as a foreign key. In my experience these kind of constraints are NOT in the catalog, they are just "assumed to be true" .. in this case you end up assuming that any part number in the sales order line table is in fact a valid part number in the parts table.

                              Note that products like BI QUERY and Hummingbird are ALSO ignorant of "database integrity rules which are not reflected in the catalog," too.

                              I'm actually the wrong guy to talk about forming DB queries using pictures. The times I've had to use MS-Access to do that, first thing I did was find the "SQL View" and just wrote my queries using SQL.

                              But in the PPPS, I created a "query the database" function, with all kinds of options. Let me see if I can get a picture of that screen... here it is, on the product web page.


                              The last picture toward the bottom of that page shows the options I gave the user. Hmm, that's an older picture... no it isn't, the date filter is on a different screen. But it would be easy to add a couple of date controls to allow the user to specify a range of dates.

                              When the user clicks execute, I read the screen, build and execute an SQL statement and display the results. Maybe you could do something like that in your application.

                              MCM
                              Michael Mattias
                              Tal Systems (retired)
                              Port Washington WI USA
                              [email protected]
                              http://www.talsystems.com

                              Comment


                                #16
                                Is still trying to get information through MSQRY32. I can read out information from the field to the SQL text.
                                Can I download during a dialogue with xx = Shell (prgm.exe) and get access to the program's PID and hWnd and then read the messages?
                                Or how do I know when someone closes the dialog or press the "OK" button, Can I achieve this via some type of subclass or some kind of hook?
                                Have tried some hook, it must be through the DLL or? Can I reach any message or all?

                                Grateful for clues

                                Code:
                                #COMPILE EXE
                                #DIM ALL
                                #INCLUDE "Win32Api.inc"
                                
                                GLOBAL glresult, ghwnd AS LONG
                                '=============================================================================================
                                 FUNCTION PBMAIN() AS LONG
                                      DIM hDlg AS DWORD, hCtl AS DWORD
                                      LOCAL Result AS LONG
                                      DIALOG NEW 0, "Control SQL",200,300,150,120, %WS_SYSMENU,0 TO hDlg
                                      CONTROL ADD BUTTON, hDlg, 1, "Start MSQRY and getPID", 25, 15, 90, 20
                                      CONTROL ADD BUTTON, hDlg, 2, "Put button on SQL dialog", 25, 35, 90, 20
                                      CONTROL ADD BUTTON, hDlg, 3, "Get SQL text fron dialog", 25, 55, 90, 20
                                      CONTROL ADD BUTTON, hDlg, 4, "Exit", 25, 75, 90, 20
                                      'aixa hdlg
                                      DIALOG SHOW MODAL hDlg CALL dDlgProc TO Result
                                   END FUNCTION
                                '=============================================================================================
                                CALLBACK FUNCTION dDlgProc() AS LONG
                                      IF CB.MSG = %WM_COMMAND AND CB.CTL = 1 AND  CB.CTLMSG = %BN_CLICKED THEN StartPID CBHNDL
                                      IF CB.MSG = %WM_COMMAND AND CB.CTL = 2 AND  CB.CTLMSG = %BN_CLICKED THEN SQLButton CBHNDL
                                      IF CB.MSG = %WM_COMMAND AND CB.CTL = 3 AND  CB.CTLMSG = %BN_CLICKED THEN GetSQLText CBHNDL
                                      IF CB.MSG = %WM_COMMAND AND CB.CTL = 4 AND  CB.CTLMSG = %BN_CLICKED THEN DIALOG END CBHNDL
                                END FUNCTION
                                
                                '=============================================================================================
                                FUNCTION SQLButton(hdlg AS DWORD) AS LONG
                                    LOCAL hWnd,hwndMain AS DWORD
                                
                                    hWnd = FindWindow("", "SQL")
                                    hWnd = CreateWindowEx(0,"button","GET SQL",%WS_CHILD OR %WS_VISIBLE,355,125,80,25,hWnd,100,hdlg,BYVAL 0)
                                END FUNCTION
                                '=============================================================================================
                                FUNCTION GetSQLText(hdlg AS DWORD) AS LONG
                                    LOCAL hWnd,hwndMain AS DWORD
                                    LOCAL nLen   AS LONG
                                    LOCAL wbuffer AS WSTRING
                                    'Find Edit class (only one) in SQL dialog
                                    hWnd =   FindWindow("", "SQL")
                                    hWnd =   FindWindowEx(hWnd, 0, "Edit", "")
                                    ' Show content of EDIT
                                    nLen = SendMessageW(HWnd, %WM_GETTEXTLENGTH, 0, 0)
                                    wbuffer = SPACE$(nLen + 1)
                                    nLen = SendMessageW(HWnd, %WM_GETTEXT, nLen + 1, BYVAL STRPTR(wbuffer))
                                   ?  LEFT$(wbuffer, nLen)
                                END FUNCTION
                                '=============================================================================================
                                FUNCTION StartPID (hdlg AS DWORD) AS LONG
                                    LOCAL pid, hprocess,glresult,gerror AS LONG
                                    LOCAL s, smsg AS STRING
                                    DIM geterrstring(gerror) AS STRING
                                
                                    ' START MSQUERY
                                    ' shell to application, get the pid
                                    pid = SHELL("C:\Program Files (x86)\Microsoft Office\Office14\MSQRY32.EXE")
                                    ' get the process handle
                                    hProcess = OpenProcess( %PROCESS_ALL_ACCESS, %FALSE, pid )
                                    IF hProcess = 0 THEN
                                        ?("OpenProcess failed")
                                        EXIT FUNCTION
                                    END IF
                                    ' wait for app to initialise
                                    glresult = WaitForInputIdle (hProcess, 1000)
                                
                                    closehandle hprocess
                                    ' use the pid to enumerate windows
                                    EnumWindows (CODEPTR(EnumCB), pid)
                                    ? STR$(ghwnd)
                                   ' Can I use pid and own it as childprocess
                                END FUNCTION
                                '=============================================================================================
                                FUNCTION enumcb( BYVAL hWnd AS DWORD, BYVAL lParam AS DWORD) AS LONG
                                    LOCAL ProcessId AS DWORD
                                
                                    GetWindowThreadProcessId (hWnd, ProcessId)
                                    IF ProcessId = lParam THEN
                                        ghwnd = hwnd
                                        EXIT FUNCTION
                                    END IF
                                    FUNCTION = %TRUE
                                END FUNCTION

                                Comment


                                  #17
                                  Oh, foo. I wrote a great reply to this but that appears to have been a casualty of the software change. Maybe I can remember it and do it again.
                                  Michael Mattias
                                  Tal Systems (retired)
                                  Port Washington WI USA
                                  [email protected]
                                  http://www.talsystems.com

                                  Comment

                                  Working...
                                  X
                                  😀
                                  🥰
                                  🤢
                                  😎
                                  😡
                                  👍
                                  👎