На главную... Продукты | Технологии | Классификаторы | Проекты | Скачать | Цены| Форум | Статьи | Обучение | Контакты

Сохранение векторной карты в изображение c помощью LoadMapToPicture (C#)

Поиск  Пользователи  Правила  Войти
Форум » Настольные приложения » GIS ToolKit, GIS ToolKit Active, ГИС Конструктор для Windows
Страницы: 1
RSS
Сохранение векторной карты в изображение c помощью LoadMapToPicture (C#)
 
Задача: есть некий векторных площадной объект, который я хочу сохранить в tif или bmp формат

Использую GIS ToolKit Active v.12.0.1. При использовании v.12.0.0 программа не "вылетала", но и не производила создания изображения.

Проблема с выполнением процедуры LoadMapToPicture в результате чего возникает исключение System.AccessViolationException: 'Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.'

//инициализируем структуру фрагмента сохраняемой карты
               DFrame frame = new DFrame();
               //устанавливаем координаты фрагмента равными координатам выбранной области
               frame.X1 = xPointMin;
               frame.Y1 = yPointMin;
               frame.X2 = xPointMax;
               frame.Y2 = yPointMax;

               //кол-во бит на пиксел сохраняемого изображения (1, 8, 24-рекомендуемое значение)
               int bitcount = 24;
               //определяем разрешение(т/м) и масштаб карты
               int scale = MapScreenMain.MapScale;
               //определяем разрешение(т/д)
               double resolutionDPI = 508;
               //в одном метре 39,37 дюймов
               double sizeInchInMeter = 0.0254;
               //определяем разрешение(т/м)
               double resolutionDPM = resolutionDPI / sizeInchInMeter;
               //размер пикселя формируемого изображения в метрах на местности
               double sizePixelInMeter = scale / resolutionDPM;
               //размер формируемого изображения в метрах на местности по оси Y
               double deltaY = Math.Abs(frame.Y2 - frame.Y1);
               //ширина формируемого изображения в пикселях
               int width = (int)Math.Round( deltaY / sizePixelInMeter);
               //размер формируемого изображения в метрах на местности по оси X
               double deltaX = Math.Abs(frame.X2 - frame.X1);
               //высота формируемого изображения в пикселях
               int height = (int)Math.Round( deltaX / sizePixelInMeter);

               string NameSaveRst = "test1.bmp";
               string PathSaveRst = PathShell + NameSaveRst;
               //переводим имя сохраняемого растра/карты в формат IntPtr
               IntPtr filename = Marshal.StringToHGlobalAnsi(PathSaveRst);

                   //    Сохранить карту в формате BMP, Tiff, RSW
                   //    map        - карта,содержащая векторные, растровые и др. данные;
                   //    handle     - диалог сопровождения процесса обработки;
                   //    dframe     - фрагмент сохраняемой карты(в метрах на местности)
                   //    bitcount   - кол-во бит на пиксел сохраняемого изображения (1, 8, 24-рекомендуемое значение)
                   //    scale      - масштаб сохраняемого изображения
                   //    resolution - разрешающая способность сохраняемого изображения(т/м)
                   //    filename   - имя файла сохраняемого изображения (*.bmp, *.tif);
                   //    handleMainWin - должен быть равен нулю

                   //    При ошибке функция возвращает ноль
                   //    В СЛЕДУЮЩЕЙ СТРОЧКЕ И ВОЗНИКАЕТ ИСКЛЮЧЕНИЕ
                   if (RstAPI.LoadMapToPicture(MapScreenMain.MapHandle, (int)this.Handle, ref frame, bitcount, (int)scale, (int)resolutionDPM, filename, 0) == 0)
                   {
                       MessageBox.Show("Произошла ошибка создания BMP файла!");
                   }

------

Метод LoadMapToPicture импортируется из библиотеки gispicex.dll
       [DllImport(GisLibrary3, CharSet = CharSet.Ansi)]
       public static extern int LoadMapToPicture(int map, int handle, ref DFrame dframe, int bitcount, int scale, int resolution, IntPtr filename, int handleMainWin);

Может кто сталкивался с этой проблемой, в чём может быть причина?
Изменено: Алексей - 19.08.2019 13:10:46
 
Алексей, уточните, для какой платформы разрабатываете приложение - для x32, или x64?

В объявлении LoadMapToPicture у Вас неточность при описании параметров функции:
Цитата
Метод LoadMapToPicture импортируется из библиотеки gispicex.dll
       [DllImport(GisLibrary3, CharSet = CharSet.Ansi)]
       public static extern int LoadMapToPicture(int map, int handle, ref DFrame dframe, int bitcount, int scale, int resolution, IntPtr filename, int handleMainWin);

Обратите внимание на объявление функции LoadMapToPicture в файле MAPPICEX.H из состава  GIS ToolKit Active 12-ой версии:
Код
_PICIMP long int _PICAPI LoadMapToPicture(HMAP map,HMESSAGE handle,
                                 DFRAME * dframe, long bitcount,
                                 long scale, long resolution,
                                 const char* filename,
                                 HMESSAGE handleMainWin);

Параметр функции map имеет тип HMAP (maptype.h):
Код
#if defined(_M_X64) || defined(BUILD_DLL64)

typedef __int64   HMAP;    // ИДЕНТИФИКАТОР ОТКРЫТОЙ ВЕКТОРНОЙ КАРТЫ
                           // (УКАЗАТЕЛЬ НА TMapAccess)

#else

typedef long int  HMAP;    // ИДЕНТИФИКАТОР ОТКРЫТОЙ ВЕКТОРНОЙ КАРТЫ
                           // (УКАЗАТЕЛЬ НА TMapAccess)
#endif
Параметры функции handle и handleMainWin  имеют тип HMESSAGE (mapsyst.h):
Код
   #define HMESSAGE HWND
Для платформы x64 переменные типа HMAP и HWND не поместятся в int.
 
Для x64 на языке C#.

В примерах для языка C#, которые поставляются вместе с установочным дистрибутивом, например, в "Mapedit" используется именно int map
       [DllImport("gisu64acces.dll", EntryPoint = "mapGetNodeView")]
       private static extern int mapGetNodeView(int map);

в то время как в .H
_MAPIMP long int _MAPAPI mapGetNodeView(HMAP hMap);

буду благодарен за пояснения
 
Примеры исправим, int вместо HMAP - это пережиток прошлого. В GTK версии 12 это ошибка.
Все так, как Вам объяснил Dmitry_: типы HMAP, HSITE, HOBJ и другие типы GIS ToolKit, начинающиеся с H, являются типом HANDLE, то есть их размер равен размеру указателя.
Если такой параметр в функции описан как int, то это ошибка. Параметры идентификатора экземпляра класса работы с картой (HMAP), класса экземпляра работы с объектом (HOBJ) и т.п. должны быть описаны именно через типы (HMAP и HOBJ соответственно), а они уже в свою очередь должны быть определены исходя из разрядности системы.
 
Если я правильно понял, то должно получиться что-то следующее (C#)
Код
#if _WIN64
    using HMAP = System.Int64;
#else
    using HMAP = System.Int32;
#endif

using HWND = IntPtr;
using HMESSAGE = IntPtr;

public class RstAPI 
{
   public const string GisLibrary3 = "C:\\Windows\\SysWOW64\\gispicex.dll";

   [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
   public struct DFrame
   {
       public double X1;
       public double Y1;
       public double X2;
       public double Y2;
       public bool Empty
       {
           get { return (X1.Equals(0.0) && X2.Equals(0.0) && Y1.Equals(0.0) && Y2.Equals(0.0)); }
       }
   }

    //сохранить карту в формат BMP, TIFF, RSW
    [DllImport(GisLibrary3, CharSet = CharSet.Ansi)]
    public static extern long LoadMapToPicture(HMAP map, HMESSAGE handle, DFrame dframe, long bitcount, long scale, long resolution, IntPtr filename, HMESSAGE handleMainWin);

}

При вызове LoadMapToPicture
Код
//инициализируем структуру фрагмента сохраняемой карты
DFrame frame = new DFrame();
frame.X1 = minXX;
frame.Y1 = minYY;
frame.X2 = maxXX;
frame.Y2 = maxYY;

//переводим имя сохраняемого растра/карты в формат IntPtr
IntPtr filename = Marshal.StringToHGlobalAnsi(PathOrderFolder + "export.rsw");

if (RstAPI.LoadMapToPicture(mainMapView.MapHandle, this.Handle, frame, bitcount, scale, resolutionDPMInt, filename, this.Handle) == 0)
      {
      MessageBox.Show("Произошла ошибка");
      }
срабатывает исключение System.AccessViolationException: 'Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.'
 
Цитата
Алексей написал:
   //сохранить карту в формат BMP, TIFF, RSW
   [DllImport(GisLibrary3, CharSet = CharSet.Ansi)]
   public static extern long LoadMapToPicture(HMAP map, HMESSAGE handle, DFrame dframe, long bitcount, long scale, long resolution, IntPtr filename, HMESSAGE handleMainWin);

Параметр типа DFRAME в функцию LoadMapToPicture должен передаваться по указателю. Скорее всего, не хватает слова ref.

Цитата

//================================================-========================
//    Сохранить карту в формате BMP, Tiff, RSW
//    hmap       -  идентификатор открытых данных
//    handle     - диалог сопровождения процесса обработки;
//    dframe     - фрагмент сохраняемой карты(в метрах на местности)
//    bitcount   - кол-во бит на пиксел сохраняемого изображения (16, 24-рекомендуемое значение, 32)
//    scale      - масштаб сохраняемого изображения
//    resolution - разрешающая способность сохраняемого изображения(т/м)
//    filename   - имя файла сохраняемого изображения (*.bmp, *.tif);
//    handleMainWin - должен быть равен нулю
//    При ошибке функция возвращает ноль
//
//    Диалогу визуального сопровождения процесса обработки посылаются
//    сообщения:
//    -  (WM_PROGRESSBAR) Извещение об изменении состояния процесса
//       WPARAM - текущее состояние процесса в процентах (0% - 100%)
//       Если функция-отклик возвращает WM_PROGRESSBAR, то процесс завершается.
//
//    -  (WM_ERROR) Извещение об ошибке
//       LPARAM - указатель на структуру ERRORINFORMATION
//       Структура ERRORINFORMATION описана в picexprm.h,
//       WM_PROGRESSBAR и WM_ERROR - в maptype.h
//================================================-========================
_PICIMP long int _PICAPI LoadMapToPicture(HMAP hmap,HMESSAGE handle,
                                DFRAME * dframe, long bitcount,
                                long scale, long resolution,
                                const char* filename,
                                HMESSAGE handleMainWin);

_PICIMP long int _PICAPI LoadMapToPictureUn(HMAP map,HMESSAGE handle,
                                DFRAME * dframe, long bitcount,
                                long scale, long resolution,
                                const WCHAR* filename,
                                HMESSAGE handleMainWin);


Справочно:
при вызове MAPAPI объявить типы HMAP, HSITE, HOBJ и другие типы GIS ToolKit, начинающиеся с H, являются типом HANDLE, можно размером указателя (также как Вы объявили HWND через IntPtr).
 
Если объявить тип HMAP через IntPtr
Код
using HMAP = IntPtr;
объявление будет иметь следующий вид
Код
public static extern long LoadMapToPicture(HMAP map, HMESSAGE handle, ref DFrame dframe, long bitcount, long scale, long resolution, IntPtr filename, HMESSAGE handleMainWin)
первый параметр MapHandle (идентификатор открытой основной карты) имеет тип int, преобразуем в IntPtr и получаем вызов вида
Код
RstAPI.LoadMapToPicture((IntPtr)mainMapView.MapHandle, this.Handle, ref frame, bitcount, scale, resolutionDPMInt, filename, (IntPtr)0)
в результате исключение LoadMapToPicture разбалансировал стек. Вероятно, это вызвано тем, что управляемая сигнатура PInvoke не совпадает с неуправляемой целевой сигнатурой.
 
Цитата
Алексей написал:
первый параметр MapHandle (идентификатор открытой основной карты) имеет тип int, преобразуем в IntPtr и получаем вызов вида

Да, прошу прощения, я не очень точно выразился:
Цитата
Денис Вицко написал:
при вызове MAPAPI объявить типы HMAP, HSITE, HOBJ и другие типы GIS ToolKit, начинающиеся с H, являются типом HANDLE, можно размером указателя (также как Вы объявили HWND через IntPtr).
имелось в виду только MAPAPI, без использования компонент (в x32 можно преобразовать в IntPtr, а в x64 вообще компоненты использовать не стоит).

К сожалению, компоненты GIS ToolKit Active имеют проблемы работоспособности в x64 приложениях. В рамках одной *.ocx библиотеки не удается корректно реализовать методы с параметрами переменного размера в зависимости от разрядности. Вы уже и сами заметили, что MapView.MapHandle возвращает int, что x64 приведет к ошибке при выходе приложения из области "нижней" адресации памяти.
Пока однозначного решения данной проблемы у нас нет.
Гарантированно работать и в x32-, и в x64- разрядных приложениях может только код, основанный на вызовах MAPAPI.
Компоненты - только в x32.



Цитата
Алексей написал:
в результате исключение LoadMapToPicture разбалансировал стек. Вероятно, это вызвано тем, что управляемая сигнатура PInvoke не совпадает с неуправляемой целевой сигнатурой.

Это связано не с объявлением HMAP как IntPtr.
Проблема в описании параметров типа long. В C# не зависимо от разрядности проекта этот тип имеет длину 8 байт и реально является  типом long long, вопреки собственному определению типов данных от Microsoft.
В MAPAPI (как и в WINAPI) long - это integer (4 байта).

Кроме того, надо внимательно следить за платформой, под которую выполняется сборка проекта.
В C# установка активной целевой платформы сделана чрезвычайно неудобно и не всегда понятно, что собралось.
А платформу "AnyCPU" вообще лучше сразу удалить из опций проекта и решения, чтобы избежать путаницы.
Особенно, когда речь идет о вызовах неуправляемого кода и когда программа использует платформозависимые типы данных.


Вот рабочий код вызова LoadMapToPicture с HMAP=IntPtr:

Скрытый текст
Страницы: 1
Читают тему (гостей: 1)



© КБ Панорама, 1991-2024

Регистрируясь или авторизуясь на форуме, Вы соглашаетесь с Политикой конфиденциальности