Продолжаю войну с меню…

Как было сказано в статьях, упомянутых в Последовательность загрузки приложений, можно организовать загрузку своих приложений, используя mnl-файлы. Чем я до поры до времени успешно и пользовался.

Но, к сожалению, не все так легко и просто.

Загрузка частичных меню вносит изменения в файл основного меню - хотим мы того или нет. Казалось бы, все просто: организовываем несколько профилей AutoCAD и в каждый загружаем разный набор частичных меню. Так?

Не совсем. Если внимательно посмотреть на путь, указанный к основному файлу меню в разных профилях, то можно увидеть, что по умолчанию путь будет один и тот же.

Поэтому, если планируется тестирование нескольких файлов меню, придется либо мириться с бардаком в загруженных частичных файлах меню, либо создавать отдельный каталог, в который копировать "чистые" файлы основного меню и сопутствующие им (т.е. mnl, dll), устанавливать эту копию в качестве основного файла меню и уже потом подгружать свои файлы. Конечно, можно и третий / четвертый / пятый путь придумать, но мне было лень :) Так что я выбирал между двумя.

Меня бардак не сильно устраивает, поэтому я пошел по второму пути. Идеальным вариантом, конечно, был бы "сохранить где-то в определенном месте абсолютно чистые файлы меню", но ситуации бывают разные. Именно для этих разных ситуаций и будем "рисовать" код.

Как всегда, перед вызовом VLIDE не помешает подумать - что и в каком виде будем обрабатывать и передавать.

Нам необходимо будет определить каталог, в котором хранятся все файлы меню - и касается это прежде всего, конечно, основного меню. Файлы стандартных частичных меню туда закидывать особого смысла лично я не вижу, поэтому про них просто забудем :)

Также в качестве параметра понадобится имя файла погружаемого собственного меню. Было бы неплохо также и имя группы меню, которое он импортирует, но это не критично. Для упрощения будем считать, что нам известно не только имя файла, но и имя импортируемой группы меню - так работать значительно проще.

Вроде бы все, ничего не забыл. Поехали :)

Итак, прежде всего - определяем каталог, в котором будут храниться файлы основного меню и нашего тестируемого кусочка. Я обычно для таких целей использую каталог %AppData% - еще ни разу не встречал ситуации, чтобы туда нельзя было бы выполнять запись. Но просто %AppData% использовать по меньшей мере неразумно, поэтому я там организовываю подкаталог (kpblc), потом имя приложения (ну, например, LispRu). Дальше, учитывая, что меню обычно тестируется как минимум на 2-3 версиях AutoCAD, а то и вертикальные решения начинают вносить свою лепту, указываю имя приложения с учетом его версии, локализации и разрядности. Так, например, для AutoCAD 2014 x64 Eng следующим подкаталогом будет ACA2014x64En, для AutoCAD Civil 3D 2014 Rus - ACAC2014x64Ru и т.п.

Таким образом, получается, что надо создавать каталог вида

1
%AppData%\kpblc\LispRu\ACA2014x64Ru

Все? Нет, не все. У AutoCAD могут быть разные профили (смотрим справку, ключи вызова). Так что понадобится еще добавить имя профиля AutoCAD, не забывая про недопустимые символы. Ну и для полного счастья остается добавить подкаталог menu, откуда собственно и будет все наше счастье загружаться.

Значит, результатом будет

1
%AppData%\kpblc\LispRu\{Приложение}{Версия}{Разрядность}{Локализация}\{ИмяПрофиля}\menu

Ффух, теперь уж точно все касательно каталога. Поскольку подобная информация может потребоваться не раз и не два, возникает вопрос - то ли вычислять ее, то ли где-то хранить. Я пока предпочитаю вычислять.

Сначала вычислим путь, а уже потом будем его создавать :)

1. Вычисляем %AppData%. Казалось бы, тут ничего сложного нет:

1
(getenv "AppData")

должен вернуть все что надо. Но, к сожалению, именно должен. А не обязан. На некоторых версиях Windows вместо ожидаемого, к примеру

1
C:\Document and Settings\DomainUser

можно запросто получить

1
C:\DOCUME~1\DOMAIN~2

На Windows 7 я такого, конечно, уже не встречал, но предусмотреть подобное поведение не помешает.

Итак, для того, чтобы получить каталог %AppData%, сначала попробуем проанализировать (getenv "AppData") на предмет содержания в нем символов ~, и, если таковые будут обнаружены, полезем в реестр:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
(defun _kpblc-get-path-appdata-current-user (/)
                                            ;|
*    Получение пути установок, хранимых на локальной машине. (CurrUser)
|;

  (strcat (_kpblc-dir-path-and-splash
            (cond
              ((not (wcmatch (getenv "AppData") "*~*"))
               (getenv "AppData")
               )
              (t
               (_kpblc-dir-path-and-splash
                 (vl-registry-read
                   "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
                   "AppData"
                   ) ;_ end of vl-registry-read
                 ) ;_ end of _kpblc-dir-path-and-splash
               )
              ) ;_ end of cond
            ) ;_ end of _kpblc-dir-path-and-splash
          "kpblc"
          ) ;_ end of strcat
  ) ;_ end of defun

Тут используется одна служебная функция, возвращающая каталог с гарантированным слешем на конце:

1
2
3
4
5
6
7
8
9
10
(defun _kpblc-dir-path-and-splash (path)
                                  ;|
*    Возвращает путь со слешем в конце
*    Параметры вызова:
*  path  - обрабатываемый путь
*    Примеры вызова:
(_kpblc-dir-path-and-splash "c:\\kpblc-cad")  ; "c:\\kpblc-cad\"
|;

  (strcat (vl-string-right-trim "\" path) "\")
  ) ;_ end of defun

Вспомним, что надо получить в результате (я время от времени буду напоминать это дело):

1
%AppData%\kpblc\LispRu\{Приложение}{Версия}{Разрядность}{Локализация}\{ИмяПрофиля}\menu

Теперь пришла очередь {Приложение}. Я пошел по пути получения имени приложения из реестра и последующего его преобразования в более короткий и понятный вид.

Для преобразования понадобятся две функции: преобразование строки в список (обратная задача прямо тут не понадобится):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
(defun _kpblc-conv-string-to-list (string separator / i)
                                  ;|
*    Функция разбора строки. Возвращает список либо точечную пару.
*    Параметры вызова:
*  string    разбираемая строка
*  separator  символ, используемый в качестве разделителя частей
*    Примеры вызова:
(_kpblc-conv-string-to-list "1;2;3;4;5;6" ";")  ;'(1 2 3 4 5 6)
(_kpblc-conv-string-to-list "1;2" ";")    ;'(1 2)
*    За основу взяты уроки Евгения Елпанова по рекурсиям
|;

  (cond
    ((= string "") nil)
    ((vl-string-search separator string)
     ((lambda (/ pos res)
        (while (setq pos (vl-string-search separator string))
          (setq res    (cons (substr string 1 pos) res)
                string (substr string (+ (strlen separator) 1 pos))
                ) ;_ end of setq
          ) ;_ end of while
        (reverse (cons string res))
        ) ;_ end of lambda
      )
     )
    ((wcmatch (strcase string) (strcat "*" (strcase separator) "*"))
     ((lambda (/ pos res _str prev)
        (setq pos  1
              prev 1
              _str (substr string pos)
              ) ;_ end of setq
        (while (<= pos (1+ (- (strlen string) (strlen separator))))
          (if ;; (wcmatch (strcase (substr string pos)) (strcase (strcat separator "*")))
              (wcmatch (strcase (substr string pos (strlen separator))) (strcase separator))
            (setq res    (cons (substr string 1 (1- pos)) res)
                  string (substr string (+ (strlen separator) pos))
                  pos    0
                  ) ;_ end of setq
            ) ;_ end of if
          (setq pos (1+ pos))
          ) ;_ end of while
        (if (< (strlen string) (strlen separator))
          (setq res (cons string res))
          ) ;_ end of if
        (if (or (not res) (= _str string))
          (setq res (list string))
          (reverse res)
          ) ;_ end of if
        ) ;_ end of lambda
      )
     )
    (t (list string))
    ) ;_ end of cond
  ) ;_ end of defun

Получим собственно имя приложения. Читать будем из HKEY_LOCAL_MACHINE\Software\Autodesk\<И что-то тут>. Учтем по ходу дела тот факт, что, например, в Civil 3D или AutoCAD Architecture есть уникальные ключи, в которых хранится короткое имя приложения (в AutoCAD таких ключей, например, нет).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
(defun _kpblc-get-acad-product-name (/ res)
                                    ;|
*    Возвращает имя приложения, с указанием разрядности и локализации
|;

  (strcat (cond
            ((setq res (vl-registry-read (strcat "HKEY_LOCAL_MACHINE\" (vlax-product-key)) "ProductNameShort"))
             (vl-string-subst "
" " " res)
             )
            ((setq res (vl-registry-read (strcat "
HKEY_LOCAL_MACHINE\" (vlax-product-key)) "ProductName"))
             (apply (function strcat)
                    (vl-remove-if-not
                      (function (lambda (x) (wcmatch (strcase x) "
*CAD,####")))
                      (_kpblc-conv-string-to-list res "
")
                      ) ;_ end of vl-remove-if-not
                    ) ;_ end of apply
             )
            ) ;_ end of cond
          "
x"
          (if (wcmatch (getvar "
platform") "*x64*")
            "
64"
            "
32"
            ) ;_ end of if
          (cond
            ((= (vl-registry-read (strcat "
HKEY_LOCAL_MACHINE\" (vlax-product-key)) "LocaleId") "409") "En")
            ((= (vl-registry-read (strcat "
HKEY_LOCAL_MACHINE\" (vlax-product-key)) "LocaleId") "419") "Ru")
            (t "
UnKnown")
            ) ;_ end of cond
          ) ;_ end of strcat
  ) ;_ end of defun

Вызов функции в AutoCAD 2014 x64 Eng вернет "AutoCAD2014x64Eng", Civil 3D 2014 x64 Rus - "C3D2014x64Ru" и т.п.

Теперь имя профиля. Вроде бы и тут ничего сложного быть не должно - (getvar "cprofile") и ура. Но в имени профиля запросто могут подержаться символы, неподдерживаемые файловой системой (самый яркий пример - <<профиль без имени>>. Имя профиля содержит запрещенных символы < и >). То есть, получив имя профиля, оттуда надо убрать неправильные символы:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(defun _kpblc-get-profile-name ()
                               ;|
*    ЗАмена стандартному (getvar "cprofile")
|;

  (vl-list->string
    (vl-remove-if-not
      (function
        (lambda (x)
          (or (<= 48 x 57)
              (<= 65 x 90)
              (<= 97 x 122)
              (= x 32)
              (<= 224 x 255)
              (<= 192 x 223)
              ) ;_ end of or
          ) ;_ end of LAMBDA
        ) ;_ end of function
      (vl-string->list (getvar "cprofile"))
      ) ;_ end of vl-remove-if
    ) ;_ end of VL-LIST->STRING
  ) ;_ end of defun

Ну и напоследок - собственно создание каталога.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(defun _kpblc-dir-create (path / tmp)
                         ;|
*    Гарантированное создание каталога.
*    Параметры вызова:
  path  создаваемый каталог
|;

  (cond
    ((vl-file-directory-p path) path)
    ((setq tmp (_kpblc-dir-create (vl-filename-directory path)))
     (vl-mkdir
       (strcat tmp
               "\"
               (vl-filename-base path)
               (cond ((vl-filename-extension path))
                     (t "
")
                     ) ;_ end of cond
               ) ;_ end of strcat
       ) ;_ end of vl-mkdir
     (if (vl-file-directory-p path)
       path
       ) ;_ end of if
     )
    ) ;_ end of cond
  ) ;_ end of defun

Теперь в каталог, созданный через

1
2
3
4
5
6
7
8
9
(_kpblc-dir-create
  (strcat (_kpblc-get-path-appdata-current-user)
          "\\LispRu\"
          (_kpblc-get-acad-product-name)
          "
\"
          (_kpblc-get-profile-name)
          "
\\menu"
          ) ;_ end of strcat
  ) ;_ end of _kpblc-dir-create

надо будет копировать основной файл меню (который придется вычислять), его сопутствующие файлы (dll / mnl),и загружаемые файлы частичных меню (не забывая про те же dll, mnl и удаление - на всякий случай - mnr и mnc).

После копирования файла основного меню я сначала допустил ошибку: сразу устанавливал копию в качестве основного файла меню. Даже при условии программной загрузки остальных частичных файлов меню вид AutoCAD'а мог накрыться. Проблема кроется в несохраненном рабочем пространстве.

Т.е. перед выполнением следующих шагов надо а) получить текущее значение системной переменной WSCURRENT; б) сохранить рабочее пространство; в) установить новый файл основного меню; г) восстановить WSCURRENT.

Позволю себе пофилонить и полностью все проверки не прописывать (ну, например, я принципиально "забыл" о существовании AutoCAD версий до 2005 включительно).

Для работы понадобятся еще 3 функции - преобразования указателей в ename, в vla и vla в список. Конечно, можно поизвращаться и без них обойтись, но моя практика показала необходимость подобных функций:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
(defun _kpblc-conv-ent-to-ename (ent_value / _lst)
                                ;|
*    Функция преобразования полученного значения в ename
*    Параметры вызова:
*  ent_value  значение, которое надо преобразовать в примитив. Может
*      быть именем примитива, vla-указателем или просто
*      списком.
*      Если не принадлежит ни одному из указанных типов,
*      возвращается nil
*    Примеры вызова:
(_kpblc-conv-ent-to-ename (entlast))
(_kpblc-conv-ent-to-ename (vlax-ename->vla-object (entlast)))
|;

  ;; "_kpblc-conv-ent-to-ename")
  (cond
    ((= (type ent_value) 'vla-object)
     (vlax-vla-object->ename ent_value)
     )
    ((= (type ent_value) 'ename) ent_value)
    ((and (= (type ent_value) 'str) (handent ent_value) (entget (handent ent_value)))
     (handent ent_value)
     )
    ((and (= (type ent_value) 'str) (handent ent_value) (tblobjname "style" ent_value))
     (tblobjname "style" ent_value)
     )
    ((and (= (type ent_value) 'str) (handent ent_value) (tblobjname "dimstyle" ent_value))
     (tblobjname "dimstyle" ent_value)
     )
    ((and (= (type ent_value) 'str) (handent ent_value) (tblobjname "block" ent_value))
     (tblobjname "block" ent_value)
     )
    ((and (= (type ent_value) 'list) (cdr (assoc -1 ent_value))) (cdr (assoc -1 ent_value)))
    (t nil)
    ) ;_ end of cond
  ) ;_ end of defun

(defun _kpblc-conv-ent-to-vla (ent_value / res)
                              ;|
*    Функция преобразования полученного значения в vla-указатель.
*    Параметры вызова:
*  ent_value  значение, которое надо преобразовать в указатель. Может
*      быть именем примитива, vla-указателем или просто
*      списком.
*      Если не принадлежит ни одному из указанных типов,
*      возвращается nil
*    Примеры вызова:
(_kpblc-conv-ent-to-vla (entlast))
(_kpblc-conv-ent-to-vla (vlax-ename->vla-object (entlast)))
|;

  (cond
    ((= (type ent_value) 'vla-object) ent_value)
    ((= (type ent_value) 'ename) (vlax-ename->vla-object ent_value))
    ((setq res (_kpblc-conv-ent-to-ename ent_value))
     (vlax-ename->vla-object res)
     )
    ) ;_ end of cond
  ) ;_ end of defun

(defun _kpblc-conv-vla-to-list (value / res)
                               ;|
*    Преобразовывает vlax-variant или vlax-safearray в список.
|;

  (cond
    ((listp value)
     (mapcar (function _kpblc-conv-vla-to-list) value)
     )
    ((= (type value) 'variant)
     (_kpblc-conv-vla-to-list (vlax-variant-value value))
     )
    ((= (type value) 'safearray)
     (if (>= (vlax-safearray-get-u-bound value 1) 0)
       (_kpblc-conv-vla-to-list (vlax-safearray->list value))
       ) ;_ end of if
     )
    ((and (member (type value) (list 'ename 'str 'vla-object))
          (= (type (_kpblc-conv-ent-to-vla value)) 'vla-object)
          (vlax-property-available-p (_kpblc-conv-ent-to-vla value) 'count)
          ) ;_ end of and
     (vlax-for sub (_kpblc-conv-ent-to-vla value)
       (setq res (cons sub res))
       ) ;_ end of vlax-for
     )
    (t value)
    ) ;_ end of cond
  ) ;_ end of defun

В результате получается:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
(defun _kpblc-menu-update2 (/ loc_dir main_menu)
                           ;|
*    Обновление файла меню
|;

  (setq loc_dir   (_kpblc-dir-create
                    (strcat (_kpblc-get-path-appdata-current-user)
                            "\\LispRu\"
                            (_kpblc-get-acad-product-name)
                            "
\"
                            (_kpblc-get-profile-name)
                            "
\\menu"
                            ) ;_ end of strcat
                    ) ;_ end of _kpblc-dir-create
        main_menu (vla-get-menufile (vla-get-files (vla-get-preferences (vlax-get-acad-object))))
        ) ;_ end of setq
  (if (/= (_kpblc-dir-path-and-splash (strcase (vl-filename-directory main_menu)))
          (_kpblc-dir-path-and-splash (strcase loc_dir))
          ) ;_ end of /=
    (progn
      ;; Каталоги не совпадают. Надо копировать и устанавливать новый основной файл меню
      ;; не забывая про все остальное

      ;; Удаляем старые варианты,- вдруг они там есть
      (foreach file (vl-directory-files loc_dir (strcat (vl-filename-base main_menu) "
.*") 1)
        (vl-file-delete (strcat (_kpblc-dir-path-and-splash loc_dir) file))
        ) ;_ end of foreach

      ;; Теперь копируем из текущего положения основного файла меню все необходимое
      (foreach file (vl-remove-if-not
                      (function (lambda (x)
                                  (wcmatch (strcase (vl-string-trim "
." (vl-filename-extension x)))
                                           "
CUI,CUIX,MNL,MNS,MNU,DLL,MNL"
                                           ) ;_ end of wcmatch
                                  ) ;_ end of lambda
                                ) ;_ end of function
                      (vl-directory-files
                        (vl-filename-directory main_menu)
                        (strcat (vl-filename-base main_menu) "
.*")
                        1
                        ) ;_ end of vl-directory-files
                      ) ;_ end of vl-remove-if-not
        (vl-file-copy
          (strcat (_kpblc-dir-path-and-splash (vl-filename-directory main_menu))
                  file
                  ) ;_ end of strcat
          (strcat (_kpblc-dir-path-and-splash loc_dir) file)
          ) ;_ end of vl-file-copy
        ) ;_ end of foreach

      ;; Теперь получаем список уже загруженных файлов частичных меню.
      ;; Потом мы их снова загрузим
      ;; Получим общий список и из него исключим файл основного меню,
      ;; и файлы меню в loc_dir
      (setq partial_menus
             (vl-remove-if
               (function
                 (lambda (x)
                   (or (= (strcase (cdr (assoc "
name" x)))
                          (strcase (vl-filename-base main_menu))
                          ) ;_ end of =
                       (wcmatch (strcase (vl-filename-directory (cdr (assoc "
name" x))))
                                (strcat (strcase loc_dir "
*"))
                                ) ;_ end of wcmatch
                       ) ;_ end of or
                   ) ;_ end of lambda
                 ) ;_ end of function
               (mapcar
                 (function
                   (lambda (x)
                     (list
                       (cons "
name" (vla-get-name x))
                       (cons "
file" (vla-get-menufilename x))
                       ) ;_ end of list
                     ) ;_ end of lambda
                   ) ;_ end of function
                 (_kpblc-conv-vla-to-list
                   (vla-get-menugroups (vlax-get-acad-object))
                   ) ;_ end of _kpblc-conv-vla-to-list
                 ) ;_ end of mapcar
               ) ;_ end of vl-remove-if
            ) ;_ end of setq

      ;; Сохраняем текущее рабочее пространство
      (if (setq wscurrent (getvar "
wscurrent"))
        (command "
_.wssave" wscurrent "_y")
        ) ;_ end of if

      ;; Меняем основной файл меню
      (vla-load (vla-get-menugroups (vla-get-activedocument (vlax-get-acad-object)))
                (findfile (strcat (_kpblc-dir-path-and-splash loc_dir)
                                  (car (vl-remove-if
                                         (function (lambda (x) (wcmatch (strcase x) "
*.bak.cui*")))
                                         (vl-directory-files loc_dir (strcat (vl-filename-base main_menu) "
.cui*"))
                                         ) ;_ end of vl-remove-if
                                       ) ;_ end of car
                                  ) ;_ end of strcat
                          ) ;_ end of findfile
                :vlax-true
                ) ;_ end of vla-load

      (foreach item partial_menus
        (vl-catch-all-apply
          (function
            (lambda ()
              (vla-load (vla-get-menugroups (vla-get-activedocument (vlax-get-acad-object)))
                        (cdr (assoc "
file" item))
                        :vlax-false
                        ) ;_ end of vla-load
              ) ;_ end of lambda
            ) ;_ end of function
          ) ;_ end of vl-catch-all-apply
        ) ;_ end of foreach
      ;; Для ExpressTools немного "
своя" доработка
      (if (findfile "
acettest.fas")
        (progn
          (load "
acettest.fas")
          (vla-sendcommand (vla-get-activedocument (vlax-get-acad-object)) "
_expresstools ")
          ) ;_ end of progn
        ) ;_ end of if

      ;; Восстанавливаем рабочее пространство
      (if wscurrent
        (progn
          (setvar "
wscurrent" wscurrent)
          (command "
_.wssave" wscurrent "_y")
          ) ;_ end of progn
        ) ;_ end of if
      ) ;_ end of progn
    ) ;_ end of if
  ) ;_ end of defun

P.S. Исходники чуть позже...
_kpblc-get-appdata-current-user.lsp
_kpblc-dir-path-and-splash.lsp
_kpblc-conv-string-to-list.lsp
_kpblc-get-acad-product-name.lsp
_kpblc-get-profile-name.lsp
_kpblc-dir-create.lsp
_kpblc-conv-ent-to-ename.lsp
_kpblc-conv-ent-to-vla.lsp
_kpblc-conv-vla-to-list.lsp
_kpblc-menu-update.lsp

P.P.S. В _kpblc-menu-update я не показал, как загружать собственные частичные меню :) То, ради чего все и затевалось,- и не сделал :D Комментом добавлю, если надо. Учитывая, что vla-load так и так работать будет, особых трудностей возникнуть не должно...

Если действительно надо, напишите в комментах - отвечу как только смогу.



Комментарии

Есть 6 коммент. к “Продолжаю войну с меню…”
  1. Andrey пишет:

    >На Windows 7 я такого, конечно, уже не встречал, но предусмотреть подобное поведение не помешает.
    Зачем?

  2. Кулик Алексей aka kpblc пишет:

    Недавно пришлось подобный код на WinXP SP2 запускать. Никто не знает, что будет завтра :)

  3. Андрей пишет:

    Ты не понял моего вопроса. :)

    Попробую пояснить его: даже если %AppData% развернётся в так называемом "формате 8.3" (см. http://support.microsoft.com/kb/142982/ru ), что в твоём примере обозначено как C:\DOCUME~1\DOMAIN~2, то что в этом страшного? Главное, что операционная система сможет найти нужный каталог по этой записи.

  4. Кулик Алексей aka kpblc пишет:

    Ну, я очень не люблю, когда код возвращает не то, что ожидаешь. Не нравится мне неопределенность :)

  5. Андрей пишет:

    >Конечно, можно и третий / четвертый / пятый путь придумать, но мне было лень :) Так что я выбирал между двумя.

    Лично мне не нравится такое дублирование:
    >создавать отдельный каталог, в который копировать “чистые” файлы основного меню и сопутствующие им (т.е. mnl, dll), устанавливать эту копию в качестве основного файла меню и уже потом подгружать свои файлы.

    Поэтому третий, достаточно простой вариант, устраняющий обозначенный выше дубляж: иметь один основной файл меню и произвольное количество частичных. Каждый раз при завершении работы AutoCAD выполнять автоматическую программную выгрузку всех частичных меню, что по факту удалит соответствующие записи из основного меню. А при запуске AutoCAD выполнять автоматическую загрузку тех файлом частичных меню, которые прописаны в ветке реестра текущего профиля AutoCAD.

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

    Реализация обозначенного выше варианта достаточно проста и компактна. Хотя, как говорится, на вкус и цвет все фломастеры разные.

  6. Андрей пишет:

    >Ну, я очень не люблю, когда код возвращает не то, что ожидаешь. Не нравится мне неопределенность :)

    Так там и нет неопределённости, просто один и тот же путь может быть записан двумя способами - более длинным или более компактным. Имхо - важен конечный результат. Но тут опять на сцену выходят всё те же фломастеры...

Поделитесь своим мнением


Я не робот.