0% found this document useful (0 votes)
18 views

Plain and Simple About MapInfo and Delphi

This document discusses how to integrate MapInfo GIS software into a Delphi application. It provides an overview of MapInfo and integrated mapping concepts. It also includes sample code for a MapInfo server component that can launch MapInfo, send MapBasic commands, and manage MapInfo windows from a Delphi application.

Uploaded by

jeksib
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views

Plain and Simple About MapInfo and Delphi

This document discusses how to integrate MapInfo GIS software into a Delphi application. It provides an overview of MapInfo and integrated mapping concepts. It also includes sample code for a MapInfo server component that can launch MapInfo, send MapBasic commands, and manage MapInfo windows from a Delphi application.

Uploaded by

jeksib
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 13

Plain and simple about MapInfo and Delphi - Calling MapInfo and embedding it

in your program (integrated mapping basics)

Author: Dmitry Kuzan

Good time of the day!

With this article, I begin a series of articles on the possibilities of integrated MapInfo
cartography and the possibility of embedding a geographic information system into
your program. Notes : All examples are distributed freely and are developed for
educational purposes on Delphi 6. See the attached source codes for all information on
how to work.

So, let's begin.

What is MapInfo and what is it eaten with? Brief preface.

We now have access to vast amounts of information. The data is stored in spreadsheets,
trade and marketing reporting. A wealth of information about customers, stores,
personnel, equipment and resources is on paper and in computer memory. Thematic
Map containing a layer of ranges (percentage of employment) and pie charts
(production of agricultural products) Almost all of this data has a geographical
component. According to various estimates, up to 85 percent of all databases contain
some kind of geographic information.

This estimate took into account data volumes containing addresses, city names, state
names, state names, postal codes, and even phone numbers, including dial-up codes
and extensions. Desktop cartography will allow your computer to not just process data,
but to quickly and visually represent it using geographical data components so that you
can capture their general meaning reflected on maps.

How can desktop cartography work for you? MapInfo, as a desktop mapping tool, is a
powerful data analysis tool. You can give a graphical appearance to statistical and other
data. You can display your data as points, as thematic areas, pie and bar graphs,
districts, and more. Geographic operators can be applied to the data, such as zoning,
feature combination and slicing, and buffering. Data can be accessed as queries,
including access to remote databases directly from MapInfo. For example, which store
is closer to your firm's biggest customers? The map makes it easy to see features and
trends that are almost impossible to detect in list-organized data. You can easily
calculate the distances between customers and stores; you can see the location of the
office of the client who spent the largest amount over the past year; the size of the
symbols marking the location of stores on the Map may depend on the volume of sales.
All this makes the visualization of your data more visual. So a brief preface from the
user's guide gives you a general idea of MapInfo.

What is integrated cartography and what does it mean to us.

Integrated mapping allows you to manage the MapInfo package using programming
languages other than MapBasic. For example, if you are familiar with programming in
Visual Basic or C++ or Delphi (which will be discussed later ...), you can include a
MapInfo window in your application, thereby ensuring the integration of the MapInfo
package with the logic (business rules) of your programs.

Moreover, MapInfo (MapBasic) takes on the main work of maintaining vector maps,
and you can create and assign handlers and interaction mechanisms that are not
characteristic of MapBasic, as well as those mechanisms that MapBasic does not
directly support (for example, updating a map via the Internet, picking up information
from sensors on the territory and updating on the map, etc.)

So let's get started: in a series of articles the following things will be considered

 Connecting and Loading MapInfo


 Embedding a MapInfo window and other windows (legend, info, etc.) in a
Delphi program
 Sending MapBasic Commands to a MapInfo Package
 Getting Information from MapInfo Using Functions
 Using notification calls (CallBack) and connecting them to your program.
 Creating Your Own Notification Calls
 Redefining notification calls
 Handling Notification Calls
 Creating a simple component (perhaps this topic will be covered) for managing
MapInfo.
 and much more.

Concepts of Integrated Cartography

To create an Integrated Map application, you must write a program - not a MapBasic
program. Applications with an Integrated Map can be written in several programming
languages, among which C, Visual Basic, Delphi are the most commonly used.

Your program must have a statement that runs MapInfo in the background. For
example, in a program, you can start MapInfo by calling the CreateObject() function.
MapInfo runs in the background without the user noticing it, without displaying a
splash screen. Your program controls the MapInfo program by constructing strings that
represent MapBasic language statements, which are then passed to MapInfo through
the OLE Object Engine (OLE Automation) or Dynamic Data Exchange (DDE).
MapInfo executes these statements exactly as if the user were typing them into a
MapBasic window.

Note:

Reassigning MapInfo windows to another application prevents MapInfo from


automatically accessing that application's data. To display application data in a
MapInfo window, you must first write the data to a MapInfo table.

System requirements

Integrated mapping requires MapInfo version 4.0 or higher on your computer. You can
use the full version of MapInfo or the so-called runtime module (a truncated version of
MapInfo supplied as the basis for specialized applications)

You must be experienced with Handle.

Your program must be able to act as an OLE Automation Controller (OLE) controller
or DDE client. The use of an OLE controller is recommended as a faster and more
reliable method than DDE. We will consider it

Other brief technical notes

 Integrated mapping uses the OLE management engine but does not use OLE
embedding.
 Integrated cartography does not use VBX or OCX controls (this is not quite the
case - there is an OCX MapX module - for working with MapInfo GIS (not
included in the standard package), but this is no longer integrated cartography
and will not be considered).
 Integrated mapping does not provide you with any header files or libraries
 Integrated Mapping includes several DLLs but does not provide direct access to
them.

Launching and Linking to the MapInfo Server

So let's consider the simplest component for launching and managing MapInfo
(TKDMapInfoServer), it should be noted that I did not write a specialized component -
I present the basics.

unit KDMapInfoServer;

interface

uses
ComObj, Controls, Variants, ExtCtrls, Windows, Messages,
SysUtils, Classes;

const
scMapInfoWindowClass = 'xvt320mditask100';
icWinMapinfo = 1011;
icWinInfoWindowid = 13;

type
TEvalResult = record
AsVariant: OLEVariant;
AsString: string ;
AsInteger: Integer;
AsFloat: Extended;
AsBoolean: Boolean;
end ;

TKDMapInfoServer = class (TComponent)


private
{ Private declarations }
// Owner
FOwner : TWinControl;

// OLE server
FServer : Variant;
FHandle : THandle;
FActive : Boolean;
FPanel : TPanel;

Connected : Boolean;

MapperID : Cardinal;
MapperNum : Cardinal;
procedure SetActive( const Value: Boolean);
procedure SetPanel( const Value: TPanel);

procedure CreateMapInfoServer;
procedure DestroyMapInfoServer;
protected
{ Protected declarations }
public
{ Public declarations }
constructor Create(AOwner: TComponent); override ;
destructor Destroy; override ;
// This procedure executes the MapInfo Server method - Do
procedure ExecuteCommandMapBasic(Command: string ; const
Args: array of const );
// This procedure executes the MapInfo server method - Eval
function Eval(Command: string ; const Args: array of
const ): TEvalResult; virtual ;
procedure WindowMapDef;
procedure OpenMap(Path : string );
published
{ Published declarations }
// Creates a connection to the MapInfo server
property Active: Boolean read FActive write SetActive;
property PanelMap : TPanel read FPanel write SetPanel;
end ;

procedure register ;

implementation

procedure register ;
begin
RegisterComponents('Kuzan', [TKDMapInfoServer]);
end ;

{ TKDMapInfoServer }
constructor TKDMapInfoServer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FOwner := AOwner as TWinControl;
FHandle := 0;
FActive := False;
Connected := False;
end ;

destructor TKDMapInfoServer.Destroy;
begin
DestroyMapInfoServer;
inherited Destroy;
end ;

procedure TKDMapInfoServer.CreateMapInfoServer;
begin
try
FServer := CreateOleObject('MapInfo.Application');
except
FServer := Unassigned;
end ;

// Hide MapInfo Control Panels


ExecuteCommandMapBasic('Alter ButtonPad ID 4 ToolbarPosition (0,
0) Show Fixed', []);
ExecuteCommandMapBasic('Alter ButtonPad ID 3 ToolbarPosition (0,
2) Show Fixed', []);
ExecuteCommandMapBasic('Alter ButtonPad ID 1 ToolbarPosition (1,
0) Show Fixed', []);
ExecuteCommandMapBasic('Alter ButtonPad ID 2 ToolbarPosition (1,
1) Show Fixed', []);
// Redefining windows
ExecuteCommandMapBasic('Close All', []);
ExecuteCommandMapBasic('Set ProgressBars Off', []);
ExecuteCommandMapBasic('Set Application Window %D',
[FOwner.Handle]);
ExecuteCommandMapBasic('Set Window Info Parent %D',
[FOwner.Handle]);

FServer.Application.Visible := True;
if IsIconic(FOwner.Handle) then
ShowWindow(FOwner.Handle, SW_Restore);
BringWindowToTop(FOwner.Handle);
end ;

procedure TKDMapInfoServer.DestroyMapInfoServer;
begin
ExecuteCommandMapBasic('End MapInfo', []);
FServer := Unassigned;
end ;

procedure TKDMapInfoServer.ExecuteCommandMapBasic(Command: string


;
const Args: array of const );
begin
if Connected then
try
FServer. do (Format(Command, Args));
except
on E: Exception do MessageBox(FOwner.Handle,
PChar(Format('Ошибка выполнения () - %S', [E. message ])),
'Warning', MB_ICONINFORMATION or MB_OK);
end ;
end ;

function TKDMapInfoServer.Eval(Command: string ;


const Args: array of const ): TEvalResult;

function IsInt(Str : string ): Boolean;


var
Pos : Integer;
begin
Result := True;
for Pos := 1 to Length(Trim(Str)) do
begin
if (Str[Pos] <> '0') and (Str[Pos] <> '1') and
(Str[Pos] <> '2') and (Str[Pos] <> '3') and
(Str[Pos] <> '4') and (Str[Pos] <> '5') and
(Str[Pos] <> '6') and (Str[Pos] <> '7') and
(Str[Pos] <> '8') and (Str[Pos] <> '9') and
(Str[Pos] <> '.') then
begin
Result := False;
Exit;
end ;
end ;
end ;

var
ds_save: Char;
begin
if Connected then
begin
Result.AsVariant := FServer.Eval(Format(Command, Args));
Result.AsString := Result.AsVariant;
Result.AsBoolean := (Result.AsString = 'T') or
(Result.AsString = 't');

if IsInt(Result.AsVariant) then
begin
try
ds_save := DecimalSeparator;
try
DecimalSeparator := '.';
Result.AsFloat := StrToFloat(Result.AsString);
//Result.AsVariant;
finally
DecimalSeparator := ds_save;
end ;
except
Result.AsFloat := 0.00;
end ;

try
Result.AsInteger := Trunc(Result.AsFloat);
except
Result.AsInteger := 0;
end ;
end
else
begin
Result.AsInteger := 0;
Result.AsFloat := 0.00;
end ;
end ;
end ;

procedure TKDMapInfoServer.SetActive( const Value: Boolean);


begin
FActive := Value;
if FActive then
begin
CreateMapInfoServer;
WindowMapDef;
Connected := True;
end
else
begin
if Connected then
begin
DestroyMapInfoServer;
Connected := False;
end ;
end ;
end ;

procedure TKDMapInfoServer.SetPanel( const Value: TPanel);


begin
FPanel := Value;
end ;

procedure TKDMapInfoServer.WindowMapDef;
begin
ExecuteCommandMapBasic('Set Next Document Parent %D Style 1',
[FPanel.Handle]);
end ;

procedure TKDMapInfoServer.OpenMap(Path: string );


begin
ExecuteCommandMapBasic('Run Application "%S"', [Path]);
MapperID := Eval('WindowInfo(FrontWindow(),%D)',[12]).AsInteger;
with PanelMap do
MoveWindow(MapperID, 0, 0, FPanel.ClientWidth,
FPanel.ClientHeight, True);
end ;

end .

And so we have -

 We have established a connection with the MapInfo server.


 We learned that the MapInfo server has a Do method - it is designed to send
MapBasic commands to the server just as if the user were typing them in the
MapBasic window of the MapInfo program itself.
 We learned that the MapInfo server has an Eval method - it is designed to get
the value of functions after sending MapBasic commands to the server.
 We've seen the MapInfo output direction override commands.

Good to start

Now for some theory.


Start MapInfo

A unique instance of the MapInfo program is launched by calling the CreateObject()


Visual Basic function, assigning the return value to an object variable. (You can
declare an object variable as global; otherwise, the MapInfo object is freed when the
local procedure exits.)

For example:

FServer := CreateOleObject('MapInfo.Application');

To connect to a previously running MapInfo instance that was not started by a call to
the CreateObject() function, use the GetObject() function.

// This implementation is left for you dear readers to practice


FServer := GetObject('MapInfo.Application');

Attention:

If you are using a Runtime version of MapInfo rather than a full copy, use
"MapInfo.Runtime" instead of "MapInfo.Application". The runtime version and the
full version can run at the same time.

The CreateObject() and GetObject() functions use the OLE Object Management (OLE
Automation) mechanism to communicate with MapInfo.

Note:

On a 32-bit version of Windows (Windows95 or Windows NT), you can run multiple
instances of MapInfo. If you run MapInfo followed by a program that uses Integrated
Mapping and calls CreateObjectf), then two independent instances of MapInfo will run.
However, in the 16-bit version, a program using Integrated Mapping with MapInfo
running will not work.

Sending Commands to MapInfo

After running the MapInfo program, you must construct text strings that represent Map
Basic language statements.

If you communicated with MapInfo using OLE Object Management (OLE


Automation), pass the command line to MapInfo using the Do method.

For example:

FServer.Do('MapBasic command here');

Note:

In the component, this is implemented by the ExecuteCommandMapBasic procedure,


but in the entity, FServer.Do is called

When using the Do method, MapInfo executes the command line exactly as if it were
entered in the MapBasic command window.

Note:

You can pass a statement to a MapInfo program if that statement is valid in a MapBasic
window. For example, you cannot send a MapBasic Dialog statement because its use is
not allowed in a MapBasic window.

To determine whether a MapBasic language statement is valid in a MapBasic window,


see the MapBasic Reference or open the Help system; the information you are looking
for is under the heading "Warning". For example, the Dialog Statement Help gives the
following restriction: "You cannot use a Dialog statement in a runtime window (such
as For..-Next and Goto) are not allowed to run in a MapBasic window.

Requesting data from the MapInfo program

To query a MapBasic value from your client program, use the OLE method Eval.

For example:

MyVar:= FServer.Eval('MapBasic command here');

Note:

In the component, this is implemented by the Eval procedure, but in the entity,
FServer.Eval is called

When you use the Eval method, MapInfo interprets the string as a MapBasic
expression, determines the value of the expression, and returns that value as a string.
Note: If the expression evaluates to a boolean value (type Logical), MapInfo returns a
single character string, "T" or "F" respectively.

Reassigning MapInfo windows

After starting MapInfo, use the Set Application Window statement of the MapBasic
language to ensure that your client program takes control of the dialog boxes and error
messages of the MapInfo program.

Then, at the point you want to include a MapInfo window in your application, pass
MapInfo a Set Next Document statement followed by a MapBasic statement that
creates the window.

The Set Next Document statement allows you to "reparent" document windows. The
syntax of this statement requires you to specify a unique HWND number for the
control in your program. When a MapInfo document window is subsequently created
(using the Map, Graph, Browse, Layout, or Create Legend statements), the newly
created window becomes the window's parent object.

Examples are given from the component, but the same can be done with the Do method
directly, but I think you already understood this

ExecuteCommandMapBasic('Set Application Window %D',


[FOwner.Handle]);
ExecuteCommandMapBasic('Set Window Info Parent %D',
[FOwner.Handle]);
ExecuteCommandMapBasic('Set Next Document Parent %D Style 1',
[FPanel.Handle]);

Note:

In the component, this is implemented by the WindowMapDef procedure, which refers


to the panel specified by the PanelMap property.

For each window you resubordinate, you need to pass a pair of statements from your
program to MapInfo - the Set Next Document Parent statement, and then the statement
that creates the window. After the window has been created, you may need to query
MapInfo for the value of the WindowID(0) function, MapInfo's integer Window ID
number, as many MapBasic statements require this number to be specified. This query
is executed on a component basis like this:

WindowID := Eval('WindowID(%D)',[0]).AsInteger;
Note that even after reparenting the Maps window, MapInfo continues to control it. the
client program may not pay attention to messages about redrawing, I will leave the
implementation of this feature for later.

Reassigning Legend windows, raster dialogs, and other MapInfo windows

To change (subordinate) window data, the MapBasic Set Window... Parent statement is
used.

For example, in the component, resubordination of the information window is


implemented as follows -

ExecuteCommandMapBasic('Set Window Info Parent %D',


[FOwner.Handle]);

I leave the implementation of re-subordination of other windows to you dear readers.

Note that the way to resubordinate the Info window is different than for the Map
window. In the latter case, the Set Next Document clause is not used. The fact is that
there can be several Map windows.

Windows Legends is a special case. Usually there is only one Legend window, as well
as one Information window. However, you can create additional Legend windows
using the MapBasic Create Legend statement.

For a single Legend window, use the MapBasic Window Legend Parent statement.

To create an additional Legend window, use the MapBasic Set Next Document
statement and the Create Legend statement. Note that in this case you are creating a
Legend that is tied to one specific Map window or Graph window. Such a Legend
window does not change when another window becomes active.

Tip:

You can create a "floating" Legend window inside the Map window. In the Set Next
Document statement, specify the Map window as the parent window. See the
MapBasic documentation for more information.

To be continued….

End of the first part.


Project Delphi World © Issue 2002 - 2020
Author of the project: Business automation
You can buy the franchise of this project here.

You might also like