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.
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.
reverse engineer, the evil twin of the obverse decomposer
Active Members
335 posts
Posted 26 December 2008 - 10:39 AM
@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.
reverse engineer, the evil twin of the obverse decomposer
Active Members
335 posts
Posted 26 December 2008 - 11:17 AM
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.
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.
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?
reverse engineer, the evil twin of the obverse decomposer
Active Members
335 posts
Posted 27 January 2009 - 11:58 PM
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):
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).
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" ?
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:
Plain Text
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?
reverse engineer, the evil twin of the obverse decomposer
Active Members
335 posts
Posted 12 February 2009 - 01:57 AM
Ok, I still can't get this work with my application. My application requests info from the DDE server using the following .NET code:
Plain Text
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
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.
reverse engineer, the evil twin of the obverse decomposer
Active Members
335 posts
Posted 23 February 2009 - 04:49 PM
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:
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..
Plain Text
#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. )