//+++++++++++++++++++++++++++++++
// +++++ DDEPoke for MATLAB 16bit
#include <windows.h>
#include <ddeml.h>
#include <stdlib.h> //fuer _gcvt()
#include <string.h> //strlen()
#define DLLMEX
extern "C"
{
#include "..\header\mex.h"
#include "..\header\testargs.h"
}
#include "..\header\fastdde.h"
#pragma hdrstop
#define ARGS_IN_MIN 3
#define ARGS_IN_MAX 5
#define ARG1_IN prhs[0] //channel
#define ARG2_IN prhs[1] //item
#define ARG3_IN prhs[2] //data
#define ARG4_IN prhs[3] //cbFormat
#define ARG5_IN prhs[4] //timeout
#define ARG1_OUT plhs[0] //return code
extern "C" void mexFunction(
int nlhs,
Matrix *plhs[],
int nrhs,
Matrix *prhs[]
)
{
DWORD timeout = TIMEOUT;
WORD cbFormat = CF_TEXT; //default
double Result = 0;
if ( TestIOArgs( nrhs, ARGS_IN_MIN, ARGS_IN_MAX ) && //alle erforderlichen Parameter angegeben?
TestChannelArg( ARG1_IN ) && //Channel-Argument ok?
TestItemArg( ARG2_IN ) ) //Item-Argument ok?
{
if ( nrhs >= ARGS_IN_MAX - 1 ) //4. Parameter (Clipboard-Format)?
{
cbFormat = TestFormatArg( ARG4_IN, NO_CHK_STR_FORMAT, NULL );
if ( nrhs == ARGS_IN_MAX ) //5. Parameter (TimeOut)?
timeout = TestTimeoutArg( ARG5_IN );
}
if (cbFormat != (WORD)-1 && //sind bei ungueltigen Argumenten
timeout != (DWORD)-1 ) // -1
{
int n;
DWORD hChannel[2]; //2 mal 32 bit
PokeFuncParam FParam;
hmemcpy( (char*)hChannel, (char huge*)mxGetPr(ARG1_IN), sizeof(double) );
//Struktur zur Parameteruebergabe an Unterfunktion fuellen
FParam.hConv = hChannel[0];
FParam.idInst = hChannel[1];
FParam.cbFormat = cbFormat;
FParam.timeout = timeout;
FParam.Data_Matrix = ARG3_IN;
char* szItem = (char*) mxCalloc( n= (int)mxGetN(ARG2_IN) + 1, sizeof(char) );
if ( szItem )
{
mxGetString( ARG2_IN, szItem, n );
FParam.hszItem = DdeCreateStringHandle( FParam.idInst, szItem, CP_WINANSI );
mxFree( szItem );
if ( FParam.hszItem )
{
//Absprung in Abhaengigkeit des gewaehlten Clipboard-Formates
if ( cbFormat == CF_TEXT ) // CF_TEXT Format
{
if ( CFTextPoke( &FParam ) )
Result = (double)1;
}
else // Excel Format
{
if ( FastDDEPoke( &FParam ) )
Result = (double)1;
}
DdeFreeStringHandle ( FParam.idInst, FParam.hszItem );
}
else
HandleDdeError(DdeGetLastError(FParam.idInst));
}
else
{
mexPrintf( "??? Memory allocation error.\r\n" );
ErrorBeep();
}
}
}
ARG1_OUT = mxCreateFull(1, 1, REAL);
hmemcpy( (char huge*)mxGetPr(ARG1_OUT), (char*)&Result, sizeof(double) );
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CFTextPoke( PokeFuncParam* FParam )
{
HDDEDATA hTrans; //Ergebnis der DDE Transaktion
HGLOBAL hGlobal; //Handle auf freien Speicherbereich
DWORD maxLength;
DWORD rows, columns;
rows = (DWORD) mxGetM( FParam->Data_Matrix );
columns = (DWORD) mxGetN( FParam->Data_Matrix );
if (mxIsString(FParam->Data_Matrix)) {
maxLength=(columns+2)*rows -1; /* jede Zeile mit 0D0A abgeschlossen, die letzte mit 00 */
hGlobal=GlobalAlloc(0,maxLength);
if (!hGlobal) {
mexPrintf( __FILE__ "??? Memory allocation error.\r\n" );
ErrorBeep();
}
char huge *dst=GlobalLock(hGlobal);
double huge *src=mxGetPr(FParam->Data_Matrix);
for (;rows--;) {
for (;columns--;) {
*dst++=(char)*src++;
}
if (rows) {
*dst++='\r';
*dst++='\n';
}else{
*dst++='\0';
}
}
GlobalUnlock(hGlobal);
hTrans = DdeClientTransaction( GlobalLock(hGlobal), maxLength, FParam->hConv, FParam->hszItem,
FParam->cbFormat, XTYP_POKE, FParam->timeout, NULL );
}else{
//zwischen den Strings darf keine null stehen, nur TAB oder CR+LF
//maximale Laenge der in Strings konvertierten Matrix (in bytes)
maxLength = rows*columns*((DWORD)(CVT_DIGITS + 10)); //... + 10 fuer '\0', E+10 usw.
maxLength += rows*(columns-1); //Tabs am Spaltenende
maxLength += 2*rows; //CR+LF am Zeilenende
//Speicher fuer eine Zahl
char* cvtString = (char*)mxCalloc( CVT_DIGITS + 10, sizeof(char) ); //... + 10 fuer '\0', E+10 usw.
//Speicher reservieren
hGlobal = GlobalAlloc( GPTR, maxLength+1 ); //+1, damit am Ende immer eine null stehen kann
if ( !cvtString || !hGlobal )
{
mexPrintf( "??? Memory allocation error.\r\n" );
ErrorBeep();
if ( cvtString ) mxFree( cvtString );
if ( hGlobal ) GlobalFree( hGlobal );
return FALSE;
}
char huge* hData = GlobalLock( hGlobal );
char huge* dest = hData;
//Zeiger auf MATLAB-Matrix holen
double huge* src = (double huge*)mxGetPr( FParam->Data_Matrix );
int count; //StringLaenge ohne abschliessende null
DWORD index = 0; //Index zum Zugriff auf MATLAB-Matrix
DWORD realLength = 0; //reale Stringlaenge (d.h. evtl. ohne Vorzeichen usw.)
//Matrix transponieren
for ( int i = 0; i < (int)rows; i++ )
{
index = (DWORD)i;
for ( int k = 0; k < (int)columns; k++ )
{
// index = (DWORD)i+ ((DWORD)k * (DWORD)rows); //schneller: siehe 2 Zeilen weiter
count = StringConvert( cvtString, src[index] );
index += (DWORD)rows;
hmemcpy( (char huge*)dest, (char*)cvtString, count );
dest += count;
*dest++ = '\t'; //Spaltenende
realLength += (count+1); //count + einen Tabulator
}
dest--;
*dest++ = '\r'; //Zeilenende
*dest++ = '\n';
realLength++;
}
*dest = '\0'; //abschliessende Null
mxFree( cvtString );
hTrans = DdeClientTransaction( hData, realLength+1, FParam->hConv, FParam->hszItem,
FParam->cbFormat, XTYP_POKE, FParam->timeout, NULL );
}
GlobalUnlock( hGlobal );
GlobalFree( hGlobal );
return (BOOL)hTrans;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
_inline int StringConvert( char* cvtString, double value )
{
//double -> string
_gcvt( value, CVT_DIGITS, cvtString );
return strlen( cvtString ); //= Laenge ohne StringEnde-Null
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL FastDDEPoke( PokeFuncParam* FParam )
{
HDDEDATA hTrans;
HDDEDATA hData;
FastDDEMemValues DDEMemVal;
DWORD DBLength; //Laenge der gesamten DDE-Transaktion in Bytes
long MSize; //Anzahl der Matrix-Elemente
//Struktur zur Uebergabe an FastDDEMem()
DDEMemVal.hPr = (double huge*) mxGetPr( FParam->Data_Matrix );
DDEMemVal.rows = (int) mxGetM( FParam->Data_Matrix );
DDEMemVal.columns = (int) mxGetN( FParam->Data_Matrix );
DDEMemVal.quot = 0;
//Laenge in Bytes fuer alle tdtx-Header berechnen
MSize = (long)DDEMemVal.rows * (long)DDEMemVal.columns;
while ( (MSize - maxData) >= 0 ) // => quot=MSize/maxData und rem=MSize%maxData
{
DDEMemVal.quot++;
MSize -= maxData;
}
DDEMemVal.offset = 8 + (DDEMemVal.quot * 4); //tdtTableLaenge + (quot * tdtFloatLaenge)
DDEMemVal.rem = (int)MSize;
if ( DDEMemVal.rem != 0 )
DDEMemVal.offset += 4; //tdtFloat-Header fuer letzten tdtFloat-Block
//Laenge in DDEMemVal.offset gespeichert
//Laenge der gesamten DDE-Transaktion in Bytes
DBLength = (DWORD)DDEMemVal.offset + ((DWORD)DDEMemVal.rows * (DWORD)DDEMemVal.columns * sizeof(double));
hData = DdeCreateDataHandle( FParam->idInst, NULL, DBLength, 0, FParam->hszItem, FParam->cbFormat, NULL );
if ( !hData )
{
HandleDdeError(DdeGetLastError(FParam->idInst));
return FALSE;
}
DDEMemVal.hDataBlock = DdeAccessData( hData, NULL );
FastDDEMem( &DDEMemVal ); //Erstellen der kompletten Datenstruktur
DdeUnaccessData( hData );
hTrans = DdeClientTransaction( (LPBYTE) hData, (DWORD) -1, FParam->hConv, FParam->hszItem,
FParam->cbFormat, XTYP_POKE, FParam->timeout, NULL );
DdeFreeDataHandle( hData );
return (BOOL)hTrans;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
void FastDDEMem( FastDDEMemValues* DDEMemVal )
{
WORD tdtTable_block[] = {tdtTable, 4, DDEMemVal->rows, DDEMemVal->columns};
WORD tdtFloat_block[] = {tdtFloat, maxData * sizeof(double)};
WORD tdtFloat_last_block[] = {tdtFloat, DDEMemVal->rem * sizeof(double)};
// *** tdtTable Block kopieren und StartPointer anpassen
hmemcpy( (char*)DDEMemVal->hDataBlock, (char*)tdtTable_block, sizeof(tdtTable_block) );
DDEMemVal->hDataBlock += sizeof(tdtTable_block);
if ( DDEMemVal->quot == 0 ) //Datenmenge < maxData
{
hmemcpy( (char*)DDEMemVal->hDataBlock, (char*)tdtFloat_last_block, sizeof(tdtFloat_last_block) );
DDEMemVal->hDataBlock += sizeof(tdtFloat_last_block);
}
else //Datenmenge >= maxData
{
hmemcpy( (char*)DDEMemVal->hDataBlock, (char*)tdtFloat_block, sizeof(tdtFloat_block) );
DDEMemVal->hDataBlock += sizeof(tdtFloat_block);
}
BYTE* dest = (BYTE*)DDEMemVal->hDataBlock; //transponierte Matrix
double huge* src = (double huge*)DDEMemVal->hPr; //MATLAB-Matrix
double value;
int l_quot = 0;
int loop = 0;
DWORD index = 0;
// *** Matrix transponieren
for ( int i = 0; i < DDEMemVal->rows; i++ )
{
for ( int k = 0; k < DDEMemVal->columns; k++ )
{
//Einfuegen der tdtFloat-Header nach Aufteilung in Datenbloecke der Groesse maxData
if ( loop == maxData ) //nach maxData Werten...
{
l_quot++; //l_quot maxDataDatenbloecke
loop = 0; //neuer Datenblock wird begonnen
if ( l_quot < DDEMemVal->quot ) //sind noch maxData-Datenbloecke vorhanden?
{
hmemcpy( (char*)dest, (char*)tdtFloat_block, sizeof(tdtFloat_block) );
dest += sizeof(tdtFloat_block); //dann tdtFloat-Header einfuegen
}
else
{
hmemcpy( (char*)dest, (char*)tdtFloat_last_block, sizeof(tdtFloat_last_block) );
dest += sizeof(tdtFloat_last_block); //dann letzten tdtFloat-Header einfuegen
}
}
//Ende der Header-Einfuege-Routine
loop++;
index = (DWORD)i+ ((DWORD)k * (DWORD)DDEMemVal->rows);
value = src[index];
hmemcpy( (char*)dest, (char*)&value, sizeof(double) );
dest += sizeof(double);
}
}
}
Detected encoding: ASCII (7 bit) | 2
|