Jump to content

DDEML.au3 - DDE Client + Server


Recommended Posts

I think there is a problem with Unicode implementation in DDEML. The following script uses POKE transaction to put "24" in Excel cell R2C2. Book1.xls should be open in Excel.

#include <DDEML.au3>
#include <DDEMLClient.au3>

_DdeInitialize("", BitOR($APPCMD_CLIENTONLY, $CBF_SKIP_ALLNOTIFICATIONS))

$hszService = _DdeCreateStringHandle("excel")
$hszTopic = _DdeCreateStringHandle("[Book1.xls]Sheet1")
$hConvSrv = _DdeConnect($hszService, $hszTopic)

$hszItem = _DdeCreateStringHandle("R2C2")

$res = _DdeClientTransaction($XTYP_POKE, $hConvSrv, 24, 1000, $hszItem, $CF_TEXT)

_DdeFreeStringHandle($hszService)
_DdeFreeStringHandle($hszTopic)
_DdeDisconnect($hConvSrv)
_DdeUninitialize()

However this code will only work if compiled as ANSI. If it is compiled as Unicode, only the first symbol ("2") is sent to the Excel cell (even if $CF_TEXT is replaced with $CF_UNICODETEXT). If "wchar" is replaced with "char" in line 619 of DDEML.au3, everything works fine. The alternative way of doing the POKE transaction which sends a data handle rather than a pointer to user32.dll, does not work. Stateless _DDEMLClient_Poke("excel", "[book1.xls]Sheet1", "R2C2", "24", $CF_UNICODETEXT) does not work either (also with $CF_TEXT). I think these issues are also connected with the Unicode problems.

Thanks!

Link to post
Share on other sites
  • 2 weeks later...
  • Replies 98
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Popular Posts

It's been frequently asked here, but no complete solution provided. Well, now it's here! With DDEML UDF one can use an AutoIt script as a DDE client or server. Version 1.5.4 DDEML: invalid struct d

Hello. I have 2 questions: 1) in registers under ddeexec key for .dwg files (for AutoCAD) says [open("%1")] Do I need to enclose the command in square brackets? 2) for some

Try this one --  

  • 2 months later...

Sorry, everyone who was expecting an answer: something is wrong with topic subscription here and I was to busy to check the posts manually.

UDFS & Apps:

Spoiler

DDEML.au3 - DDE Client + Server
Localization.au3 - localize your scripts
TLI.au3 - type information on COM objects (TLBINF emulation)
TLBAutoEnum.au3 - auto-import of COM constants (enums)
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector - OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCE 

Link to post
Share on other sites

@doudou - thank you for this

My pleasure.

I have tried to make a simple Gui (with a label having data from a file) to work as a DDE Server for the Excel (client) - without success.

Is it possible at all? - if yes, i would appreciate some advice.

As long as there are mechanisms in Excel to talk to a DDE server it is surely possible. I didn't investigate Excel DDE capabilities but if You post the code of Your efforts (both sides, client and server), I'd take a look at it and try to help.

UDFS & Apps:

Spoiler

DDEML.au3 - DDE Client + Server
Localization.au3 - localize your scripts
TLI.au3 - type information on COM objects (TLBINF emulation)
TLBAutoEnum.au3 - auto-import of COM constants (enums)
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector - OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCE 

Link to post
Share on other sites

I downloaded au3_ddeml_v1.4.zip and au3_ddeml_samples.zip, But I can't execute the examples within the samples.

Can you give a simple and clear sample code ? Thanks!

In case You still have problems with that can You please state more precisely what You were doing and what the outcome was?

UDFS & Apps:

Spoiler

DDEML.au3 - DDE Client + Server
Localization.au3 - localize your scripts
TLI.au3 - type information on COM objects (TLBINF emulation)
TLBAutoEnum.au3 - auto-import of COM constants (enums)
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector - OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCE 

Link to post
Share on other sites

If I had set a excel's cell which value is "=YES|DQ!'&TWTK1.Price'" , It can update the DDE data souce.

How Can I write the same code by autoit and DDEML ?

Shame on me - absolutely no idea, what You are talking about. How can a cell in Excel update DDE data source? What is after all this DDE data source?

I think it is impossible to help out requests of such chunked format because all the context is missing. Like in:

- Officer, if I go 60 mph can I get ticket for speeding?

- Well, it depends...

UDFS & Apps:

Spoiler

DDEML.au3 - DDE Client + Server
Localization.au3 - localize your scripts
TLI.au3 - type information on COM objects (TLBINF emulation)
TLBAutoEnum.au3 - auto-import of COM constants (enums)
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector - OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCE 

Link to post
Share on other sites

I think there is a problem with Unicode implementation in DDEML. The following script uses POKE transaction to put "24" in Excel cell R2C2. Book1.xls should be open in Excel.

#include <DDEML.au3>
#include <DDEMLClient.au3>

_DdeInitialize("", BitOR($APPCMD_CLIENTONLY, $CBF_SKIP_ALLNOTIFICATIONS))

$hszService = _DdeCreateStringHandle("excel")
$hszTopic = _DdeCreateStringHandle("[Book1.xls]Sheet1")
$hConvSrv = _DdeConnect($hszService, $hszTopic)

$hszItem = _DdeCreateStringHandle("R2C2")

$res = _DdeClientTransaction($XTYP_POKE, $hConvSrv, 24, 1000, $hszItem, $CF_TEXT)

_DdeFreeStringHandle($hszService)
_DdeFreeStringHandle($hszTopic)
_DdeDisconnect($hConvSrv)
_DdeUninitialize()

However this code will only work if compiled as ANSI. If it is compiled as Unicode, only the first symbol ("2") is sent to the Excel cell (even if $CF_TEXT is replaced with $CF_UNICODETEXT). If "wchar" is replaced with "char" in line 619 of DDEML.au3, everything works fine. The alternative way of doing the POKE transaction which sends a data handle rather than a pointer to user32.dll, does not work. Stateless _DDEMLClient_Poke("excel", "[book1.xls]Sheet1", "R2C2", "24", $CF_UNICODETEXT) does not work either (also with $CF_TEXT). I think these issues are also connected with the Unicode problems.

A very similar problem had been handled time ago in another topic DDE Command.

This has to do with DDE implementation generally: if the server talks ANSI only, You HAVE TO compile Your client as ANSI. We could of course break up the UNICODE automatism in the UDF leaving the choice of all arguments to API calls to the programmer but this way one could use Win32 as well directly.

Edited by doudou

UDFS & Apps:

Spoiler

DDEML.au3 - DDE Client + Server
Localization.au3 - localize your scripts
TLI.au3 - type information on COM objects (TLBINF emulation)
TLBAutoEnum.au3 - auto-import of COM constants (enums)
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector - OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCE 

Link to post
Share on other sites
  • 4 weeks later...

Hello,

I am writing a DDE server in AutoIT3 using a slightly modified version of the sample Server program provided by this UDF. I will be communicating with it using a client program written in C# .NET using the NDde.dll class libraries and it's DDE functions.

To request information from the server, I will be using the NDde command: client.Request (string Command, int Timeout) to request data from the AutoIT3 based server. Will this work with the sample server program?

In other words, can anyone give me an example of what I need to add to the (sample)server script to have it return data when it receives a client.Request() command from a client program?

Thanks!

Keymaker

Edited by Keymaker
Link to post
Share on other sites

To request information from the server, I will be using the NDde command: client.Request (string Command, int Timeout) to request data from the AutoIT3 based server. Will this work with the sample server program?

In other words, can anyone give me an example of what I need to add to the (sample)server script to have it return data when it receives a client.Request() command from a client program?

Essentially all You have to do is add a callback to Your server (here addition to SampleDDEServer):

Func OnDDE_Request($szTopic, $szItem, $uFmt, $hConv)
    ConsoleWrite("OnDDE_Request(" & $szTopic & ", " & $szItem & ")" & @CRLF)
    return _DdeCreateDataHandle("My data")
EndFunc

You can pass any data (binaries too) as result handle, You will have to set the last optional parameter $wFmt of _DdeCreateDataHandle appropriately then (s. ClipboardConstants.au3).

UDFS & Apps:

Spoiler

DDEML.au3 - DDE Client + Server
Localization.au3 - localize your scripts
TLI.au3 - type information on COM objects (TLBINF emulation)
TLBAutoEnum.au3 - auto-import of COM constants (enums)
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector - OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCE 

Link to post
Share on other sites

Essentially all You have to do is add a callback to Your server (here addition to SampleDDEServer):

Func OnDDE_Request($szTopic, $szItem, $uFmt, $hConv)
    ConsoleWrite("OnDDE_Request(" & $szTopic & ", " & $szItem & ")" & @CRLF)
    return _DdeCreateDataHandle("My data")
EndFunc

You can pass any data (binaries too) as result handle, You will have to set the last optional parameter $wFmt of _DdeCreateDataHandle appropriately then (s. ClipboardConstants.au3).

Thanks i'll try that.

One last question. Why is it when I run Syntax check, I get errors saying: "@Unicode is an undefined macro" ?

Thanks

Link to post
Share on other sites

One last question. Why is it when I run Syntax check, I get errors saying: "@Unicode is an undefined macro" ?

New macro @AutoItUnicode will be integrated in v. 1.5 of DDEML, keep checking this thread.

UDFS & Apps:

Spoiler

DDEML.au3 - DDE Client + Server
Localization.au3 - localize your scripts
TLI.au3 - type information on COM objects (TLBINF emulation)
TLBAutoEnum.au3 - auto-import of COM constants (enums)
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector - OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCE 

Link to post
Share on other sites

One last question. Why is it when I run Syntax check, I get errors saying: "@Unicode is an undefined macro" ?

Fixed: version 1.5 is online - works with AutoIt 3.3 (s. the very top post in this topic).

UDFS & Apps:

Spoiler

DDEML.au3 - DDE Client + Server
Localization.au3 - localize your scripts
TLI.au3 - type information on COM objects (TLBINF emulation)
TLBAutoEnum.au3 - auto-import of COM constants (enums)
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector - OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCE 

Link to post
Share on other sites

Essentially all You have to do is add a callback to Your server (here addition to SampleDDEServer):

Func OnDDE_Request($szTopic, $szItem, $uFmt, $hConv)
    ConsoleWrite("OnDDE_Request(" & $szTopic & ", " & $szItem & ")" & @CRLF)
    return _DdeCreateDataHandle("My data")
EndFunc

You can pass any data (binaries too) as result handle, You will have to set the last optional parameter $wFmt of _DdeCreateDataHandle appropriately then (s. ClipboardConstants.au3).

Ok, I still can't get this work with my application. My application requests info from the DDE server using the following .NET code:

private void SendInfoRequest_Click(object sender, EventArgs e)
        {
            string Command = String.Empty;
            byte[] data = new byte[1024];
            System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();

            try
            {
               using (DdeClient Client = new DdeClient("Player", InfoTopic.Text))
               {
                    Client.TryConnect(); // Connect to the server.
                    if (Client.IsConnected)
                        Messages.Text = "Connected successfully!" + "\r\n";

                    Command = InfoCommand.Text;
                    if (Command != String.Empty)
                    {
                         Client.TryRequest(Command, 1, 5000, out data);
                         Messages.Text = enc.GetString(data);
                    }
                    else
                        Messages.Text = "No command to send. Please enter a valid command.";
                }
            }
            catch (Exception ex)
            {
                Messages.Text = ex.ToString();
            }
        }

As you can see, the Client.TryRequest() expects data to be returned in a byte array. When I execute this using the OnDDE_Request code provided above I get an error saying the byte array is null. It looks like the OnDDE_Request function returns a handle instead of byte data.

I know my code works because I have tried it on two other DDE server apps and they return data in the correct format (byte data). What changes need to be made to the OnDDE_Request function so that it returns data as a byte array?

Thanks

Keymaker.

Edited by Keymaker
Link to post
Share on other sites

Ok, I still can't get this work with my application. My application requests info from the DDE server using the following .NET code:

private void SendInfoRequest_Click(object sender, EventArgs e)
        {
            string Command = String.Empty;
            byte[] data = new byte[1024];
            System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();

            try
            {
               using (DdeClient Client = new DdeClient("Player", InfoTopic.Text))
               {
                    Client.TryConnect(); // Connect to the server.
                    if (Client.IsConnected)
                        Messages.Text = "Connected successfully!" + "\r\n";

                    Command = InfoCommand.Text;
                    if (Command != String.Empty)
                    {
                         Client.TryRequest(Command, 1, 5000, out data);
                         Messages.Text = enc.GetString(data);
                    }
                    else
                        Messages.Text = "No command to send. Please enter a valid command.";
                }
            }
            catch (Exception ex)
            {
                Messages.Text = ex.ToString();
            }
        }

As you can see, the Client.TryRequest() expects data to be returned in a byte array. When I execute this using the OnDDE_Request code provided above I get an error saying the byte array is null. It looks like the OnDDE_Request function returns a handle instead of byte data.

I know my code works because I have tried it on two other DDE server apps and they return data in the correct format (byte data). What changes need to be made to the OnDDE_Request function so that it returns data as a byte array?

Thanks

Keymaker.

Sorry, the last release of DDEML was buggy. I submitted v. 1.5.1 (s. 1st post) along with functioning examples for DDE request (SampleDDEClient, SampleDDEServer).

Working with requests 2 things are absolutely essential:

1. The requested item must be the same one used in server for returned data handle (therefore OnDDE_Request callback receives now hszItem instead of converted string).

2. The requested data format must match returned one (i.e. if request was sent for CF_UNICODETEXT, server should create data handle for CF_UNICODETEXT as well).

Unless both conditions are met Win API would always return DDE_FNOTPROCESSED to the client regardless of what the server actually replied. If You don't know what string formats Your client is set for, You can try both CF_TEXT and CF_UNICODETEXT by manually setting

Global Const $_DDEML_UNICODE = 1

accordingly in Your server code BEFORE including DDEML.au3.

General tip: the best way to find out, what is going wrong during a DDE conversation is running DDE Spy tool from Windows SDK at the same time. Providing the output of the Spy here would help me a lot to help You in case of troubles with DDEML.

UDFS & Apps:

Spoiler

DDEML.au3 - DDE Client + Server
Localization.au3 - localize your scripts
TLI.au3 - type information on COM objects (TLBINF emulation)
TLBAutoEnum.au3 - auto-import of COM constants (enums)
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector - OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCE 

Link to post
Share on other sites
  • 2 weeks later...

Thank you for good modules!

but, i have one question.

( i'm korean. sorry for my english.. )

How can i use the DDE server's $XTYP_ADVREQ call back fuctions?

any example for DDE server's $XTYP_ADVREQ callback functions?

i want to update the client's input box from server realtime datas.

i called my vars like below.

func SetMyVarsToClient() 
   _DdePostAdvise( _DdeQueryString($topic) , _DdeQueryString('10') );
EndFunc

Func OnDDE_AdvReq($dwData1,$szTopic, $hszItem, $uFmt, $hConv)
    Local $szItem = _DdeQueryString($hszItem)
    if $szItem='10' then 
       return _DdeCreateDataHandle( '5678' , 0, $szItem, $uFmt)
    endif 
EndFunc

but, the value (5678) is not retuned to client.

please... any idea?

Link to post
Share on other sites

Thank you for good modules!

My pleasure.

How can i use the DDE server's $XTYP_ADVREQ call back fuctions?

any example for DDE server's $XTYP_ADVREQ callback functions?

i want to update the client's input box from server realtime datas.

i called my vars like below.

func SetMyVarsToClient() 
   _DdePostAdvise( _DdeQueryString($topic) , _DdeQueryString('10') );
EndFunc

Func OnDDE_AdvReq($dwData1,$szTopic, $hszItem, $uFmt, $hConv)
    Local $szItem = _DdeQueryString($hszItem)
    if $szItem='10' then 
       return _DdeCreateDataHandle( '5678' , 0, $szItem, $uFmt)
    endif 
EndFunc

but, the value (5678) is not retuned to client.

please... any idea?

As already discussed here using DDE advise loops is most complicated and I would not recommend that. If You must go this way, please refer to the mentioned post and particularly these MSDN articles:

http://msdn.microsoft.com/en-us/library/ms648716(VS.85).aspx

http://msdn.microsoft.com/en-us/library/ms648714(VS.85).aspx

http://msdn.microsoft.com/en-us/library/ms648717(VS.85).aspx

UDFS & Apps:

Spoiler

DDEML.au3 - DDE Client + Server
Localization.au3 - localize your scripts
TLI.au3 - type information on COM objects (TLBINF emulation)
TLBAutoEnum.au3 - auto-import of COM constants (enums)
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector - OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCE 

Link to post
Share on other sites

Thank you "Dr."doudou :-)

i knew these msdn sites articles already.

however, i can't understand these documents.

so.... i'm sorry but, i need your help. :)

i made the advise loop DDE Client already.

My DDE Client used OnDDE_AdvData( ... ) CallBack Functions.

and this DDE Server (My DDE Client connected.) was not made by AutoIT3.

it's a good job!

But,

now. i need to make DDE Server.

so, i use autoIt3 too.

the DDE Client is same program.

I make DDE Server hard.

but, i can't understand the DDE Server Advise looping mechanism..

because of my ability in English.

i can't find any korean documents about it.. ( MSDN korea, too )

so i need "Advise looping about AutoIT3 DDE Server Example Source.. using DDEML.au3 UDF.

here is my sample test code.

please teach me, or some hints..

#include <DDEML.au3>
#include <DDEMLServer.au3>
Opt("OnExitFunc", "CleanExit")

$hszSrvService = 0
$topic = '';
$_flag = False;

If $DMLERR_NO_ERROR = _DdeInitialize("OnDDE_", $APPCLASS_STANDARD) Then
    $hszSrvService = _DdeCreateStringHandle("TESTSERVER")
    If Not _DdeNameService($hszSrvService, $DNS_REGISTER) Then MsgBox(0, 'error', "error for init")
Else
    MsgBox(0, 'error', "error for init 2")
EndIf

; main loop
While 1
    
    if $_flag = True then 
        _DdePostAdvise( _DdeCreateStringHandle($topic) , _DdeCreateStringHandle('10')  );       
    endif 
    
WEnd

Func OnDDE_Connect($szTopic, $szService)
    $topic = $szTopic;
    ConsoleWrite("OnDDE_Connect(" & $szTopic & ", " & $szService & ")" & @CRLF)
    $_flag = True;
    Return 1
EndFunc

Func OnDDE_AdvStart( $hsz1, $hsz2, $uFmt, $hConv)
    ConsoleWrite( 'start ' &  $hsz1 & ' / ' &  $hsz2 & @CRLF );
    
; return 1 = return True?
    return 1;
EndFunc

Func OnDDE_Disconnect($hConv)
    ConsoleWrite("OnDDE_Disconnect()" & @CRLF)
    Return 0
EndFunc

Func OnDDE_AdvReq($dwData1,$szTopic, $hszItem, $uFmt, $hConv)

; test moving value.
    $test_data = Random(1,10);
    $item = _DdeQueryString( $hszItem );
    
; Event Callback test
    ConsoleWrite( 'req ' &  $szTopic & ' / ' &$item & @CRLF );]

    Local $hData = _DdeCreateDataHandle($test_data, 0, $hszItem)
    If @error Then ConsoleWriteError("data alloc error (0x" & StringFormat("%x", @error) & ")" & @CRLF)
    return $hData

EndFunc

Func OnDDE_Request($szTopic, $hszItem, $uFmt, $hConv)
; request test 
; this query is one time only by client call.
    Local $hData = _DdeCreateDataHandle('first time request', 0, $hszItem)
    If @error Then ConsoleWriteError("data alloc error (0x" & StringFormat("%x", @error) & ")" & @CRLF)
    return $hData
EndFunc

Func CleanExit()
    If 0 <> $hszSrvService Then
        _DdeNameService($hszSrvService, $DNS_UNREGISTER)
        _DdeFreeStringHandle($hszSrvService)
    EndIf
    _DdeUninitialize()
EndFunc

i did change above source code after first posting.. ( some error fixed, sorry. )

thank in advance!

Edited by byseob
Link to post
Share on other sites
  • 11 months later...

Version 1.5.2 includes some updates due to AutoIt changes.

UDFS & Apps:

Spoiler

DDEML.au3 - DDE Client + Server
Localization.au3 - localize your scripts
TLI.au3 - type information on COM objects (TLBINF emulation)
TLBAutoEnum.au3 - auto-import of COM constants (enums)
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector - OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCE 

Link to post
Share on other sites
  • 1 month later...

Some functionality for exchanging raw data was missing. I've added it in 1.5.3 release.

UDFS & Apps:

Spoiler

DDEML.au3 - DDE Client + Server
Localization.au3 - localize your scripts
TLI.au3 - type information on COM objects (TLBINF emulation)
TLBAutoEnum.au3 - auto-import of COM constants (enums)
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector - OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCE 

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...