4
votes

I have a Delphi program I have to convert to c#. I have done most of the conversion but ran into a couple of challenges with VarArrayCreate.

what I have is this : Line := VarArrayCreate([0, 1], varVariant);

I can't seem to figure out a conversion or substitute for the VarArrayCreate. I know that the object in c# can be used for Variant substitute but the above has me stuck.

any help would be great.

I have added the Delphi code below I interested in the procedure "TForm1.Button3Click(Sender: TObject); procedure:

unit Unit1;

(*------------------------------------------------------------------------------
DX Atlas Automation demo #2 (early binding)

Make sure that DX Atlas is installed.

Requires DxAtlas_TLB. You can either generate this file in Delphi
(Project -> Import Type Library -> DxAtlas) or use the one included
with this demo.

http://www.dxatlas.com
------------------------------------------------------------------------------*)

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  OleServer, StdCtrls, DxAtlas_TLB, ActiveX, AxCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    CheckBox1: TCheckBox;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Button6: TButton;
    procedure FormShow(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Button6Click(Sender: TObject);
  private
    { Private declarations }
  public
    Atlas: IAtlas;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

//------------------------------------------------------------------------------
//                             Start DX Atlas
//------------------------------------------------------------------------------
procedure TForm1.FormCreate(Sender: TObject);
begin
  //connect to Dx Atlas on program startup
  try
    Atlas := CoAtlas.Create;
  except on E: Exception do
    begin
    ShowMessage('Cannot connect to DX Atlas: ' + E.Message);
    Application.Terminate;
    end;
  end;
end;


procedure TForm1.FormShow(Sender: TObject);
var
  WorkArea: TRect;
begin
  //get Desktop work area dimensions
  SystemParametersInfo(SPI_GETWORKAREA, 0, @WorkArea, 0);


  //form placement

  Top := WorkArea.Top;
  Left := WorkArea.Left;
  Height := WorkArea.Bottom - WorkArea.Top;


  //atlas placement

  //stop repainting
  Atlas.Map.BeginUpdate;
  //place window
  Atlas.Top := Top;
  Atlas.Left := Left + Width;
  Atlas.Width := WorkArea.Right - Left - Width;
  Atlas.Height := Height;
  //hide prefixes
  Atlas.Map.PrefixesVisible := false;
  //now allow repainting
  Atlas.Map.EndUpdate;
  //show the Atlas window
  Atlas.Visible := true;
end;

//------------------------------------------------------------------------------
//                                  Points
//------------------------------------------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
var
  Pt, Points: OleVariant;
  i: integer;
  Layer: ICustomLayer;
begin
  Randomize;

  //create Variant array for data
  Points := VarArrayCreate([0, 999], varVariant);

  //fill the array with random points

  for i:=0 to 999 do
    begin
    //each point is a variant array with 2 elements
    Pt := VarArrayCreate([0,1], varVariant);
    //point coordinates are random (decimal degrees)
    Pt[0] := Random(360) - 180; //longitude
    Pt[1] := Random(180) - 90;  //latitude
    //add point to the data array
    Points[i] := Pt;
    end;

  //show data on the map

  Atlas.Map.BeginUpdate;
  with Atlas.Map do
    try

      Projection := PRJ_RECTANGULAR;
      Dimmed := false;
      CustomLayers.Clear;
      //add new custom layer
      Layer := CustomLayers.Add(LK_POINTS);
      with Layer do
        begin
        //set layer attributes
        PenColor := clBlue;
        BrushColor := clLime;
        PointSize := 2;
        //set data
        SetData(Points);
        end;
    finally
      EndUpdate;
    end;
end;

//------------------------------------------------------------------------------
//                                  Labels
//------------------------------------------------------------------------------
procedure TForm1.Button2Click(Sender: TObject);
var
  //Lb: Variant;
  Labels: Variant;
  i: integer;
  Layer: ICustomLayer;
begin
  Randomize;

  Labels := VarArrayCreate([0, 999], varVariant);

  for i:=0 to 999 do
    begin
    //each label is a variant array of 3 Variants
    Labels[i] := VarArrayOf([Random(360) - 180,           //longitude
                            Random(180) - 90,             //latitude
                            Format(' LABEL #%d ', [i])]); //label text

    //alternate way of creating and filling the array
    {
    Lb := VarArrayCreate([0,2], varVariant);
    Lb[0] := Random(360) - 180;
    Lb[1] := Random(180) - 90;
    Lb[2] := Format(' Label #%d ', [i]);
    Labels[i] := Lb;
    }
    end;


  Atlas.Map.BeginUpdate;
  with Atlas.Map do
   try
     Projection := PRJ_RECTANGULAR;
     Dimmed := false;
     CustomLayers.Clear;
     Layer := CustomLayers.Add(LK_LABELS);
     with Layer do
       begin
       LabelsTransparent := CheckBox1.Checked;
       //label BG if not transparent
       BrushColor := clAqua;
       //font attributes

       with (Font as IFont) do
         begin
         Put_Name('Courier New');
         Put_Italic(true);
         Put_Size(9);

         //Put_Name('Small fonts');
         //Put_Size(5);
         end;

       //font color
       PenColor := clBlue;
       //data
       SetData(Labels);
       end;
   finally
     EndUpdate;
   end;
end;


//------------------------------------------------------------------------------
//                                  Lines
//------------------------------------------------------------------------------
procedure TForm1.Button3Click(Sender: TObject);
var
  Pt, Line, Meridians, Parallels: OleVariant;
  i, j: integer;
begin
  //generate meridians
  Meridians := VarArrayCreate([0, 7], varVariant);
  for i:=0 to 7 do
    begin
    Line := VarArrayCreate([0, 36], varVariant);
    for j:=0 to 36 do
      begin
      Pt := VarArrayCreate([0, 1], varVariant);
      Pt[0] := i*45 - 180;
      Pt[1] := j*5 - 90;
      Line[j] := Pt;
      end;
    Meridians[i] := Line;
    end;

  //generate parallels
  Parallels := VarArrayCreate([0, 2], varVariant);
  for i:=0 to 2 do
    begin
    Line := VarArrayCreate([0, 72], varVariant);
    for j:=0 to 72 do
      begin
      Pt := VarArrayCreate([0, 1], varVariant);
      Pt[0] := j*5 - 180;
      Pt[1] := i*45 - 45;
      Line[j] := Pt;
      end;
    Parallels[i] := Line;
    end;

  //show on the map

  Atlas.Map.BeginUpdate;
  with Atlas.Map do
   try
     Projection := PRJ_AZIMUTHAL;
     Dimmed := false;
     CenterLatitude := 43;
     CenterLongitude := -79;
     CustomLayers.Clear;

     //show meridians
     with CustomLayers.Add(LK_LINES) do
       begin
       PenColor := clBlue;
       SetData(Meridians);
       end;

     //show parallels
     with CustomLayers.Add(LK_LINES) do
       begin
       PenColor := clRed;
       SetData(Parallels);
       end;

   finally
     EndUpdate;
   end;
end;


//------------------------------------------------------------------------------
//                                  Area
//------------------------------------------------------------------------------
procedure TForm1.Button4Click(Sender: TObject);
var
  Pt, Area, Areas: OleVariant;
  i: integer;
begin
  //single area
  Areas := VarArrayCreate([0, 0], varVariant);

  //generate area data
  Area := VarArrayCreate([0, 72], varVariant);
  for i:=0 to 72 do
    begin
    Pt := VarArrayCreate([0, 1], varVariant);
    Pt[0] := -79 + 20 * cos(i*5/180*Pi);
    Pt[1] := 43 + 20 * sin(i*5/180*Pi);
    Area[i] := Pt;
    end;

  Areas[0] := Area;

  //show on the map
  Atlas.Map.BeginUpdate;
  with Atlas.Map do
   try
     Projection := PRJ_RECTANGULAR;
     Dimmed := true;
     CustomLayers.Clear;
     with CustomLayers.Add(LK_AREAS) do
       begin
       AreaBrightness := 12; //0..15, 15=max
       SetData(Areas);
       end;
   finally
     EndUpdate;
   end;
end;



//------------------------------------------------------------------------------
//                                  Glyphs
//------------------------------------------------------------------------------
procedure TForm1.Button5Click(Sender: TObject);
var
  Glyphs: Variant;
  i: integer;
  Layer: ICustomLayer;
begin
  Randomize;

  //create array of Variants
  Glyphs := VarArrayCreate([0,333], varVariant);
  //each element of the array is a variant array with 3 elements
  for i:=0 to 333 do
    Glyphs[i] := VarArrayOf([Random(360)-180, //longitude    -180..180
                             Random(180)-90,  //latitude     -90..90
                             Random(10)]);    //image index   0..9


  Atlas.Map.BeginUpdate;
  with Atlas.Map do
   try
     Projection := PRJ_RECTANGULAR;
     Dimmed := false;
     //delete all layers
     CustomLayers.Clear;
     //add layer
     Layer := CustomLayers.Add(LK_GLYPHS);
     //Glyphs.bmp is a bitmap 160x16 that contains 10 glyphs, 16x16 each
     //the color of lower left pixel (clFuchsia) is considered transparent
     //the hot spot of the glyph is at (1, 15).
     Layer.LoadGlyphsFromFile(ExtractFilePath(ParamStr(0)) + 'Glyphs.bmp', 1, 15);
     //send locations to the layer
     Layer.SetData(Glyphs);
   finally
     //now allow repainting
     EndUpdate;
   end;
end;



//------------------------------------------------------------------------------
//                            Great Circle paths
//------------------------------------------------------------------------------
procedure TForm1.Button6Click(Sender: TObject);
var
  Pt, Line, Lines: Variant;
  i, j: integer;
begin
  //generate an array of Great Circle paths

  Lines := VarArrayCreate([0, 33], varVariant);
  for i:=0 to 33 do
    begin
    //a Great Circle path is defined by its end points
    Line := VarArrayCreate([0, 1], varVariant);
    Line[0] := VarArrayOf([-79, 43 {Toronto}]);
    Line[1] := VarArrayOf([Random(360) - 180, Random(180) - 90]);
    //add path to the array
    Lines[i] := Line;
    end;

  //show paths on the map

  Atlas.Map.BeginUpdate;
  with Atlas.Map do
   try
     Projection := PRJ_RECTANGULAR;
     Dimmed := false;
     CustomLayers.Clear;
     with CustomLayers.Add(LK_LINES) do
       begin
       PenColor := clBlue;
       SetData(Lines);
       end;
   finally
     EndUpdate;
   end;

  //Note that Delphi automatically releases the variant arrays when they go out of scope.
  //In other languages you may have to release them explicitly.
end;


end.

Mike

4

4 Answers

0
votes

you can either make a "normal" array....

MyType[] Line = new MyType[2];

or a generic List....

List<MyType> Line = new List<MyType>(); // list is empty, still have to add n elements
Line.Add( new MyType() );
Line.Add( new MyType() );

which way you go depends on what you need. If you need an "array" that grows dynamically while your program is running, go with a generic List. if not, go with an array.

now, the thing to keep in mind is that either one of these is 0 based--not arbitrarily starting at N like Delphi can do.

now, you could simulate that with a HashTable or a Dictionary, if you need to.

3
votes

The VarArrayCreate call in your example is creating an array of 2 elements starting with index zero and ending with index 1.

The C# equivalent would be this:

object[] Line;
Line = new object[2];
1
votes

It should perhaps be mentioned that varArray creates an array of the variant datatype, which is quite different from normal types. It creates a structure in memory that cannot be compared to an object instance (AFAIK). It is expected to be stored as an inter-linked (by pointer) list of nodes. However, the Delphi variant structure is identical to Microsoft's own storage format, which means you can call winapi to achieve the same thing.

If you havent solved it yet I would take a look at the COM support libraries inside .NET. Probably under "System.Runtime.InteropServices"". Or look at the variants.pas unit in Delphi and see what WinAPI functions they call.

1
votes
private void _showPoints()
{
  object[] pt = new object[2];
  object[] points = new object[4];

  for (int i = 0; i < 3; i++)
  {
    pt[0] = _dx[i, 0];
    pt[1] = _dx[i, 1];
    points[i] = pt;
  }
  _aquaPoints.SetData(points);
}

Above is an example of the ShowPoints method from Alex's VB code. It will also apply to the conversion of the Delphi code you are converting...

object is the nearest thing to variant in C#.