Page 1 of 1

D4D Lyr_Set not working

PostPosted: Sat Oct 06, 2018 1:01 am
by dhs
Hi,
The Delphi version of the Lyr_Set procedure does not appear to work.
I have written a simple test macro which simply attempts to create a new layer and then set it as the active layer. The new layer is created ok, but it is not set as the active layer. Code of this test macro is below:
Code: Select alllibrary LyrTest;

{$E dmx}  // dmx is the extension for DCAL Dll's
{$R *.res}

uses
  UConstants in 'C:\DataCAD 20\DCAL for Delphi\Header Files\UConstants.pas',
  UInterfaces in 'C:\DataCAD 20\DCAL for Delphi\Header Files\UInterfaces.pas',
  UInterfacesRecords in 'C:\DataCAD 20\DCAL for Delphi\Header Files\UInterfacesRecords.pas',
  URecords in 'C:\DataCAD 20\DCAL for Delphi\Header Files\URecords.pas',
  UVariables in 'C:\DataCAD 20\DCAL for Delphi\Header Files\UVariables.pas';

type
  LyrTestL = record
    state: asint;
    LyrName : str255;
    case byte of
      0: (gete: getescarg);
      1: (gets: DgetstrArg);
    end;

  PLyrTestL = ^LyrTestL;

function LyrTest_world_main(act: action; pl, pargs: Pointer): wantType;
var
  retval: asint;
  l: PLyrTestL;
  addr : lyraddr;
begin
  l := PLyrTestL(pl);

  if act = aagain then begin
    case l^.state of
      1: case l^.gete.key of
            f1: l^.state := 2;
            s0: l^.state := 0;
         end;
      2: begin
           wrtmsg('');
           if  l^.gets.Result = res_normal then begin
              lyr_create (l^.LyrName, addr);
              lyr_set (addr);
           end;
           l^.state := 1;
         end;
      else l^.state := 0;
    end;
  end;

  if act = Afirst then
    l^.state := 1
  else if act = AlSize then
    SetLocalSize(sizeof(l^));

  if act <> AlSize then begin
    case l^.state of
      1: begin
          wrtlvl('LyrTest');
          lblsinit;
          lblset(1, 'New Layer', 'Create new layer and set it as active');
          lblset(20, 'Exit');
          lblson;
          getesc(l^.gete, retval);
        end;
      2: begin
          lblsinit;
          lblson;
          wrtmsg('Layer Name: ', true);
          callDGetstr255(l^.LyrName, 70, l^.gets, retval);
        end;
      else retval := XDone;
    end;
  end;
  Result := retval;
end;

function Main(dcalstate: asint; act: action; pl, pargs: Pointer): wantType; stdcall;
begin
  case dcalstate of
    XDcalStateBegin: Result := LyrTest_world_main(act, pl, pargs);
  else Result := XDone;
  end;
end;

exports
  Main;

begin

end.

I don't think I am doing anything wrong? Can anybody offer advice on the use of Lyr_Set in D4D ?

Re: D4D Lyr_Set not working

PostPosted: Thu Feb 07, 2019 2:08 pm
by Mark F. Madura
Tracing through the debugger in DataCAD, the procedure lyr_set makes a call to valid_addr which returns false and the subsequent call to lyr_setcurr never gets called.

Re: D4D Lyr_Set not working

PostPosted: Thu Feb 07, 2019 3:33 pm
by Mark F. Madura
I'm still digging into this a bit. It looks like you'll have to declare a layer record to store the layer address.

rlyr: Rlayer

Once the address for the layer you want is stored in the record, you can call...

lyr_set(rlyr.addr)

Re: D4D Lyr_Set not working

PostPosted: Thu Feb 07, 2019 3:38 pm
by Mark F. Madura
The DCAL for Delphi sample LyrRename uses the Rlayer variable.

Re: D4D Lyr_Set not working

PostPosted: Thu Feb 07, 2019 9:28 pm
by dhs
Thanks Mark,

Given the lack of any response to my post 4 months ago I assumed I was correct in thinking Lyr_Set did not work. Following your posts I have had another look at it and discovered that the problem is actually with Lyr_Create.
I had assumed that Lyr_Create returned the address of the created layer in the var addr parameter. I still think that is probably the intention, but it appears that it does not return a valid address.

I have used Rlayer in the past, but didn't quite follow your logic to store the layer address in an Rlayer variable. I tried adding a lyr_get call to put the address in the Rlayer parameter, but that resulted in a drawing crash (fault 19 Error from: 73). See the commented lines in the code fragment below for that logic.

Next I tried retrieving the new layer by name using lyr_find, and passing the address returned by lyr_find to lyr_set. That did in fact work. The updated code fragment (from the code in my first post) is shown below:

Code: Select all      2: begin
           wrtmsg('');
           if  l^.gets.Result = res_normal then begin
              lyr_create (l^.LyrName, addr);

              {following code results in fault 19 Error from: 73 }
              //if lyr_get(addr, rlyr) then
                //lyr_set (rlyr.addr);

              {following code works}
              if lyr_find (l^.LyrName, addr) then
                lyr_set (addr);
           end;
           l^.state := 1;
         end;


Note: using the name to retrieve the new layer is not 100% reliable as duplicate layer names are possible ... I think the DataCAD UI prevents duplicates, but the underlying database allows them and a macro can still create duplicates. This is not a problem for me at this stage, just mentioning it out of interest.