Имеется карта с расширением .SIT. В своей прикладной задаче я создаю свою карту по параметрам имеющейся через mapCreateAndAppendSite. Карта создается и в операторе видно, что теперь 2 карты в одной. Я пытался получить идентификатор созданной карты серез mapOpenSiteForMap и вроде как получаю какое-то значение, но если я пытаюсь создать объект на карте с этим идентификатором, то получаю exception.
По идее, после вызова функци mapCreateAndAppendSite я должен был получить идентификатор созданной карты, но при попытке использовать этот идентификатор вылетает exception: Project Operator.exercise raised exeception class $C0000005 access violation at 0x0241c741:read of address 0x00000023.
В задаче сперва проверяется наличие нашей карты, если она отсутствует, то задача её создает:
Код
function GetMapHandle(Map : HMap): HMap; var tMap : HMap; name : PAnsiChar; newMap,newRsc : AnsiString; I : Integer;
begin
name := mapGetMapPath(Map);
I := Length(name) - 1;
while name[I] <> '\' do
begin
I := I - 1;
end;
newMap := AnsiString(name);
Delete(newMap,(I+2),Length(name)+5);
newRsc := newMap;
Insert(MapName,newMap,Length(newMap)+1);
Insert(RscName,newRsc,Length(newRsc)+1);
if not FileExists(newMap) then
begin tMap := CreateMap(Map,PAnsiChar(newMap),PAnsiChar(newRsc));
end
else
begin
tMap := mapOpenSiteForMap(Map,PAnsiChar(newMap),0);
end;
Result := tMap;
end;
function CreateMap(Map : HMap;NewMap : PAnsiChar; NewRsc : PAnsiChar): HMap;
var
tMap : HMap;
tSite : TCreateSite;
MR : TMAPREGISTER;
LR : TLISTREGISTER;
I : integer;
name : PAnsiChar;
begin
name := mapGetMapName(Map);
mapGetMapInfo(Map,0,MR,LR);
tSite.Length := MR.Length;
FillChar(tSite.MapName, sizeof(tSite.MapName),0);
for I := 0 to Length(name) do
begin
tSite.MapName[I+1] := name[I];
end;
tSite.MapType := MR.MapType;
tSite.MaterialProjection := MR.MaterialProjection;
tSite.Scale := MR.Scale; tSite.FirstMainParallel := MR.FirstMainParallel;
tSite.SecondMainParallel := MR.SecondMainParallel; tSite.AxisMeridian := MR.AxisMeridian;
tSite.MainPointParallel := MR.MainPointParallel;
try
tMap := mapCreateAndAppendSite(Map,NewMap,NewRsc,tSite);
Result := tMap;
except
on E:Exception
do begin
ShowMessage(E.Message);
Result := 0;
end;
end;
end;
На первый взгляд, Ваш код не содержит ошибок в части использования MAPAPI.
Исключение exeception class $C0000005 - это, как правило, исключение среды разработки, в большинстве случаев являющееся следствием повреждения памяти где-то в программе. Этот экскепшн, например, может встречаться в режиме отладки и не проявляться при сборке в release (или наоборот). Надо искать место, где портиться память.
Если mapCreateAndAppendSite возвращает ненулевой результат, значит функция отработала. Скорее всего, память повреждается в другом месте. Или до, или после. Непосредственно определить, отработала ли функция можно проверив наличие созданной карты на диске - NewMap.
Для начала я бы проверил этот фрагмент:
Код
for I := 0 to Length(name) do begin
tSite.MapName[I+1] := name[I];
end;
Тут tSite.MapName - это массив из 32-х однобайтовых символов, I := 0 to Length(name) не проверяется на превышение этого предела.
Это в принципе не верно:
Код
tSite.Length := MR.Length;
sizeof(TCreateSite) не равен sizeof(TMAPREGISTER).
Далее следует по максимуму анализировать коды возврата от функций. В частности mapGetMapInfo скорее всего не отработает, так как нумерация листов начинается с 1, а Вы указываете 0. В этом случае код возврата будет равен 0, а структуры MR : TMAPREGISTER и LR : TLISTREGISTER останутся непроинициализированными и могут содержать грязь.
Также повреждения памяти могут быть в других фрагментах кода, который тут не представлен.
Просьба на будущее - указывать версию среды разработки, версию GIS ToolKit и версию библиотек ГИС-ядра (gisacces.dll), а также под какую ОС какой разрядности ведется разработка. Также следует уточнить, Вы разрабатывает отдельное приложение или прикладную задачу для работы в ГИС Панорама или ГИС Оператор.
Евгений написал: tSite.MapName не может быть превышен, т.к. берется с основой карты.
Не гарантированно. Всегда лучше проверять. Рекомендуется использовать более безопасные функции, заполняющие выделенный Вами буфер с контролем заданного размера, например, mapGetMapNameEx. Имя карты в паспорте с ограничением в 32 символа - это, можно сказать, устаревшее поле в паспорте карты. Паспорт карты имеет возможность хранить и более длинное имя (смотря какая функция используется при создании), и даже имя в кодировке юникод. Поэтому, какой длины имя Вам вернулось, лучше все-таки проверить.
Цитата
Евгений написал: tSite.Length я не знаю какой размер задать, т.к. не создаю структуры TCREATESITE.
В Delphi указание в разделе VAR переменной заданного типа - "tSite : TCreateSite" - это и есть объявление локальной переменной типа TCreateSite, то есть реально выделение под нее памяти в стеке. Вы же используете остальные поля этой структуры. Поле Length используется для контроля, причиной Вашего exeception это не является, но это поле подлежит заполнению. tSite.Length := sizeof(tSite);
Цитата
Евгений написал: Разрабатывается прикладная задача для ГИС Оператор 11. За основу взят образец с sdk11. 32 разрядная версия.
Тогда все немного сложнее. Тут могут быть дополнительные ошибки в процессе "прикручивания" задачи к ГИС Оператору. Кроме того, поскольку Вы пишете на Delphi, надо смотреть корректность объявления прототипов функций (проверять на предмет их соответствия заголовочным файлам ядра в части объявления параметров и стандартов вызова). Заголовочные файлы содержатся в SDK в директории .\Include.
Примеры, как правильно должны выглядеть прототипы Вы можете посмотреть в исходных текстах GIS ToolKit (см. файлы *.inc).
function mapCreateAndAppendSite(map : HMAP;
const mapname:PChar;const rscname:PChar;
var createsite : TCREATESITE):HMap; stdcall;
external sGisAcces name 'mapCreateAndAppendSite';
Если Вы используете Delphi XE2 и выше, то тип PChar будет означать уже не указатель на строку в однобайтовой (ANSI) кодировке, а указатель на Unicode-строку.
Также необходимо следить, чтобы Вы работали именно с той библиотекой mapacces.dll, с которой работает ГИС Оператор.
А вообще ошибка exeception class $C0000005 может быть следствием очень и очень многих причин. Начиная от ошибок в коде (как правило рушащих память), заканчивая ошибками самой среды разработки (некорректная инсталляция, не крайний сервис-пак, ошибки в работе CodeGuard и т.д.). Также при разработке динамических библиотек эта ошибка возможна в следствие разных runtime-библиотек разрабатываемой DLL и вызывающего приложения. Разброс очень большой - Google
Поэтому рекомендую по возможности сначала отладить логику Вашей задачи в отдельном приложении (exe), а уже затем переносить ее в библиотеку (dll) и реализовывать в виде прикладной задачи ГИС Оператор. Если, конечно, это возможно.
Цитата
Евгений написал: Мне удалось получить доступ к созданию объектов на новой карте через mapOpenMap. Как-то не сразу дошло до меня его использовать.
Это, скорее всего, не решение задачи. Заменив функцию, Вы изменили слегка логику работы программы, значит перераспределили память по-другому. Если ошибка по памяти есть, она вылезет в другом месте.
Ну и как догадка - а Вы после того, как получаете HSITE методом mapCreateAndAppendSite, перед тем, как его использовать, случайно не закрываете основную карту?