Source file: /~heha/messtech/calldll.zip/16BIT/calldll.pas

library calldll; {$N+,E-} {MATLAB setzt ohnehin Koprozessor voraus}
{$D Matlab-MEX: Universal-DLL-Aufrufschnittstelle (h#s 12/99)}

uses pasmex,winprocs,wintypes,win31,wutils;

var
 CatchBuf: TCatchBuf;
 hDllLast: THandle;
 ParseStr: array[0..1023] of Char;
 ProcEntry: TFarProc;
 cdecl: Boolean;

procedure Error(s: PChar);
 begin
  mexVPrintf('CALLDLL.DLL: FEHLER: %s'#10,s,4);
  Throw(CatchBuf,-1);
 end;

procedure Warning(s: PChar);
 begin
  mexVPrintf('CALLDLL.DLL: WARNUNG: %s'#10,s,4);
 end;

const
 ARG_I08	=$81;
 ARG_I16	=$82;	{Standard für mxIsNumeric}
 ARG_I32	=$84;
 ARG_U08	=$01;
 ARG_U16	=$02;
 ARG_U32	=$04;
 ARG_F32	=$C4;
 ARG_F64	=$C8;
 ARG_C08	=$01;	{Standard für mxIsString}
 ARG_Str	=$00;
 ARG_Ptr	=$20;	{falls m*n<>1}
 ARG_Ret	=$10;
{Bit
 7=vzb/vzl
 6=Gleitkomma/Ganzzahl
 5=Pointer auf Datentyp (Indirektion, immer FAR)
 4=Parameter-Rückgabe (schließt Bit 5 ein)
 3..0=Zahl der Bytes pro Element}
var
 argt: array[0..17] of Byte;
{Index 0: Funktionsergebnis, 1..17: Argumente}
 allocs: array[0..17] of THandle;
 sizes: array[0..17] of LongInt;
type
 TType=record
  t: Byte;
  c: Char;
  s: array[0..3] of Char;
 end;

const
 CType: array[0..8] of TType=(
  (t: ARG_I08; c: 'h'; s: 'i08'),
  (t: ARG_I16; c: 'i'; s: 'i16'),
  (t: ARG_I32; c: 'l'; s: 'i32'),
  (t: ARG_U08; c: 'c'; s: 'u08'),
  (t: ARG_U16; c: 'u'; s: 'u16'),
  (t: ARG_U32; c: 'w'; s: 'u32'),
  (t: ARG_F32; c: 'f'; s: 'f32'),
  (t: ARG_F64; c: 'g'; s: 'f64'),
  (t: ARG_Str; c: 's'; s: 'str'));	{nullterminierter String}

function mxGetMxN(pm: PMatrix):LongInt;
 begin
  mxGetMxN:=mxGetM(pm)*mxGetN(pm);
 end;

procedure ParseArg(Arg:PChar; ArgNum: Integer);
{Einen einzelnen Argument-Prototypen erfassen}
(* Syntaxdiagramm: {*}spec{[{arraysize}]} *)
 var
  sp,sp2: PChar;
  i,e: Integer;
  b: Byte;
 begin
  while Arg^=' ' do Inc(Arg);		{TrimLeft}
  if Arg^='*' then begin
   Inc(Arg);
   asm	mov	si,[ArgNum]
	or	byte ptr argt[si],ARG_Ptr	{Indirektion}
   end;
  end;
  sp:=lstrchr(Arg,'[');
  if sp<>nil then begin
   sp^:=#0;
   inc(sp);
   asm	mov	si,[ArgNum]
	or	byte ptr argt[si],(ARG_Ptr or ARG_Ret)	{Indirektion und Ret}
   end;
   sp2:=lstrchr(sp,']');
   if sp2=nil then Error('Prototyp-[]');
   sp2^:=#0;
   if sp2<>sp then begin		{sonst Länge von Matrix nehmen}
    Val(sp,sizes[ArgNum],e);
    if e<>0 then Error('Prototyp-Arraygr÷▀e');
   end;
  end;
  for i:=0 to 8 do with CType[i] do begin
   if (Arg[0]=c) and (Arg[1]=#0)
   or (lstrcmpi(Arg,s)=0) then begin
    b:=t;
    asm	mov	si,[ArgNum]
	and	byte ptr argt[si],ARG_Ptr or ARG_Ret
	mov	al,[b]
	or	byte ptr argt[si],al
    end;
    exit;
   end;
  end;
  Error('Prototyp-Typ');
 end;

procedure ParseString;
 var
  hDLL: THandle;
  sp,sp2: PChar;
  wordval: Word;
  arg,e: Integer;
  savebuf: array[0..4] of Char;
  OldEM: Word;
 begin
  sp:=lStrChr(ParseStr,':');
  if sp=ParseStr+1
  then sp:=lStrChr(ParseStr+2,':');	{<Laufwerk:> übergehend}

  if sp<>nil then begin		{Versuch, die DLL zu laden}
   OldEM:=SetErrorMode(SEM_NoOpenFileErrorBox);
   sp^:=#0;
   hDLL:=LoadLibrary(ParseStr);
   if hDLL<32 then begin
    Move(sp^,savebuf,5);	{ausstanzen}
    lstrcpy(sp,'.DLL');		{heranflicken}
    hDLL:=LoadLibrary(ParseStr);
    Move(savebuf,sp^,5);	{zurücksetzen}
   end;
   SetErrorMode(OldEM);
   if hDLL>=32 then begin
    FreeLibrary(hDllLast);
    hDllLast:=hDLL;
   end else Error('Kann DLL nicht finden/laden');
   inc(sp);
  end else sp:=ParseStr;
  sp2:=lstrchr(sp,' ');
  if sp2<>nil then sp2^:=#0;
  cdecl:=false;
  Val(sp,wordval,e);		{numerischer Einsprung?}
  if e=0 then sp:=MakeIntResource(wordval)
  else if sp^='_' then cdecl:=true;
  ProcEntry:=GetProcAddress(hDllLast,sp);
  if ProcEntry=nil then Error('Kann Einsprungpunkt nicht finden');
  arg:=1;
  while sp2<>nil do begin
   sp:=sp2+1;
   if sp^=#0 then break;	{Nichts mehr zu parsen}
   sp2:=lstrchr(sp,'=');
   if sp2<>nil then arg:=0	{Retval-Argument}
   else sp2:=lstrchr(sp,',');
   if sp2<>nil then sp2^:=#0;
   ParseArg(sp,arg);
   Inc(arg);
  end;
 end;

procedure ShowProto(hirhs:Integer);
 var
  sp: PChar;
  carg: Byte;
  c: Char;
  i,j: Integer;
  s: array[0..255] of Char;
 begin
  sp:=s;
  for i:=0 to hirhs do begin
   carg:=argt[i] and not (ARG_Ptr or ARG_Ret);
   for j:=0 to 8 do if carg=CType[j].t then break;
   lstrcpy(sp,CType[j].s); Inc(sp,3);
   if argt[i] and ARG_Ptr <>0
   then Inc(sp,wvsprintf(sp,'[%ld]',sizes[i]));
   if argt[i] and ARG_Ret <>0
   then begin sp^:='r'; inc(sp); end;
   c:=',';
   if i=hirhs then c:=#0;
   if i=0 then c:='=';
   sp^:=c; inc(sp);
  end;
  sp^:=#0;
  sp:=s;
  mexVPrintf('%s'#10,sp,4);
 end;

type
 PAnyNum=^TAnyNum;
 TAnyNum=record
 case integer of
  1: (x: double);
  2: (s: single);
  3: (l: LongInt);
  4: (w: Word);
  5: (i: Integer);
  6: (c: Char);
  7: (b: Byte);
  8: (h: ShortInt);
 end;

function CallEntry(hirhs:Integer; var prhs:TMatArr):Double;
 const
  StackFehler: array[0..11] of Char='Stackfehler';
 var
  i: integer;
  xx: TAnyNum;
  xp,xp2: PAnyNum;
  rp: HPDouble;
  l: LongInt;
  carg: Byte;
  cmat: PMatrix;
  csiz: LongInt;
  s: array[0..15] of Char;
  savestack,teststack: Word;
 begin
  asm mov [savestack],sp; mov [teststack],sp end;
  for i:=1 to hirhs do begin
   carg:=argt[i];
   cmat:=prhs[i];
   csiz:=sizes[i];
   if carg and Arg_Ptr <>0 then begin
    asm and carg,not (ARG_Ptr or ARG_Ret) end;
    if carg=ARG_Str then begin
     xp:=Ptr(GlobalAlloc(GMEM_Fixed,csiz+1),0);
     if PtrRec(xp).sel=0 then Error('Speicherfehler');
     allocs[i]:=PtrRec(xp).sel;
     mxGetString(cmat,PChar(xp),csiz+1);
    end else if (carg=ARG_F64)
    and (mxGetMxN(cmat)=csiz)
    then HPDouble(xp):=mxGetPr(cmat)	{nicht ganzes Array kopieren}
    else begin
     xp:=Ptr(GlobalAlloc(GMEM_Fixed,csiz*(carg and $0F)),0);
     if PtrRec(xp).sel=0 then Error('Speicherfehler');
     allocs[i]:=PtrRec(xp).sel;
     rp:=mxGetPr(cmat);
     l:=mxGetMxN(cmat);
     asm db $66; mov ax,word ptr [xp];
	 db $66; mov word ptr [xp2],ax;
	 db $66; mov ax,word ptr [csiz];
	 db $66; cmp ax,word ptr [l]
	 jnc	@@1
	 db $66; mov word ptr [l],ax;	{Minimum zu l}
@@1:
     end;
     repeat			{compiliert besser als FOR}
      with xp2^ do case carg of
       ARG_I08: h:=Round(rp^);
       ARG_I16: i:=Round(rp^);
       ARG_I32,
       ARG_U32: l:=Round(rp^);
       ARG_U16: w:=Round(rp^);
       ARG_U08: b:=Round(rp^);
       ARG_F32: s:=rp^;
       ARG_F64: x:=rp^;
      end;
      IncHP(PChar(rp),8);
      IncHP(PChar(xp2),carg and $0F);
      asm db $66; dec word ptr[l] end;
     until l=0;
    end{case};
    asm	db $66; push word ptr [xp] end;
   end else begin
    xx.x:=mxGetScalar(cmat);
    case carg of
     ARG_F64: ;
     ARG_F32: xx.s:=xx.x;
     else     xx.l:=Round(xx.x);{Integrale Typen in INTEL-Notation: reicht!}
    end;
    asm	mov	al,[carg]
	and	al,0Fh
	cmp	al,8		{DOUBLEs?}
	jc	@@1
	db $66; push word ptr [xx+4]
@@1:	cmp	al,4		{LONGINTs?}
	jc	@@2
	push	word ptr [xx+2]
@@2:	push	word ptr [xx+0]
    end;
   end{if};
  end{for};
  asm	cmp	[cdecl],FALSE
	jz	@@pas
	mov	[teststack],sp	{bei cdecl ist dies die Stack-Rückgabepos.}
@@pas:	call	[ProcEntry]	{Aufruf!}
	mov	[xx.i],ax
	mov	word ptr xx[2],dx	{LongInt-Rückgabe retten}
	cmp	[teststack],sp	{steht richtig?}
	je	@@1
	push	ds
	push	offset stackfehler
	call	Warning		{ob dieser ST(0) in Ruhe läßt?}
@@1:	mov	sp,[savestack]
	mov	al,byte ptr argt
	cmp	al,ARG_F64
	jz	@@sto
	cmp	al,ARG_F32
	jz	@@sto
	cmp	al,ARG_I16
	jz	@@i16
	cmp	al,ARG_I32
	jz	@@i32
	cmp	al,ARG_U32
	jz	@@i32
	cmp	al,ARG_U16
	jz	@@u16
	cmp	al,ARG_U08
	jz	@@u08
	cmp	al,ARG_I08
	jz	@@i08
	jmp	@@e
@@i08:	mov	al,[xx.h]
	cbw
	mov	[xx.i],ax
	jmp	@@i16
@@u08:	mov	byte ptr xx[1],0
@@i16:	fild	[xx.i]
	jmp	@@sto
@@u16:	mov	word ptr xx[2],0
@@i32:	fild	[xx.l]
	jmp	@@sto
@@sto:	fwait
	fstp	[@result]
	fwait
@@e:
  end;
  for i:=1 to hirhs do begin
   carg:=argt[i];
   cmat:=prhs[i];
   csiz:=sizes[i];
   if carg and ARG_Ret <>0 then begin
    asm and carg,not (ARG_Ptr or ARG_Ret) end;
    if carg=ARG_Str then begin
     Warning('String-Rⁿckgabe fⁿhrt zu InstabilitΣt in Matlab');
     mxFreeMatrix(cmat);
     cmat:=mxCreateString(Ptr(allocs[i],0));	{Ende an terminierender Null}
{     MessageBox(hwndMatlabCmd,Ptr(allocs[i],0),'Hier vorbei',0);}
{MATLAB scheint Schwierigkeiten zu haben, Return-Werte auf der rechten
 Seite (als quasi VAR-Parameter) zu liefern!}
     prhs[i]:=cmat;
    end else begin
     if mxGetMxN(cmat)<>csiz then begin
      Warning('Die rechtsseitige Ergebnismatrix sollte gleich gro▀ sein!'#10+
	'Matlab wird instabil');
      mxFreeMatrix(cmat);
      cmat:=mxCreateFull(1,csiz,false);
      prhs[i]:=cmat;		{ob sie jemals da ankommt? Manchmal!}
     end else if carg=ARG_F64 then continue;	{nächstes I}
     rp:=mxGetPr(cmat);
     xp:=Ptr(allocs[i],0);
     asm db $66; mov ax,word ptr [csiz];
	 db $66; mov word ptr [l],ax;
     end;
     repeat			{compiliert besser als FOR}
      with xp^ do case carg of
       ARG_I08: xx.x:=h;
       ARG_I16: xx.x:=i;
       ARG_I32,
       ARG_U32: xx.x:=l;
       ARG_U16: xx.x:=w;
       ARG_U08: xx.x:=b;
       ARG_F32: xx.x:=s;
       ARG_F64: xx.x:=x;
      end;
      rp^:=xx.x;
{$IFOPT D+}
      str(rp^:3:3,s);
      lstrcat(s,#10);
      mexVPrintf(s,s,0);
{$ENDIF}
      IncHP(PChar(rp),8);
      IncHP(PChar(xp),carg and $0F);
      asm db $66; dec word ptr[l] end;
     until l=0;
    end;
   end{if};
  end{for};
 end;

function R2I(pm: PMatrix; min,max: Integer; var r: array of Integer):Boolean;
 var
  zp: HPDouble;
  i,e: Integer;
 begin
  R2I:=false;
  if not mxIsNumeric(pm) then exit;
  zp:=mxGetPr(pm);
  e:=wutils.min(HIGH(r),mxGetM(pm));
  for i:=0 to e do begin
   if (zp^<min) or (zp^>max) then exit;
   r[i]:=Round(zp^);
   Inc(zp);
  end;
  R2I:=true;
 end;

procedure mexFunction(nlhs:Integer; var plhs:TMatArr;
  nrhs:Integer; var prhs:TMatArr); export;
 var
  i: Integer;
  t: Byte;
  pm: ^PMatrix;
  x: Double;
{ intp: PInteger;
  s: array[0..255] of Char;}
 begin
  FillChar(allocs,sizeof(allocs),0);
  if Catch(CatchBuf)=0 then begin
   if nrhs>=1 then begin
    FillChar(argt,sizeof(argt),0);
    mxGetString(prhs[0],ParseStr,sizeof(ParseStr)-1);
    if nlhs<>0 then argt[0]:=ARG_I16;
    pm:=@prhs[0];
    for i:=1 to nrhs-1 do begin
     Inc(pm);
     if mxIsString(pm^) then t:=ARG_Str or ARG_Ptr
     else t:=ARG_I16;
     sizes[i]:=mxGetMxN(pm^);
     if sizes[i]>1 then asm or t,ARG_Ptr end;
     argt[i]:=t;
    end;
    ParseString;
{$IFOPT D+}
    ShowProto(nrhs-1);
{$ENDIF}
    x:=CallEntry(nrhs-1,prhs);
    if argt[0]<>0 then begin
     plhs[0]:=mxCreateFull(1,1,false);
     mxGetPr(plhs[0])^:=x;
    end;

   end else mexVPrintf(
     '1 und mehr Parameter:'#10+
     '1. ''[DLL-Name:]Eintrittspunkt[ Prototyp]'' (wird DLL-Name weggelassen, dann letztgenutzte)'#10+
     '   Funktionsprototyp ''i=i,u32,f,s,i16,i32'' i=int, u=unsigned, f=float, s=asciiz'#10+
     '2.. Parameter'#10+
     'Mehr Info: help calldll',i,0);
  end;
  for i:=0 to 17 do if allocs[i]<>0 then GlobalFree(allocs[i]);
 end;

exports
 set_entry_point index 2,
 mexFunction 	 index 3,
 mexAtExitFcn	 index 4;

var
 OldExitProc: Pointer;
procedure NewExitProc; far;
 begin
  ExitProc:=OldExitProc;
  FreeLibrary(hDllLast);
 end;

begin
 OldExitProc:=ExitProc;
 ExitProc:=@NewExitProc;
 hDllLast:=LoadLibrary('USER');
end.
Detected encoding: OEM (CP437)1
Wrong umlauts? - Assume file is ANSI (CP1252) encoded