Почему ошибка при формировании интерфейса?

0 голосов
спросил 22 Апр, 10 от dmitry12081973 (1,920 баллов) в категории Программные продукты Esri
Здравствуйте.
Подскажите, пожалуйста, что я не так делаю.

Создаю COM-объект в Delphi 7, при этом получаю автоматически с помощью делфиевского окна "COM Object Wizard" следующий код:

unit MAPCOMServerInit;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses
  ComObj, ActiveX, MAPCOMServer_TLB, StdVcl, esriSystemUI_TLB;

type
  TMAPCOMServerDima = class(TAutoObject, ICommand)
  protected
    function Get_Caption: WideString; safecall;
    function Get_Category: WideString; safecall;
    function Get_Checked: WordBool; safecall;
    function Get_Enabled: WordBool; safecall;
    function Get_HelpContextID: Integer; safecall;
    function Get_HelpFile: WideString; safecall;
    function Get_Message: WideString; safecall;
    function Get_Name: WideString; safecall;
    function Get_Tooltip: WideString; safecall;
    function Get_Bitmap: OLE_HANDLE; safecall;
    procedure OnClick; safecall;
    procedure OnCreate(const hook: IDispatch); safecall;
  end;

implementation

uses ComServ;

function TMAPCOMServerDima.Get_Caption: WideString;
begin
end;

function TMAPCOMServerDima.Get_Category: WideString;
begin
end;

function TMAPCOMServerDima.Get_Checked: WordBool;
begin
end;

function TMAPCOMServerDima.Get_Enabled: WordBool;
begin
end;

function TMAPCOMServerDima.Get_HelpContextID: Integer;
begin
end;

function TMAPCOMServerDima.Get_HelpFile: WideString;
begin
end;

function TMAPCOMServerDima.Get_Message: WideString;
begin

end;

function TMAPCOMServerDima.Get_Name: WideString;
begin
end;

function TMAPCOMServerDima.Get_Tooltip: WideString;
begin
end;

function TMAPCOMServerDima.Get_Bitmap: OLE_HANDLE;
begin
end;

procedure TMAPCOMServerDima.OnClick;
begin
end;

procedure TMAPCOMServerDima.OnCreate(const hook: IDispatch);
begin
end;

initialization
  TAutoObjectFactory.Create(ComServer, TMAPCOMServerDima, Class_MAPCOMServerDima,
    ciMultiInstance, tmApartment);

В результате компиляции этого кода выдаётся ошибка:
Declaration of 'Get_Bitmap' differs from declaration in interface 'ICommand'

Смотрю исходный код файла esriSystemUI_TLB.pas, в котором этот ICommand объявлен и который соответственно взят в качестве предка для моего класса, вижу:

  ICommand = interface(IUnknown)
    ['{36B06538-4437-11D1-B970-080009EE4E51}']
    function Get_Enabled: WordBool; safecall;
    function Get_Checked: WordBool; safecall;
    function Get_Name: WideString; safecall;
    function Get_Caption: WideString; safecall;
    function Get_Tooltip: WideString; safecall;
    function Get_Message: WideString; safecall;
    function Get_HelpFile: WideString; safecall;
    function Get_HelpContextID: Integer; safecall;
    function Get_Category: WideString; safecall;
    procedure OnCreate(const hook: IDispatch); safecall;
    function Get_Bitmap: OLE_HANDLE; safecall;
    procedure OnClick; safecall;
    property Enabled: WordBool read Get_Enabled;
    property Checked: WordBool read Get_Checked;
    property Name: WideString read Get_Name;
    property Caption: WideString read Get_Caption;
    property Tooltip: WideString read Get_Tooltip;
    property Message: WideString read Get_Message;
    property HelpFile: WideString read Get_HelpFile;
    property HelpContextID: Integer read Get_HelpContextID;
    property Bitmap: OLE_HANDLE read Get_Bitmap;
    property Category: WideString read Get_Category;
  end;

То есть объявление функции Get_Bitmap точно такое же, как и в моём классе TMAPCOMServerDima.

Почему тогда ругается компилятор?

39 Ответы

0 голосов
ответил 26 Апр, 10 от dmitry12081973 (1,920 баллов)
>1. А какой тип переменной pmxApp
pMxApp : IApplication; - глобально обьявил

И никак у меня не получается, как я уже писал выше, выполнить строку в процедуре OnCreate:
pmxApp := hook as IApplication; - пишет компилятор, что не поддерживается интерфейс.

А как же мне тогда поступить, если в процедуре OnClick я хочу реализовать следующий код (взял из примера на форуме, хочу нарисовать точку в слое карты):

procedure TMAPCOMServerDima.OnClick;
var
  pDoc: IMxDocument;
  pLayer: ILayer;
  pFeatLayer: IFeatureLayer;
  pFeature: IFeature;
  pFeatClass: IFeatureClass;
  pGeometry: IGeometry;
  pPointcoll: IPointCollection;
  pQFilt: IQueryFilter;
  pPoint: IPoint;
  pFeatCur: IFeatureCursor;
  FeatureCount: Integer;
  PointCount: Integer;
  PointCoordinates: String;
  Uniq_Code: String;
  FieldIndex: Integer;
  i: Integer;
begin
  (pMxApp as IApplication).Document.QueryInterface(IMxDocument, pDoc);

  pLayer := pDoc.FocusMap.Layer[0];
  pLayer.QueryInterface(IID_IFeatureLayer, pFeatLayer);

  pQFilt := CoQueryFilter.Create as IQueryFilter;
  pQFilt.WhereClause := 'FID >= 0';

  ShowMessage(pQFilt.WhereClause);

  pFeatClass := pFeatLayer.FeatureClass;
  try
    FeatureCount := pFeatClass.FeatureCount(pQFilt);
  except
    on e: exception do ShowMessage(e.Message);
  end;

  ShowMessage('Feature Count is      ' + IntToStr(FeatureCount));
  pFeatCur := pFeatLayer.FeatureClass.Search(pQFilt, False);
  pFeature := pFeatCur.NextFeature;
  repeat
    pGeometry := pFeature.Shape;
    pGeometry.QueryInterface(IID_IPointCollection, pPointcoll);
    FieldIndex := pFeature.Fields.FindFieldByAliasName('Uniq_Code');
    Uniq_Code := pFeature.Value[FieldIndex];
    PointCount := pPointcoll.PointCount;
    ShowMessage( Uniq_Code + '      ' + IntToStr(PointCount - 1) );
    PointCoordinates := '';
    For i := 0 To PointCount - 1 do
    begin
      pPoint := pPointcoll.Point;
      PointCoordinates := PointCoordinates + FloatToStr(pPoint.X) + '   ' + FloatToStr(pPoint.Y) + #13#10;
    end;
    ShowMessage(PointCoordinates);
    pFeature := pFeatCur.NextFeature;
  Until pFeature = nil;
end;

и мне нужна эта переменная pMxApp, потому что, как я понимаю, без неё никак нельзя обойтись.



0 голосов
ответил 26 Апр, 10 от pooperec (10,820 баллов)
Ну, а по логике вы сами то видите, что переменная pMxApp, используется для получения переменной pDoc, которая в свою очередь нужна только для получения первого в списке слоя...
pLayer := pDoc.FocusMap.Layer[0];

Было бы очень грустно, если бы без неё нельзя было обойтись...

Крайний раз поясню по переменным:
1) Переменная типа (диспатч интерфейс) IApplication, нужен для сопряжения и работы с приложением ArcMap, эта переменная используется также во встроенном калькуляторе. В общем во всех случаях, когда Вашу библиотеку (сборку) вызывает приложение ArcMap, ArcCatalog.

2) Переменная IMapContol2(2-4) используется когда Вы знаете что Вам управление передаст непосредственно MapControl, то есть это приложения ArcEngine, и возможно (но не знаю точно - Веб приложения)...

3) Интерфейс IHookHelper "научен" съедать (приводить) основные типы переменных (диспатч интерфейсов - IMapControl, IApplication, и т.д.) и на выход предоставлять только необходимые "отростки", интерфейсы IMap и IActiveView.

В Вашем примере, Вам по сути необходим интерфейс IMap, и то, только для того чтобы получить "слой 0"...

Если, уж совсем всё печально, ниже привожу готовый код:
var
pHook : IHookHelper;
//...
//...
//...
procedure TMAPCOMServerDima.OnCreate(const hook: IDispatch);
begin
if supports(hook,IMapControl) then Begin
// ShowMessage('Нас вызвал MapControl');
pHook:=CoHookHelper.Create as IHookHelper;
pHook.hook:=hook;
End;
end;

procedure TMAPCOMServerDima.OnClick;
var
///
///
Begin
pLayer := phook.FocusMap.Layer[0];
// Дальше по тексту
End;
    
0 голосов
ответил 26 Апр, 10 от dmitry12081973 (1,920 баллов)
Спасибо Вам.

Я Вас уже замучил, наверное.

Пытаюсь как в примере, приведённом выше (procedure TMAPCOMServerDima.OnClick;) проинициализировать pFeatLayer через pLayer:

pLayer.QueryInterface(IID_IFeatureLayer, pFeatLayer);

получаю pFeatLayer = nil.

Я понимаю, что это происходит из-за того, что не находится требуемый интерфейс, а почему он не находится, это уже к сожалению выше моего понимания.
Unhappy


0 голосов
ответил 26 Апр, 10 от pooperec (10,820 баллов)
Ну тут либо лыжи либо...

У Вас самый верхний слой в TOC, какой?
0 голосов
ответил 27 Апр, 10 от dmitry12081973 (1,920 баллов)
Посмотрел, сколько слоёв у меня на карте так:
count := phook.FocusMap.LayerCount;
count = 1; - всего один слой
0 голосов
ответил 27 Апр, 10 от pooperec (10,820 баллов)
И что это за слой?

Он должен быть векторным слоем шейп файла, или слоем из ГБД, или нечто подобное... Растро и группа слоев не подойдет...

Попробуйте простое присваивание
pFeatureLayer := pLayer as IFeatureLayer;
0 голосов
ответил 27 Апр, 10 от dmitry12081973 (1,920 баллов)
Да, Вы правы, у меня это вероятно растровый слой, хотя, как точно проверить, не знаю.
Пробовал грузить и сохранять слои в ArcMap-е из C:\Program Files\ArcGIS\Reference Systems\*.shp, строка
pLayer.QueryInterface(IID_IFeatureLayer, pFeatLayer);
уже работает нормально, но программа падает на строке
pFeatClass := pFeatLayer.FeatureClass; - pFeatClass остаётся равным nil

Может есть ссылка, по которой можно скачать векторный слой для нормальной работы с ним? Спасибо.
0 голосов
ответил 28 Апр, 10 от pooperec (10,820 баллов)
У Вас shp слой единственный в ТОС?
Присваивание pFeatureLayer := pLayer as IFeatureLayer; Вы пробовали?
Имя слоя с помощью ShowMessage(pFL.Name); проверяли?
0 голосов
ответил 28 Апр, 10 от dmitry12081973 (1,920 баллов)
>У Вас shp слой единственный в ТОС?
Да, единственный: phook.FocusMap.LayerCount = 1

>Присваивание pFeatureLayer := pLayer as IFeatureLayer; Вы пробовали?
Да, пробовал, появляется ошибка: интерфейс не поддерживается

>Имя слоя с помощью ShowMessage(pFL.Name); проверяли?
Проверял, имя слоя pLayer.Name = 'World Images'

0 голосов
ответил 28 Апр, 10 от pooperec (10,820 баллов)
'World Images' стрёмное название для шейп файла....

Попробуйте World Time Zones...
Добро пожаловать на сайт Вопросов и Ответов, где вы можете задавать вопросы по GIS тематике и получать ответы от других членов сообщества.
...