DDE execute from LiveCode

Deploying to Windows? Utilizing VB Script execution? This is the place to ask Windows-specific questions.

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller

trevix
Posts: 1064
Joined: Sat Feb 24, 2007 11:25 pm
Contact:

Re: DDE execute from LiveCode DONE !!!

Post by trevix » Tue Mar 06, 2012 6:39 pm

Ok...I managed to make it works even with my nonexistente C++ knowledge. Even if the code is probably quite "dirty", I'm proud of it (most of it is not mine, anyway).
This is the C++ code:

Code: Select all

//Make DLL to send DDEexecute from LiveCode
// Generated by External Creator V1.00
// For language: C++ (no exceptions, no rtti)

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <C:\Documents and Settings\3vix\Build LC external\ExternalsEnvironmentV3\libexternal\src\external.h>
//#include "stdafx.h"
#include "windows.h"
#include "ddeml.h"
#include "stdio.h"
#include <string>
#include <iostream>
using namespace std;

////////Roba di DDE///////////////////////////////////////////////////////////////////////
HDDEDATA CALLBACK DdeCallback(
    UINT uType,     // Transaction type.
    UINT uFmt,      // Clipboard data format.
    HCONV hconv,    // Handle to the conversation.
    HSZ hsz1,       // Handle to a string.
    HSZ hsz2,       // Handle to a string.
    HDDEDATA hdata, // Handle to a global memory object.
    DWORD dwData1,  // Transaction-specific data.
    DWORD dwData2)  // Transaction-specific data.
{
    return 0;
}
char *risultato = "0";

void DDEExecute(DWORD idInst, HCONV hConv, char* szCommand)
{
	HDDEDATA hData = DdeCreateDataHandle(idInst, (LPBYTE)szCommand,
                               lstrlen(szCommand) +1, 0, NULL, CF_TEXT, 0);
    if (hData==NULL)   {
		risultato = "Parametri di comando errati!";
		return;
    }
    else    {
        DdeClientTransaction((LPBYTE)hData, 0xFFFFFFFF, hConv, 0L, 0,
                             XTYP_EXECUTE, TIMEOUT_ASYNC, NULL);
    }
}

void GetDDEready(char* TheApp, char* TheTopic, char* TheVar) //prepare connection DDE
{
//char myapp[] = "IOMidaDB";
	//char mytopic[] = "IOM4";
	//richiesta dati per ID
	//char szCmd1[] = "S;C:/archiviMida4/O01820110701.MDB;;C:/CC_SaniMont_DB2012/IOMidaDbFornitura/RisultatoMida.txt;C:/CC_SaniMont_DB2012/IOMidaDbFornitura/EsitoMida.txt;2646_ClienteCodice;10";
	//char szCmd1[] = p_arguments[2];

	//DDE Initialization
    DWORD idInst=0;
    UINT iReturn;
    iReturn = DdeInitialize(&idInst, (PFNCALLBACK)DdeCallback, 
                            APPCLASS_STANDARD | APPCMD_CLIENTONLY, 0 );
    if (iReturn!=DMLERR_NO_ERROR)
    {
		risultato = "Inizializzazione DDE fallita !";
		return;
    }

    //DDE Connect to Server using given AppName and topic.
    HSZ hszApp, hszTopic;
    HCONV hConv;
    //hszApp = DdeCreateStringHandle(idInst, myapp, 0);
    //hszTopic = DdeCreateStringHandle(idInst, mytopic, 0);
	hszApp = DdeCreateStringHandle(idInst, TheApp, 0);
    hszTopic = DdeCreateStringHandle(idInst, TheTopic, 0);
    hConv = DdeConnect(idInst, hszApp, hszTopic, NULL);
    DdeFreeStringHandle(idInst, hszApp);
    DdeFreeStringHandle(idInst, hszTopic);
    if (hConv == NULL)
    {
		risultato = "Connessione DDE fallita !";
		return;
    }
    //Execute commands/requests specific to the DDE Server.
	DDEExecute(idInst, hConv, TheVar); //send the DDE
    //DDE Disconnect and Uninitialize.
    DdeDisconnect(hConv);
    DdeUninitialize(idInst);
}
void runDDEexecute(char *p_arguments[], int p_argument_count,
                  char **r_result, Bool *r_pass, Bool *r_err)
//void rnaHelloUser(char *p_arguments[], int p_argument_count,
                  //char **r_result, Bool *r_pass, Bool *r_err)
{
// First check we have been passed a single argument ñ if not itís an error
//
if (p_argument_count != 3)
{
*r_result = strdup("Wrong number of parameters");
*r_err = True;
*r_pass = False;
return;
}
GetDDEready(p_arguments[0],p_arguments[1],p_arguments[2]); //get connection
// Next compute the length of our required string
unsigned int t_buffer_length;
char *t_buffer;
p_arguments[0]= risultato;
t_buffer_length = strlen(p_arguments[0]) + 1;
t_buffer = (char *)malloc(t_buffer_length);
if (t_buffer == NULL)
{
*r_result = strdup("out of memory");
*r_err = True;
*r_pass = False;
return;
}

// We have allocated our buffer ñ so now construct our string
sprintf(t_buffer, "%s", p_arguments[0]);
// t_buffer now contains a pointer to the result so just return...
*r_result = t_buffer;
*r_err = False;
*r_pass = False;
risultato = "0";
}

// END USER DEFINITIONS

EXTERNAL_BEGIN_DECLARATIONS("runDDE")
	//EXTERNAL_BEGIN_DECLARATIONS("rnahello")

// BEGIN USER DECLARATIONS
EXTERNAL_DECLARE_FUNCTION("runddeexecute", runDDEexecute)
// END USER DECLARATIONS

EXTERNAL_END_DECLARATIONS
The DDL produced must of course be put in the external directory of LiveCode and the text file "External" must be updated with a line "DDEexecute,ddeexte.dll".
If you create for example a Excel file named "C:/Test.xls", you open it and from LiveCode you send a runDDEexecute("Excel","C:/Test.xls","convid,'[close(false)]'") function (return 0 if correctly executed),...voilà: Excel close the doc!
Now...I have 2 problems:
1 - For my needs, the DDEexecute get sent from LC to an application that write something to disk (a text file). How can I have LC to wait until the file get written ? I believe that a recursive "get URL" doesn't make sense...uh?

2 - LiveCode 4.6.4: if I do a "put the externalPackages", I don't get anything. Not even the default externals.

If you need the dll, you can download it here:
http://www.managementcalendar.com/Downl ... addll.html
Trevix
Trevix
OSX 14.6.1 xCode 15 LC 10 RC1 iOS 15> Android 7>

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: DDE execute from LiveCode

Post by mwieder » Tue Mar 06, 2012 6:56 pm

2 - LiveCode 4.6.4: if I do a "put the externalPackages", I don't get anything. Not even the default externals.

Code: Select all

put the externalPackages of stack "xyzzy"
should show you the package name. Also

put the externalFunctions of...
put the externalCommands of...

Update: I just read your post again.
The DDL produced must of course be put in the external directory of LiveCode and the text file "External" must be updated with a line "DDEexecute,ddeexte.dll".
This is not a recommended way to use external libraries. And the code I posted above will not show you the externalPackages, etc. The built-in external packages (those in the LiveCode externals folder) are explicitly *not* displayed that way.

Instead, from the message box you can say

Code: Select all

set the externals of stack "xyzzy" to <path to your dll>
and then save the stack, close it, and reopen it.

I usually put a button on my test stack with the following code:

Code: Select all

on mouseUp
  answer file "where is the dll?"
  if it is not empty then
    set the externals of this stack to it
    save this stack
  end if
end mouseUp

trevix
Posts: 1064
Joined: Sat Feb 24, 2007 11:25 pm
Contact:

Re: DDE execute from LiveCode

Post by trevix » Wed Mar 07, 2012 9:48 am

Hi.
I forgot to say that I have already read the
http://lessons.runrev.com/s/lessons/m/4 ... your-stack
but a "Put the externalPackages of..." does not work.
What I understand is that the default externals are on the "C:\Programs\RunRev\LiveCode 4.6.4\Externals" and my externals are on the directory specified on the LiveCode preferences (File & Memory).
So the command "put the externalPackages of my stak" should show my dll, that is on the "User Extensions" folder.
Am I correct ?

One more thing: for some reason if I don't specifically select the "Select inclusions for the standalone application", but I leave "Search for required inclusions...", when I build the standalone the dll does not show up on the build ( it does if I use "Select inclusions..."). Is there something to do with the way the dll is created, like if LC does not recognize it ?
Trevix
Trevix
OSX 14.6.1 xCode 15 LC 10 RC1 iOS 15> Android 7>

trevix
Posts: 1064
Joined: Sat Feb 24, 2007 11:25 pm
Contact:

Re: DDE execute from LiveCode

Post by trevix » Wed Mar 07, 2012 12:40 pm

Mmmmh...
Finally, even though this should probably go on the "Extending LC" forum, I think that there must be a better way to do things...

When you run trough the standalone cycle and you want to use your new Mydll, you end up with a lot of places where your new extension is or must be (?):
- your Extensions user folder (as from LC preferences, for example: "C:\Documents and Settings\UserName\Documents\MyLiveCode\Externals\Mydll)
- your RunTime folder (for WinXP: ""C:\Documents and Settings\UserName\Documents\MyLiveCode\RunTime\Windows\x86-32\Externals\Mydll)
- when you build your Windows standalone you got also a folder "Externals\Mydll", beside your new app.

Things get even more confuse if you want also a OSX app, because you need different places...
(and do not forget the default externals directory in "C:\Programs\RunRev\LiveCode 4.6.4\Externals", even if it has no use with your Mydll)

If I understand, it is always the same file (Mydll) or the equivalent for OSX.

If you put your Mydll on the user Extensions folder, the "put the externalPackages" does not show it (but it works. So what is the use of the LC preference User Extensions directory???).
But if you load it, as mwieder said, with a "set the externals of stack "xyzzy" to <path to your dll>", then it shows. But it refers to your LC Extension User folder, so if you send the NewApp to someone else, it does not. You must do a "set the externals" of your stack to the folder beside you Win NewApp (or the not yet built package for a OSX NewApp).

As I said...you can do it, but there must be a better way to do things...
Trevix
Trevix
OSX 14.6.1 xCode 15 LC 10 RC1 iOS 15> Android 7>

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: DDE execute from LiveCode

Post by mwieder » Wed Mar 07, 2012 8:49 pm

trevix-

What are you trying to do?
Do you want the external library to function only in the IDE or are you creating a standalone application? Or a stack to distribute to others?

The answer to how to deal with the external library will be different for each of these situations.

If you want the library to function *only* when you are in the IDE, then you can place the library into e.g., "C:\Programs\RunRev\LiveCode 4.6.4\Externals". But there are two downsides to this:

1. you will have to do this again for different versions of LiveCode, since they each have separate Externals folders
2. nothing in that folder will show up when you look at the externalPackages

If you are going to distribute the stack itself to others then you probably want to place the external library in the same folder as the stack and set the externals of the stack to thename (not the full file path) of the external library file. If you are creating a standalone application then this technique should also work, and the standalone builder should put the external library into the right place for you.

trevix
Posts: 1064
Joined: Sat Feb 24, 2007 11:25 pm
Contact:

Re: DDE execute from LiveCode

Post by trevix » Wed Mar 07, 2012 9:47 pm

Thanks for your patience but...I got that.
I have to build a standalone, so for Win I have to do a "set the externals..." from the stack, pointing to the external folder beside the yet to be done standalone.
If I want to do a OSX standalone I need to point the stack to the resource folder inside the package (again...yet to be build!).

It is not that I have not understood or that I don't know how to do it...I was just moaning. I lost one day just to figure it out and to me it is pretty messy.
Trevix
Trevix
OSX 14.6.1 xCode 15 LC 10 RC1 iOS 15> Android 7>

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: DDE execute from LiveCode

Post by mwieder » Wed Mar 07, 2012 10:19 pm

It is not that I have not understood or that I don't know how to do it...
No... you *are* misunderstanding it. The externals property of the stack only needs to be set once, not each time the stack starts up.

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10043
Joined: Sat Apr 08, 2006 7:05 am
Contact:

Re: DDE execute from LiveCode

Post by FourthWorld » Wed Mar 07, 2012 10:39 pm

With relative paths that should be true, but I've had mixed results with relative paths in different versions and have since adopted a habit of setting the path dynamically during startup. If relative paths are expected to always work then I'll pin down a recipe and submit a bug report.
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: DDE execute from LiveCode

Post by mwieder » Wed Mar 07, 2012 11:55 pm

The only time I've had relative paths fail is when I've had a linked library that had a dependency on absolute file paths. Relative paths *should* always work... if you can pin this down to a bug report, that would be great.

Of course, it's safe to set this on startup, but it can easily lead to user confusion.

trevix
Posts: 1064
Joined: Sat Feb 24, 2007 11:25 pm
Contact:

Re: DDE execute from LiveCode

Post by trevix » Thu Mar 08, 2012 12:36 am

mwieder:
No... you *are* misunderstanding it. The externals property of the stack only needs to be set once, not each time the stack starts up.
Windows and OSX standalone put the externals in two different places, wright? So if you don't set it up on startup on the standalone, how would you do it (if off course you build them both in a single pass)?
The nice thing about OSX applications is that they have all the junk inside them...
Trevix
Trevix
OSX 14.6.1 xCode 15 LC 10 RC1 iOS 15> Android 7>

Klaus
Posts: 14177
Joined: Sat Apr 08, 2006 8:41 am
Contact:

Re: DDE execute from LiveCode

Post by Klaus » Thu Mar 08, 2012 3:30 pm

Hi Trevix,

yep, "on startup" is the best place to load externals!

Since Livecodes Standalone builder still does not copy third party external to the standalone,
like the Enhanced QuickTime External that I use a LOT, although they are listed in the standalone
builder settings, I started to add a "on startup" script manually to every standalone I build and
not check any of the external in the standalone builder!


Best

Klaus

Post Reply