вторник, 23 ноября 2010 г.

Delphi + ActiveX или ничего не понимаю!

Добрый день коллеги.

Столкнулся с такой загадкой:


Понадобилось использовать ActiveX компонент MapWinGis http://www.mapwindow.org/ для создания картографической информации в Delphi. Скачал, установил, импортировал, установил, сделал тестовый проект и столкнулся с такой проблемой, компонент не работает в следующем тривиальном коде:

var
Sh : IShapefile;
begin
Sh := CoShapefile.Create;
IF OpenDialog1.Execute then
begin
if not Sh.Open(OpenDialog1.FileName, nil) then
ShowMessage('err!');
try
  Map1.AddLayer(sh,true);   // выдает ошибку после чего, карта становится черным цветом
Map1.ZoomToMaxExtents;
except
On E:Exception do
ShowMessage(E.Message);
end;
end;


Ну не работает и не работает и бог с ним, но однако дернул меня черт проверить похожий код в C++ Builder-е

void __fastcall TfrmMain::aLoadSHPExecute(TObject *Sender)
{
if (OpenDialog1->Execute())
{
IShapefilePtr shapefile1;
shapefile1.CreateInstance(CLSID_Shapefile);
shapefile1->Open(OpenDialog1->FileName.w_str(), NULL );
 Map1->AddLayer(shapefile1,true); // работает
}
}


И там он заработал, пошел дальше проверил в C# и Visual Basic - ТОЖЕ РАБОТАЕТ!

В общем работает везде, но только не в Delphi! Вот и сижу гадаю, вроде ActiveX является универсальным так сказать компонентом и доступен их всех языков поддерживающих данную технологию и ПО ИДЕЕ в DELPHI должен работать. Или что то Delphi делает не так, что вызывает ошибку в данной ActiveX. Такие вот пироги с котятами. У кого какие идеи?

7 комментариев:

  1. Судя по примеру Sh должно быть типа Shapefile

    ОтветитьУдалить
  2. В том то и дело что Shapefile = IShapefile, то есть в AddLayer передается интерфейс. Но почему то в Delphi выходит ошибка EZeroDivide а в других языках программирования ее и нет. И это для меня увы большая загадка. Ну и разочарование конечно, так как MapWinGis довольно мощный OpenSource компонент для поддержки карт

    ОтветитьУдалить
  3. И все же обратите внимание на то, что в примерах, которые можно скачать на сайте, везде используется подход вроде

    var
    sf: MapWinGIS_TLB.Shapefile;

    begin
    sf := CoShapefile.Create();
    sf.Open('c:\dev\data\dan.shp', nil);
    Map1.AddLayer(sf, true);

    Как мне кажется, в вашем варианте после Sh.Open объект Sh будет автоматически уничтожен... Из-за автоматического подсчета ссылок.

    ОтветитьУдалить
  4. Да нет, в таком случае она будет уничтожена при выходе из процедуры, а код до выхода не выполняется.

    даже если sh перенести в класс, чтобы гарантировать неудаление, ошибка все равно остается.

    type
    TForm2 = class(TForm)
    Map1: TMap;
    OpenDialog1: TOpenDialog;
    procedure FormCreate(Sender: TObject);
    private
    { Private declarations }
    public
    { Public declarations }
    Sh : IShapefile;
    end;

    var
    Form2: TForm2;

    implementation

    {$R *.dfm}

    procedure TForm2.FormCreate(Sender: TObject);
    begin
    Sh := CoShapefile.Create;
    IF OpenDialog1.Execute then
    begin
    if not Sh.Open(OpenDialog1.FileName, nil) then
    ShowMessage('err!');
    try
    Map1.AddLayer(sh,true);
    Map1.ZoomToMaxExtents;
    except
    On E:Exception do
    ShowMessage(E.Message);
    end;
    end;
    end;

    end.

    ОтветитьУдалить
  5. К сожалению на своей XE проверить не могу.
    Примеры-то проходят? С ShapeFile? Ведь зачем-то они в обоих примерах используют именно ShapeFile...
    Поэтому у меня чисто интуитивно складывается ощущение что тут тот самый азбучный принцип "никогда не смешивать модель объекта и модель интерфейса".

    ОтветитьУдалить
  6. Это то понятно, но увы даже демо-примеры не проходят. То есть простейший пример

    var
    sf: MapWinGIS_TLB.Shapefile;

    begin
    sf := CoShapefile.Create();
    sf.Open('c:\dev\data\dan.shp', nil);
    Map1.AddLayer(sf, true);

    выдает ошибку в AddLayer. И это только в Delphi, как я и писал в C++ С# и VB такой код выполняется без проблем

    Мало того если код переделать так

    var
    sf: MapWinGIS_TLB.TShapefile;

    begin
    sf := TShapefile.Create(self); // Испольуется класс. а не интерфейс
    sf.Open('c:\dev\data\dan.shp', nil);

    то тоже самое, Класс TShapefile это класс созданный Delphi при импортировании ocx.

    Спасибо за помощь

    ОтветитьУдалить
  7. Найдено решение проблемы
    http://deeptown12.blogspot.com/2011/01/mapwingis-delphi-activex.html

    ОтветитьУдалить