library ddeinit;
uses PasMex32,Parser32,Windows,DDEML;
{jede dieser DLLs auf andere Basisadressen relozieren}
{$IMAGEBASE $10000000}
{$HINTS ON}
{$R ddeinit} {englisch und deutsch, DCC32 kann das nicht getrennt}
{$Z4}
const
idInst: LongInt=0; {globale Variable fr alle DDE-DLLs,...}
{Lesezugriff fr alle via GetInst-Funktion}
type
EClip=(Text,Unicode,XlTable,MatTable);
const
ClipNames: array[EClip] of PChar=(
'Text', {normaler ASCII-Text}
'UnicodeText', {16-bit-Zeichen fr's Japanisch}
'XlTable', {Clipboard-Format-Name fr FastDDE}
'MatTable'); {fr Double-Matrizen und -Arrays}
var {die Ergebnisse von RegisterClipboardFormat,...}
ClipForms: array[EClip] of UInt; {fr CheckClipFormat zur Umsetzung}
verbose: Integer;
{Schlafmtzen, die die Delphi-Standardbibliothek geschrieben haben:}
function wsprintf1(ret,template,a1: PChar):LongInt;
cdecl; external 'user32.dll' name 'wsprintfA';
function wsprintf2(ret,template,a1,a2: PChar):LongInt;
cdecl; external 'user32.dll' name 'wsprintfA';
function MyRegisterClipboardFormat(FormatName:PChar):UInt; stdcall;
{wie die Windows-Funktion, jedoch mit Verarbeitung von "Text" und
"UnicodeText" als vordefinierte Codes}
begin
if lstrcmpi(FormatName,ClipNames[Text])=0
then Result:=CF_Text
else if lstrcmpi(FormatName,ClipNames[Unicode])=0
then Result:=CF_UnicodeText
else Result:=RegisterClipboardFormat(FormatName);
end;
function GetInst:DWord; stdcall;
{ID-Spender fr die anderen Funktionen}
begin
GetInst:=idInst;
end;
procedure HandleDdeError(DdeError:UInt); stdcall;
{Bei DDE-Fehler Warnmeldung (kein Skript-Abbruch!);
DdeError darf auch 0 sein; dann wird DdeGetLastError herangezogen}
var
strcode: UInt;
sz1,sz2: array[0..255] of Char;
szBuf: array[0..1023] of Char;
begin
if DdeError=0 then begin
if verbose=0 then exit; {nie meckern}
DdeError:=DdeGetLastError(idInst);
if DdeError=0 then exit; {nichts zu meckern!}
if (DdeError=DMLERR_NotProcessed)
and (verbose<2) then exit;
{der h„ufigste Fehler wird sonst auf die Dauer l„stig}
end;
strcode:=DdeError;
if (strcode<DMLErr_First) or (strcode>DMLErr_Last)
then strcode:=$4012; {"unbek. Fehler"}
LoadString(HInstance,strcode,sz1,sizeof(sz1));
LoadString(HInstance,1,sz2,sizeof(sz2)); {"code %d, text %s"}
wsprintf2(szBuf,sz2,PChar(DdeError),sz1);
mexWarnMsgTxt(szBuf);
end;
function TestInputArgs(nrhs:LongInt; const prhs: TMatArr;
minIn,maxIn:LongInt; permitString,permitNumeric: DWord):Boolean; stdcall;
{Testet Rechte-Hand-Parameter auf Anzahl (Minimum und Maximum)
und auf Typ via zweier Bitmasken (so sind auch zwei Typen erlaubt)
Liefert immer TRUE, weil bei Fehler Skript-Abbruch}
var
strcode: UInt;
i: LongInt;
szBuffer,sz1: array[0..255] of Char;
begin
if (nrhs<minIn) or (nrhs>maxIn) then begin
strcode:=4; {"must be one arg"}
if minIn<>1 then strcode:=5; {"must be %d args"}
if minIn<>maxIn then strcode:=6; {"must be %d to %d args"}
LoadString(HInstance,strcode,sz1,sizeof(sz1));
wsprintf2(szBuffer,sz1,PChar(minIn),PChar(maxIn));
mexErrMsgTxt(szBuffer);
end;
strcode:=0;
for i:=0 to nrhs-1 do begin
if (permitString and (1 shl i) =0)
and mxIsChar(prhs[i]) then begin
strcode:=7; {"String fr %ites Arg nicht erlaubt!"}
break;
end;
if (permitNumeric and (1 shl i) =0)
and mxIsNumeric(prhs[i]) then begin
strcode:=8; {"Numerisch fr %ites Arg nicht erlaubt!"}
break;
end;
if not (mxGetClassID(prhs[i]) in [mxChar_Class,mxDouble_Class]) then begin
strcode:=9; {"Nur `traditionelle` Typen bitte!"}
break;
end;
end;
if strcode<>0 then begin
LoadString(HInstance,strcode,sz1,sizeof(sz1));
wsprintf1(szBuffer,sz1,PChar(i+1));
mexErrMsgTxt(szBuffer);
end;
TestInputArgs:=true;
end;
function ArrayToStringHandle(a:PArray):Hsz; stdcall;
{Umwandlung Matlab-String-Matrix in DDE-String-Handle}
var
psz: PChar;
begin
psz:=mxArrayToString(a);
ArrayToStringHandle:=DdeCreateStringHandle(idInst,psz,CP_WinAnsi);
mxFree(psz);
end;
type
PHSZ=^HSZ;
function ArrayToStringHandles(a:PArray;szp:PHSZ;szplen:Integer):Integer;
stdcall; {Umwandlung Matlab-String-Matrix in DDE-String-Handle-Array
(fr DDEADV und DDEUNADV)}
var
psz,s2,s3: PChar;
begin
psz:=mxArrayToString(a); s2:=psz; Result:=0;
while szplen>0 do begin
s3:=NextItem(s2,ESCAP_DblQuote or DELIM_NilWhenNone or DELIM_WhiteSpace);
if s3=nil then break; {Ende mit Allende}
szp^:=DdeCreateStringHandle(idInst,s3,CP_WinAnsi);
Inc(szp);
Inc(Result);
Dec(szplen);
end;
mxFree(psz);
end;
function FreeStringHandle(sz:HSZ):Boolean; stdcall;
{ein oder mehrere String-Handles freigeben und Referenzen nullsetzen}
begin
Result:=DdeFreeStringHandle(idInst,sz);
end;
function CheckClipFormat(a:PArray; var cf: UInt; ocp:PBool):EClip; stdcall;
{Testet auf CF_Text(=1) oder CF_XlTable oder CF_MatTable
und liefert 1, 2 oder 3; bei Fehler keine Rckkehr
Verarbeitet sowohl Zahlen als auch (neu) Konstanten-Strings
Bei Angabe des Parameters ocp wird auf Zwei-Element-Array getestet,
fr DDEREQ und DDEADV, und so der Rckgabe-Typ ermittelt}
var
indp: PDouble;
szTemp,szBuf: array[0..255] of Char;
begin
if mxIsChar(a) then begin
mxGetString(a,szTemp,sizeof(szTemp)); {String sollte kurz sein}
cf:=MyRegisterClipboardFormat(szTemp);
end else begin
cf:=Round(mxGetScalar(a));
end;
for Result:=LOW(EClip) to HIGH(EClip) do if cf=ClipForms[Result] then begin
if ocp<>nil then begin
if mxIsChar(a)
then ocp^:=(Result<=Unicode) {bei Text Textrckgabe, sonst bin„r}
else if (mxGetM(a)=1) and (mxGetN(a)>=2) then begin
indp:=mxGetPr(a);
Inc(indp);
ocp^:=(indp^=1);
end else ocp^:=false;
end;
exit;
end;
LoadString(HInstance,10,szTemp,sizeof(szTemp)); {"ungltiges CF"}
wsprintf1(szBuf,szTemp,PChar(cf));
mexErrMsgTxt(szBuf);
CheckClipFormat:=Text; {Compiler ruhigstellen}
end;
procedure PutErr(strcode:UInt); stdcall;
{einfache Fehlermeldung fr die anderen DLLs}
var
s: array[0..255] of Char;
begin
LoadString(HInstance,strcode,s,sizeof(s));
mexErrMsgTxt(s);
end;
procedure PutWarn(strcode:UInt); stdcall;
{einfache Warnung fr die anderen DLLs}
var
s: array[0..255] of Char;
begin
LoadString(HInstance,strcode,s,sizeof(s));
mexWarnMsgTxt(s);
end;
{***** ehemals in DDEPOKE *****}
{Weil nicht klar ist, ob DDEPOKE vor oder nach DDEREQ aufgerufen wird,
muss alles gemeinsam benutzte nun nach DDEINIT, was DEFINITIV zuerst
aufgerufen wird. Andernfalls kann Matlab die DLL nicht laden, weil
der Querbezug nicht gefunden wird.}
const
NumberLength=26; {L„nge eines DOUBLE in Zeichen, volle Pr„zision}
function Alloc_Datalen(format:EClip; x,y:LongInt; var datalen: UInt):PChar;
stdcall;
{Berechnet die ben”tigte Menge an Speicherplatz fr die angegebenen
Dimensionen und fordert ihn an. Nur fr max. zweidimensionales!
Liefert nie NIL; bricht ggf. mit mexErrMsgTxt() ab.
Speicher ist mit Nullen gefllt}
var
DataBlocks:LongInt;
begin
datalen:=x*y*sizeof(Double); {meistens - irgendwie}
case format of
Text: begin
datalen:=x*y*(NumberLength+1)+y+1; {Anzahl Zeichen, 0D0A fr Zeilen}
if y=1 then Dec(datalen,2); {einzeilige ohne 0D0A am Ende!}
end;
Unicode: begin
datalen:=(x*y+1)*sizeof(WChar); {hier Ausnahme: String-L„nge!}
end;
XlTable: begin
if (x>=65536) or (y>=65536) then PutErr(11);{zu groáe Matrixausdehnung}
datablocks:=(datalen+$7FFF) div $8000; {also 32-KB-Bl”cke}
Inc(datalen,8+datablocks*4);
end;
MatTable: Inc(datalen,4*sizeof(LongInt));
end;
Result:=PChar(LocalAlloc(LMEM_Fixed or LMEM_ZeroInit,datalen));
if Result=nil then PutErr(12); {Speicherbelegungsfehler}
end;
procedure str_skip_ws(var s:PChar);
{(anf„nglichen) Weiáraum bergehen}
begin
while s^ in [#9,#13,' '] do inc(s);
end;
procedure str_find_lt(var s:PChar; dp:PDouble);
{Listentrenner suchen, dabei nachfolgenden Weiáraum (auch 0Dh) bergehen;
liefert die Zahl (die im ersten Durchlauf verworfen wird)}
var
ec: LongInt;
memsp: PChar;
memchr: Char;
begin
str_skip_ws(s);
if dp<>nil then begin {will die Zahl haben!}
Val(s,dp^,ec);
if ec>1 then begin {bei EC=1 sollte Null herauskommen...}
{das w„re ein leeres Feld zwischen Kommata oder Semikola bzw. eine Leerzeile}
memsp:=s+ec-1;
memchr:=memsp^;
memsp^:=#0;
Val(s,dp^,ec);
memsp^:=memchr;
end;
end;
while not (s^ in [#0..' ',',',';']) do inc(s); {Zahl und Rest bergehen}
str_skip_ws(s); {bis zu ',',';'(Spaltentrenner),#10(Zeilentrenner)}
end;
procedure str_count_numbers(s:PChar; var x,y:LongInt); stdcall;
{Z„hlt Zeilen (y) und Spalten (x) der Text-Matrix ab, nimmt dabei
das Maximum, falls einige Zeilen nicht voll sind. Trennt Spalten
an Leerzeichen, Tabs und am Windows-Listentrenner? (Systemsteuerung).
Leerzeilen werden ignoriert. Wird auch von DDEREQ ben”tigt.
X wird mindestens 1, aber Y kann Null werden!}
var
xx: LongInt;
begin
x:=1; y:=1; xx:=0;
str_skip_ws(s);
while s^<>#0 do begin
while s^ in [#10,';'] do begin
Inc(s);
str_skip_ws(s); {Leerzeilen ignorieren}
if s^=#0 then begin
Dec(y); {wenn nur leere Zeilen, dann y=0!}
exit;
end;
end;
str_find_lt(s,nil);
Inc(xx); {Zahl (scheinbar) konvertiert}
case s^ of
',': Inc(s); {Komma wie Leerzeichen bergehen}
#10,';': begin
if x<xx then x:=xx; {x als Maximum setzen}
xx:=0;
Inc(y); {also zun„chst auf 2}
end;
end;
end;
if x<xx then x:=xx; {wenn letzte Zeile maágebend}
end;
procedure PrepareXlTable(var dp:PDouble; x,y: LongInt); stdcall;
{Fllt den bereits ausgenullten Speicher mit dem Header und den
Zwischen-Headern, setzt dp hinter den Haupt-Header}
var
lp: PLongInt; {ein PWord ist zwar logischer, aber uneffektiv}
begin
lp:=Pointer(dp); Inc(dp); {gleich um 8 erh”hen}
lp^:=$00040010; Inc(lp);
lp^:=MakeLong(y,x); Inc(lp);
x:=x*y; {Rollentausch, x=Doubles-gesamt, y=Doubles-Block}
while x>0 do begin {alle Zwischen-Header verteilen}
y:=x; if y>$1000 then y:=$1000;
Dec(x,y);
lp^:=y*sizeof(Double) shl 16 +1;
Inc(PChar(lp),4+y*sizeof(Double));
end;
end;
function SkipXlFloatHeader(var dp:PDouble):LongInt; stdcall;
{berspringt genau einen Zwischen-Header und liefert die Blockl„nge
in Doubles; hoffentlich ist die Blockl„nge durch 8 teilbar}
begin
if PWord(dp)^<>1 then PutErr(14); {Konsistenzfehler}
Inc(PWord(dp));
Result:=PWord(dp)^ div sizeof(Double);
Inc(PWord(dp));
end;
function aa(dp:PDouble; x,y,yges:LongInt; makexl:Bool):PDouble;
{berechne Array-Adresse (so umst„ndlich wegen des Strzens notwendig)}
begin
yges:=x*yges+y; {das soundsovielte Double}
x:=yges*sizeof(Double); {der Adress-Offset}
Result:=dp;
if makexl then repeat
Inc(x,4); {einen Header berspringen}
y:=SkipXlFloatHeader(dp);
Dec(yges,y); {diesen Block "erledigen"}
Inc(dp,y); {und zum n„chsten Zwischenheader}
until yges<0;
Inc(PChar(Result),x);
end;
procedure str_to_numbers(s:PChar; x,y:LongInt; dp:PDouble;
skipxl:Bool); stdcall;
{wandelt durchgez„hlten Text in Doubles um}
var
xx,yy: LongInt;
dp2: PDouble;
begin
str_skip_ws(s);
for yy:=0 to y-1 do begin
if s^=#0 then break;
while s^ in [#10,';'] do begin
Inc(s);
str_skip_ws(s); {Leerzeilen ignorieren}
if s^=#0 then exit; {eigentlich Fehler, oder?}
end;
for xx:=0 to x-1 do begin
dp2:=aa(dp,xx,yy,y,skipxl);
if s^ in [#0,#10,';'] then begin
dp2^:=0.0 {Zeilenrest mit Nullen fllen}
end else begin
str_find_lt(s,dp2);
if s^=',' then Inc(s);
end;
end;
end;
end;
procedure str_from_numbers(s:PChar; x,y:LongInt; dp:PDouble;
skipxl:Bool); stdcall;
{wandelt Doubles in Text um}
type
PStrBuffer=^TStrBuffer;
TStrBuffer=array[0..NumberLength] of Char;
var
xx,yy: LongInt;
begin
for yy:=0 to y-1 do begin
for xx:=0 to x-1 do begin
if xx<>0 then begin
s^:=' ';
Inc(s);
end;
Str(aa(dp,xx,yy,y,skipxl)^:NumberLength,PStrBuffer(s)^);
s:=s+lstrlen(s);
end;
if y<>1 then begin {hier: Einzelzeile ohne Newline!}
lstrcpy(s,#13#10);
Inc(s,2);
end;
end;
end;
{***** ehemals in DDEPOKE ***** END *****}
procedure mxGetStringW(a:PArray; sp:PWChar; buflen:LongInt); stdcall;
{Unicodes aus Matlab-Array herausziehen, buflen in BYTES}
var
n: LongInt; {Anzahl der Zeichen}
dp: PDouble;
begin
buflen:=buflen div 2;
n:=mxGetN(a); if n>buflen-1 then n:=buflen-1; {begrenzen}
dp:=mxGetPr(a);
while n>0 do begin
if (dp^<0) or (dp^>65535) then sp^:=WChar(65535)
else sp^:=WChar(Round(dp^));
Inc(dp);
Inc(sp);
end;
end;
function mxCreateStringW(sp:PWChar):PArray; stdcall;
{Unicodes in neues Matlab-Array einsetzen}
var
mn: array[0..1] of LongInt;
dp: PDouble;
begin
mn[0]:=1;
mn[1]:=lstrlenW(sp); {wird ja auch von Win9x untersttzt}
Result:=mxCreateCharArray(2,@mn);
dp:=mxGetPr(Result);
while mn[1]>0 do begin
dp^:=LongInt(sp^); {mit Daten fllen}
Inc(dp);
Inc(sp);
end;
end;
{***** ehemals in DDEREQ *****}
procedure CopyXlFloat(indata,dp: PDouble; x,y:LongInt);
{XlTable-Doubles in durchgehende Doubles umwandeln}
begin
x:=x*y; {Rollentausch: x=gesamt, y=Block}
while x>0 do begin
y:=SkipXlFloatHeader(indata);
CopyMemory(dp,indata,y*sizeof(Double));
Inc(dp,y); Inc(indata,y); Dec(x,y);
end;
end;
procedure ReadXlTableHeader(var indata:PDouble; var x,y: LongInt);
{rckt indata vor und liest x und y ein}
var
wp: PWord;
begin
wp:=Pointer(indata); Inc(indata); {gleich um 8 vorrcken}
if PLongInt(wp)^<>$00040010 then PutErr(14); {inkonsistent}
Inc(wp,2);
y:=wp^; Inc(wp);
x:=wp^; Inc(wp);
if (x<>0) and (y<>0) and (wp^<>1) then PutErr(14);
{falls berhaupt Daten vorhanden sind, mssen sie Double sein}
end;
function DdeDataToArray(hindata:HDdeData; format:EClip; outchar: Bool):
PArray; stdcall;
{gemeinsame Routine fr DDEREQ und XTYP_AdvData-Callback,
wandelt DDE-Daten aus Handle in Matlab-Array um}
var
insp: PChar;
inlp: PLongInt absolute insp;
indp: PDouble absolute insp;
datalen: UInt;
outdata: PChar; {data kann, muss aber kein String sein!}
x,y: LongInt; {Matrix-Ausdehnung}
begin
Result:=nil;
insp:=DdeAccessData(hindata,nil);
if outchar then begin
case format of
Text: Result:=mxCreateString(insp);
Unicode: Result:=mxCreateStringW(PWChar(insp));
XlTable: begin
ReadXlTableHeader(indp,x,y);
outdata:=Alloc_Datalen(Text,x,y,datalen);
str_from_numbers(outdata,x,y,indp,true);
Result:=mxCreateString(outdata);
LocalFree(Integer(outdata));
PutWarn(18); {Schwachsinn-Meldung}
end;
MatTable: begin
if inlp^<>6 then PutErr(14); Inc(inlp); {muss DOUBLE sein}
x:=inlp^; Inc(inlp);
if x>2 then PutErr(13); {max. zweidimensional}
y:=1;
if x>=1 then begin
y:=inlp^; Inc(inlp);
end;
if x=2 then begin
x:=inlp^; Inc(inlp);
end else x:=1; {etwas nulldimensionales ist 1x1-Matrix = Skalar}
outdata:=Alloc_Datalen(Text,x,y,datalen);
str_from_numbers(outdata,x,y,indp,false);
Result:=mxCreateString(outdata);
LocalFree(Integer(outdata));
PutWarn(18); {Schwachsinn-Meldung}
end;
end;
end else begin
case format of
Text: begin
str_count_numbers(insp,x,y);
Result:=mxCreateDoubleMatrix(y,x,mxReal);
str_to_numbers(insp,x,y,mxGetPr(Result),false); {alles umwandeln!}
end;
Unicode: PutErr(17); {Kann nicht / will nicht}
XlTable: begin
ReadXlTableHeader(indp,x,y);
Result:=mxCreateDoubleMatrix(y,x,mxReal);
CopyXlFloat(indp,mxGetPr(Result),x,y);
end;
MatTable: begin
if inlp^<>6 then PutErr(14); Inc(inlp); {muss DOUBLE sein}
x:=inlp^; Inc(inlp);
Result:=mxCreateNumericArray(x,inlp,mxDouble_Class,mxReal);
Inc(inlp,x);
y:=mxGetNumberOfElements(Result); {sollte Dimensionsprodukt sein}
CopyMemory(mxGetPr(Result),indp,y*sizeof(Double));
end;
end;
end;
DdeUnaccessData(hindata);
end;
{***** ehemals in DDEREQ ***** END *****}
{***** ehemals in DDEADV *****}
type
PPAdvInfo=^PAdvInfo;
PAdvInfo=^TAdvInfo;
TAdvInfo=record {Advise-Information}
next: PAdvInfo; {fr verkettete Liste}
conv: HConv; {diese 3 Parameter...}
item: Hsz; {...identifizieren...}
cf: UInt; {...den richtigen Link}
format: EClip; {fr uns zum Daten konvertieren}
outchar: Bool; {numerischer oder String-Output?}
arrayname: array[0..mxMAXNAM-1] of Char; {keine Unicodes m”glich}
evalstring: array[0..0] of Char; {dynamisch, keine Unicodes}
end;
const
AdvList: PAdvInfo=nil; {Zeiger auf verkettete Liste}
function FindNextInfo(cur,prev:PPAdvInfo; conv:HConv; item:Hsz; cf:UInt)
:Boolean;
{"cur^" zeigt auf vorhergehenden Knoten, weder cur noch cur^ darf NIL sein;
"prev" wird ja bekanntlich zum L”schen gebraucht, darf NIL sein.
Bei Rckgabe von FALSE ist cur^ unver„ndert}
var
ap: PAdvInfo; {"krzerer" Zugang}
begin
Result:=false;
ap:=cur^;
repeat
if prev<>nil then prev^:=ap;
ap:=ap^.next;
if ap=nil then break;
if ((conv=0) or (ap^.conv=conv))
and ((item=0) or (ap^.item=item))
and ((cf=0) or (ap^.cf=cf))
then begin
cur^:=ap;
Result:=true;
exit;
end;
until false;
end;
procedure DdeAdvise(conv:HConv; szItem:Hsz; uFmt:UInt; data:hDdeData);
{CALLBACK, gefiltert aus der DDE-Callback-Routine}
var
ap: PAdvInfo;
a: PArray;
begin
ap:=@AdvList;
while FindNextInfo(@ap,nil,conv,szItem,uFmt) do begin
if data<>0 then begin {HotLink}
a:=DdeDataToArray(data,ap^.format,ap^.outchar);
mxSetName(a,ap^.arrayname);
if mexPutArray(a,'caller')<>mxOK then PutWarn(19); {Kann nicht updaten}
mxDestroyArray(a);
end;
if (ap^.evalstring[0]<>#0)
and (mexEvalString(ap^.evalstring)<>mxOK)
then PutWarn(18); {Fehler bei Callback-String}
end;
end;
procedure advDeleteInfo(conv:HConv; item:Hsz; cf:UInt); stdcall;
{L”scht die Daten aus der einfach verketteten Liste;
der Aufruf mit allen drei Parametern =0 l”scht alles.
Die zugeh”rigen String-Handles werden freigegeben.
Falls "multithreadend", msste das Zeug in einen kritischen Abschnitt}
var
ap,avp: PAdvInfo;
begin
ap:=@AdvList;
while FindNextInfo(@ap,@avp,conv,item,cf) do begin
FreeStringHandle(ap^.item);
avp^.next:=ap^.next; {ap aus Liste aush„ngen}
LocalFree(Integer(ap)); {ap freigeben}
ap:=avp; {weitermachen vom vorhergehenden aus}
end;
end;
procedure advNewInfo(conv:HConv; item:Hsz; cf:UInt; format:EClip; outchar:Bool;
arrayname,evalstring: PChar); stdcall;
{Neuanlage eines Listenelements; evtl. vorher vorhandenes entfernen.
Parameter-Reihenfolge und stdcall erm”glicht Speicher-Kopie}
var
ap: PAdvInfo;
el: UInt;
begin
advDeleteInfo(conv,item,cf);
el:=0; if evalstring<>nil then el:=lstrlen(evalstring);
ap:=PAdvInfo(LocalAlloc(LMEM_Fixed or LMEM_ZeroInit,sizeof(TAdvInfo)+el));
if ap=nil then PutErr(12); {Speicher-Panik!}
ap^.next:=AdvList;
AdvList:=ap; {einfach vorn einh„ngen}
CopyMemory(@(ap^.conv),@conv,4*5); {der langweilige Krempel}
if arrayname<>nil then lstrcpyn(ap^.arrayname,arrayname,mxMAXNAM);
if evalstring<>nil then lstrcpy(ap^.evalstring,evalstring);
end;
{***** ehemals in DDEADV ***** END *****}
procedure DisconnectMsgBox(Conv:HConv);
{Wenn ein DDE-Server bei aktiver Verbindung verreckt, hiermit anzeigen}
var
ci: TConvInfo;
szSvcPartner, szTopic, sz1: array[0..255] of Char;
szBuffer: array[0..1023] of Char;
begin
ci.cb:=sizeof(TConvInfo);
DdeQueryConvInfo(Conv,QID_Sync,@ci);
DdeQueryString(idInst,ci.hszSvcPartner,szSvcPartner,sizeof(szSvcPartner),
CP_WinAnsi);
DdeQueryString(idInst,ci.hszTopic,szTopic,sizeof(szTopic),CP_WinAnsi);
LoadString(HInstance,2,sz1,sizeof(sz1)); {"...Server %s Toppic %s"}
wsprintf2(szBuffer,sz1,szSvcPartner,szTopic);
LoadString(HInstance,3,sz1,sizeof(sz1)); {"MATLAB DDE Toolbox"}
MessageBox(0,szBuffer,sz1,MB_ApplModal or MB_IconInformation or MB_OK);
end;
function DdeCallback(uType,uFmt:UInt; Conv:hConv;
hsz1,hsz2:Hsz; data: hDdeData; dwData1,dwData2: DWord):HDdeData; stdcall;
{dieser Windows-Rckruf ist eher DDE-Server-typisch; hier filtert er nur
AdvData (fr Aktualisierung) und Disconnect (fr obige MsgBox)}
begin
DdeCallback:=0; {blicher Rckgabewert}
case uType of
XTYP_Disconnect: begin
if conv<>0 then advDeleteInfo(Conv,0,0);
DisconnectMsgBox(Conv);
end;
XTYP_AdvData: begin
DdeAdvise(Conv,hsz2,uFmt,data);
DdeCallback:=DDE_fAck; {hier Rckgabewert}
end;
end;
end;
procedure MyExit; cdecl;
{Aufr„um-Aktion beim Beenden von Matlab bzw. bei "clear mex|all|ddeinit"}
begin
if (idInst<>0) and DdeUninitialize(idInst) then begin
idInst:=0;
advDeleteInfo(0,0,0); {alle Advises komplett abputzen}
end;
end;
function RegisterDDECallback:Boolean;
const
CBF_Skips=CBF_Skip_Connect_Confirms
or CBF_Skip_Registrations or CBF_Skip_Unregistrations;
var
InitResult: UInt;
i: EClip;
begin
RegisterDdeCallback:=true;
if idInst=0 then begin {beim 1. Aufruf von DDEINIT}
for i:=LOW(EClip) to HIGH(EClip)
do ClipForms[i]:=MyRegisterClipboardFormat(ClipNames[i]);
InitResult:=DdeInitialize(idInst,DDECallback,
APPCLASS_Standard or APPCMD_ClientOnly or CBF_Skips,0);
if InitResult=DMLERR_No_Error then begin
mexAtExit(@MyExit);
end else begin
HandleDdeError(InitResult);
RegisterDdeCallback:=false;
end;
end;
end;
procedure mexFunction(nlhs:LongInt; var plhs:TMatArr;
nrhs:LongInt; const prhs:TMatArr); stdcall;
var
hszService,hszTopic:Hsz;
conv:HConv;
begin
if nlhs=0 then PutErr(16); {will Ausgabe-Variable!}
TestInputArgs(nrhs,prhs,2,2,3,0);
if RegisterDDECallback then begin
hszService:=ArrayToStringHandle(prhs[0]);
hszTopic:=ArrayToStringHandle(prhs[1]);
conv:=DdeConnect(idInst,hszService,hszTopic,nil);
FreeStringHandle(hszService); {Windows sollte Nullen...}
FreeStringHandle(hszTopic); {schlucken ohne zu brechen}
if conv=0 then HandleDdeError(0);
plhs[0]:=mxCreateDoubleMatrix(1,1,mxReal);
mxGetPr(plhs[0])^:=conv;
{Zwar w„re es richtig, hierfr mxUInt32_Class zu bemhen,
damit keiner auf die Idee kommt, mit der Kanalnummer zu rechnen,
aber dann hat man Schwierigkeiten, wenn man diese Variable irgendwo hin
(z.B. in ein Array) steckt.}
end;
end;
exports
mexFunction,
GetInst index 11,
HandleDdeError index 12,
TestInputArgs index 13,
ArrayToStringHandle index 14,
CheckClipFormat index 15,
PutErr index 16,
PutWarn index 17,
MyRegisterClipboardFormat index 18,
ArrayToStringHandles index 19,
FreeStringHandle index 20,
Alloc_Datalen index 21,
str_count_numbers index 22,
str_to_numbers index 23,
str_from_numbers index 24,
PrepareXlTable index 25,
SkipXlFloatHeader index 26,
DdeDataToArray index 27,
mxGetStringW index 31,
mxCreateStringW index 32,
advNewInfo index 41,
advDeleteInfo index 42;
begin {"Geheimer" Schalter}
DisableThreadLibraryCalls(HInstance);
verbose:=GetPrivateProfileInt('DDE','verbose',1,'MATLAB.INI');
end.
Detected encoding: UTF-8 | 0
|