ADN Open CIS
Сообщество программистов Autodesk в СНГ

19/12/2015

Чтение свойств чертежа (SummaryInfo) из внешнего приложения.

Вопрос:

Средствами ObjectARX и AutoCAD .NET API можно получить информацию о dwg-файле, которую записывает команда DWGPROPS. А можно ли прочитать эту информацию из внешнего C++ приложения без запуска AutoCAD?

Ответ:

Это возможно. Пример кода, который позволяет это сделать ниже:

Код - C++: [Выделить]
  1. //////////////////////////////////////////////////////////////////////////
  2. // Реализация чтения DwgProps для AutoCAD 2004...2016 (возможно и дальше,
  3. // если сохранится структура dwg-файла).
  4. //////////////////////////////////////////////////////////////////////////
  5.  
  6. #include <io.h>
  7. #include <sys/stat.h>
  8. #include <fcntl.h>
  9. #include <malloc.h>
  10. #include <stdlib.h>
  11. #include <vector>
  12. #include <string>
  13. //
  14. // Имена стандартных свойств чертежа
  15. //
  16. const char *stdPropNames[] = {
  17.   "title",
  18.   "subject",
  19.   "author",
  20.   "keywords",
  21.   "comments",
  22.   "lastSavedBy",
  23.   "revisionNumber",
  24.   "hyperlinkBase"
  25. };
  26.  
  27. class DwgProps
  28. {
  29.   struct record {
  30.     WORD len;
  31.     union {
  32.       char    c[32767];
  33.       wchar_t w[32767];
  34.     };
  35.   };
  36.  
  37. public:
  38.  
  39.     DwgProps() {
  40.       for (int i=0; i < sizeof(stdPropNames)/sizeof(stdPropNames[0]); i++)  {
  41.         m_stdProps.push_back("");
  42.       }
  43.       memset(bTotalEditingTime,0,sizeof(bTotalEditingTime));
  44.       memset(bCreateDateTime,0,sizeof(bCreateDateTime));
  45.       memset(bModifiedDateTime,0,sizeof(bModifiedDateTime));
  46.     };
  47.     ~DwgProps() {}
  48.  
  49.     //  data items
  50.     const char *title()          const    {return m_stdProps[0].c_str(); }
  51.     const char *subject()        const    {return m_stdProps[1].c_str(); }
  52.     const char *author()         const    {return m_stdProps[2].c_str(); }
  53.     const char *keywords()       const    {return m_stdProps[3].c_str(); }
  54.     const char *comments()       const    {return m_stdProps[4].c_str(); }
  55.     const char *lastSavedBy()    const    {return m_stdProps[5].c_str(); }
  56.     const char *revisionNumber() const    {return m_stdProps[6].c_str(); }
  57.     const char *hyperlinkBase()  const    {return m_stdProps[7].c_str(); }
  58.     const char *customName(int idx) const  {
  59.       return ((idx >= 0 && idx < (int)m_custPropNames.size())?m_custPropNames[idx].c_str():0);
  60.     }
  61.     const char *customValue(int idx) const {
  62.       return ((idx >= 0 && idx < (int)m_custPropValues.size())?m_custPropValues[idx].c_str():0);
  63.     }
  64.     const char *customValue(const char *name) const  {
  65.       for (int i=0; i < (int)m_custPropNames.size(); i++) {
  66.         if (m_custPropNames[i] == name) return m_custPropValues[i].c_str();
  67.       }
  68.       return 0;
  69.     }
  70.    
  71.     int    customNumber() const { return (int) m_custPropNames.size(); }
  72.     ULONG      inDwg()   { return ReadDiffDate(bTotalEditingTime); }
  73.     SYSTEMTIME created() { return ReadDate(bCreateDateTime); }
  74.     SYSTEMTIME updated() { return ReadDate(bModifiedDateTime); }
  75.  
  76.     const void DateToString(char *buf, SYSTEMTIME tm)
  77.     {
  78.       sprintf( buf,
  79.         "%d-%02d-%02d %02d:%02d:%02d.%03d",
  80.         tm.wYear, tm.wMonth, tm.wDay,
  81.         tm.wHour, tm.wMinute, tm.wSecond, tm.wMilliseconds);
  82.     }
  83.  
  84.     const void DiffDateToString(char *buf, ULONG tDiff)
  85.     {
  86.       int days = tDiff / (24*60*60*1000);
  87.       tDiff -= days * (24*60*60*1000);
  88.       int hours = tDiff / (60*60*1000);
  89.       tDiff -= hours * (60*60*1000);
  90.       int minutes = tDiff / (60*1000);
  91.       tDiff -= minutes * (60*1000);
  92.       int seconds = tDiff / 1000;
  93.       tDiff -= seconds * (1000);
  94.       int mseconds = tDiff;
  95.       sprintf( buf,
  96.         "Days:%d Hours:%d Minutes:%d Seconds:%d Milliseconds:%d",
  97.         days, hours, minutes, seconds, mseconds);
  98.     }
  99.     int load(const char * fname)
  100.     {
  101.       bool unicode = false;
  102.       int h;
  103.       char buf[32767]; memset(buf,0,sizeof(buf));
  104.       if ((h = _open(fname,_O_BINARY|_O_RDONLY)) == -1)
  105.         return 0;
  106.       char ACADVER[7];
  107.       if (_read(h,ACADVER,sizeof(ACADVER)) <= 0) {
  108.         _close(h); return 0;
  109.       }
  110.       if (atoi(ACADVER+2) < 1018) {  // AutoCAD R14,2000...2002 обрабатывать не будем
  111.         _close(h); return 0;
  112.       }
  113.       if (atoi(ACADVER+2) >= 1021) { // AutoCAD 2007... строки в Unicode
  114.         unicode = true;
  115.       }
  116.  
  117.       // Указатель перемещаем на WORD, содержащий смещение DwgProps
  118.       if (_lseek(h,0x20,SEEK_SET) == -1) {
  119.         _close(h); return 0;
  120.       }
  121.       // Считываем смещение DwgProps
  122.       WORD offset_dwgprops = 0;
  123.       if (_read(h,&offset_dwgprops,sizeof(offset_dwgprops)) <= 0) {
  124.         _close(h); return 0;
  125.       }
  126.       long begin_offset = offset_dwgprops, cur_offset = offset_dwgprops;
  127.       // Устанавливаем указатель на начало DwgProps
  128.       if (_lseek(h,offset_dwgprops,SEEK_SET) == -1) {
  129.         _close(h); return 0;
  130.       }
  131.       // Теперь можно читать длины и сами строки:
  132.       record rec;
  133.       for (int i=0; i < sizeof(stdPropNames)/sizeof(stdPropNames[0]); i++) {
  134.         if (_read(h,&rec,sizeof(record)) == -1) {
  135.           _close(h); return 0;
  136.         }
  137.         if (unicode) {
  138.           WideCharToMultiByte(CP_ACP,0,rec.w,rec.len,buf,rec.len,0,NULL);
  139.           m_stdProps[i] = buf;
  140.         } else {
  141.           m_stdProps[i] = rec.c;
  142.         }
  143.         cur_offset += (rec.len*((unicode)?2:1) + sizeof(rec.len));
  144.         if (_lseek(h,cur_offset,SEEK_SET) == -1) {
  145.           _close(h); return 0;
  146.         }
  147.       }
  148.       if (_read(h,&bTotalEditingTime,sizeof(bTotalEditingTime)) == -1) {
  149.         _close(h); return 0;
  150.       }
  151.       if (_read(h,&bCreateDateTime,sizeof(bCreateDateTime)) == -1) {
  152.         _close(h); return 0;
  153.       }
  154.       if (_read(h,&bModifiedDateTime,sizeof(bModifiedDateTime)) == -1) {
  155.         _close(h); return 0;
  156.       }
  157.  
  158.       cur_offset += (sizeof(bTotalEditingTime)+ sizeof(bCreateDateTime) + sizeof(bModifiedDateTime));
  159.  
  160.       if (_lseek(h,cur_offset,SEEK_SET) == -1) {
  161.         _close(h); return 0;
  162.       }
  163.  
  164.       // Читаем количество собственных (custom) переменных
  165.  
  166.       WORD nCust = 0;
  167.  
  168.       if (_read(h,&nCust,sizeof(nCust)) <= 0) { _close(h); return 0; }
  169.  
  170.       cur_offset += sizeof(WORD);
  171.  
  172.       for (int i=0; i < nCust; i++) {
  173.         // Считываем имя переменной
  174.         if (_read(h,&rec,sizeof(record)) == -1) {_close(h); return 0;}
  175.         if (unicode) {
  176.           WideCharToMultiByte(CP_ACP,0,rec.w,rec.len,buf,rec.len,0,NULL);
  177.           m_custPropNames.push_back(buf);
  178.         } else {
  179.           m_custPropNames.push_back(rec.c);
  180.         }
  181.  
  182.         cur_offset += (rec.len*((unicode)?2:1) + sizeof(rec.len));
  183.  
  184.         if (_lseek(h,cur_offset,SEEK_SET) == -1) {
  185.           _close(h); return 0;
  186.         }
  187.         if (_read(h,&rec,sizeof(record)) == -1) {_close(h); return 0;}
  188.         if (unicode) {
  189.           WideCharToMultiByte(CP_ACP,0,rec.w,rec.len,buf,rec.len,0,NULL);
  190.           m_custPropValues.push_back(buf);
  191.         } else {
  192.           m_custPropValues.push_back(rec.c);
  193.         }
  194.  
  195.         cur_offset += (rec.len*((unicode)?2:1) + sizeof(rec.len));
  196.         if (_lseek(h,cur_offset,SEEK_SET) == -1) {_close(h); return 0;}
  197.       }
  198.       _close(h);
  199.       return 1;
  200.     }
  201.    
  202. private:
  203.     //  data
  204.     std::vector<std::string> m_stdProps;
  205.     std::vector<std::string> m_custPropNames;
  206.     std::vector<std::string> m_custPropValues;
  207.     byte bTotalEditingTime[8];
  208.     byte bCreateDateTime[8];
  209.     byte bModifiedDateTime[8];
  210.     SYSTEMTIME minDate, maxDate;
  211.     //
  212.     // Преобразование даты/времени из юлианского календаря
  213.     //
  214.     SYSTEMTIME FromJulian(ULONG days)
  215.     {
  216.       FILETIME fmin = {0, 0} , fmax = {0x7fffffff, 0xffffffff} ;
  217.       FileTimeToSystemTime(&fmin, &minDate);  FileTimeToSystemTime(&fmax, &maxDate);
  218.       SYSTEMTIME s; memset(&s,0,sizeof(s));
  219.       if (days < 0x1a4452) return minDate;
  220.       if (days > 0x51fe2c) return maxDate;
  221.       int j = days + 32044;
  222.       int g = j / 146097;
  223.       int dg = j % 146097;
  224.       int c = (((dg / 36524) + 1) * 3) / 4;
  225.       int dc = dg - (c * 36524);
  226.       int b = dc / 1461;
  227.       int db = dc % 1461;
  228.       int a = (((db / 365) + 1) * 3) / 4;
  229.       int da = db - (a * 365);
  230.       int y = (((g * 400) + (c * 100)) + (b * 4)) + a;
  231.       int m = (((da * 5) + 308) / 153) - 2;
  232.       int d = (da - (((m + 4) * 153) / 5)) + 0x7a;
  233.       int year = (y - 4800) + ((m + 2) / 12);
  234.       int month = ((m + 2) % 12) + 1;
  235.       int day = d + 1;
  236.       s.wYear = year;
  237.       s.wMonth = month;
  238.       s.wDay = day;
  239.       s.wHour = 2;
  240.       s.wMinute = 0;
  241.       s.wSecond = 0;
  242.       s.wDayOfWeek = 0;
  243.       s.wMilliseconds = 0;
  244.       return s;
  245.     }
  246.     //
  247.     // Добавление дробной части (миллисекунд)
  248.     //
  249.     SYSTEMTIME addMilliSecs(SYSTEMTIME s, double mseconds) {
  250.       FILETIME f; SystemTimeToFileTime(&s, &f);
  251.       ULARGE_INTEGER u;
  252.       memcpy(&u, &f, sizeof(u));
  253.       ULONGLONG mmsec = mseconds * 10000;
  254.       u.QuadPart += mmsec;
  255.       memcpy(&f, &u, sizeof(f));
  256.       FileTimeToSystemTime(&f, &s);
  257.       return s;
  258.     }
  259.     //
  260.     // Чтение даты/времени
  261.     //
  262.     const SYSTEMTIME ReadDate(byte *src)
  263.     {
  264.       ULONG days = *((ULONG *)(src)); src += 4;
  265.       ULONG fraction = *((ULONG *)(src)); src += 4;
  266.       SYSTEMTIME tm = FromJulian(days);
  267.       if (tm.wYear == maxDate.wYear)
  268.         return tm;
  269.       return addMilliSecs(tm,fraction);
  270.     }
  271.     //
  272.     // Чтение интервала редактирования
  273.     //
  274.     const ULONG ReadDiffDate(byte* src)
  275.     {
  276.       ULONG days = *((ULONG *)(src)); src += 4;
  277.       ULONG fraction = *((ULONG *)(src)); src += 4;
  278.       ULONG diff = days * 24 * 60 * 60 * 1000 + fraction;
  279.       return diff;
  280.     }
  281.  
  282.  
  283. };
  284.  
  285. ////-----------------------------------------
  286. //// Пример использования класса DwgProps
  287. ////-----------------------------------------
  288. //#include "stdafx.h"
  289. //#include <conio.h>
  290. //#include <stdio.h>
  291. //#include <string.h>
  292. //#include <wtypes.h>
  293. //#include <time.h>
  294. //#include "DwgProps.h"
  295. //
  296. //
  297. //const char * valid(const char *s)
  298. //{
  299. //  return s ? s : "";
  300. //}
  301. //
  302. //void main(int argc, char *argv[])
  303. //{
  304. //  DwgProps p;
  305. //
  306. //  if ( argc < 2 )
  307. //  {
  308. //    fprintf(stderr, "Usage: dwgprops file [file ...]\n");
  309. //    return;
  310. //  }
  311. //
  312. //  //  loop over files
  313. //  for ( int f = 1; f < argc; f++ )
  314. //  {
  315. //    printf("%s\n", argv[f]);
  316. //
  317. //    if ( p.load(argv[f]) )
  318. //    {
  319. //      //  print list of tags
  320. //      printf("  Title:         [%s]\n", valid(p.title()));
  321. //      printf("  Subject:       [%s]\n", valid(p.subject()));
  322. //      printf("  Author:        [%s]\n", valid(p.author()));
  323. //      printf("  Comments:      [%s]\n", valid(p.comments()));
  324. //      printf("  Keywords:      [%s]\n", valid(p.keywords()));
  325. //      printf("  HyperlinkBase: [%s]\n", valid(p.hyperlinkBase()));
  326. //      printf("  LastSavedBy:   [%s]\n", valid(p.lastSavedBy()));
  327. //      printf("  RevisionNo.:   [%s]\n", valid(p.revisionNumber()));
  328. //      char buffer[ 256 ];
  329. //      p.DiffDateToString(buffer, p.inDwg());
  330. //      printf("  Edit time: %s\n", buffer);
  331. //      p.DateToString(buffer, p.created());
  332. //      printf("  Created:       [%s]\n", buffer);
  333. //      p.DateToString(buffer, p.updated());
  334. //      printf("  Updated:       [%s]\n", buffer);
  335. //      for ( int i = 0; i < p.customNumber(); i++ ) {
  336. //        printf("  Custom Name[%d]:   [%s]\n", i, valid(p.customName(i)));
  337. //        printf("  Custom Value[%d]:  [%s]\n", i, valid(p.customValue(i)));
  338. //      }
  339. //    }
  340. //  }
  341. //}
  342.  

Автор: Александр Ривилис

Обсуждение: http://adn-cis.org/forum/index.php?topic=3291

Опубликовано 19.12.2015
Отредактировано 19.12.2015 в 04:41:53