1 // MGW (Мохов Геннадий Владимирович) 2017 - ВК для 1С 8.3
2 //
3 // dmd -ofmgw1c_vk1.dll mgw1c_vk1 terminal asc1251 -L/IMPLIB -shared -release
4
5 module cd1;
6
7 import core.sys.windows.windows;
8 import core.sys.windows.dll;
9 import core.runtime; // Загрузка DLL Для Win
10 import std..string;
11 import core.stdc.wchar_ : wcscmp, wmemcpy;
12 import std.stdio;
13
14 /*----- Фичи, на которые ушло 5 дней тестирования алгоритма 1С при загрузке и регистрации ВК -----
15 * 1) - 1С функция "ПодключитьВнешнююКомпоненту(путьdll.XXX.типвк)" имеет три параметра. Самый примечательный средний
16 * он определяет и средний параметр 1С функции "Новый(AddIn.XXX.расширение)", который ОДНАЗНАЧНО должен
17 * совпадать с средним параметром функции "ПодключитьВнешнююКомпоненту(путьdll.XXX.типвк)". Причем, что
18 * содержит это поле не важно, ВК об этом ни чего не знает.
19 * 2) - Заставить ВК создать несколько объектов возможно, если для ВК функции GetClassNames("obj1|obj2|obj3") <-- для примера
20 * в строке параметра через разделитель ихперечислить. При этом 1С последовательно будет вызывать GetClassObject
21 * для каждого объекта в этом списке. Поскольку первый и второй параметр в Новый() у нас уже предопределен, то
22 * как то различить объекты можно только по третьему параметру. По этому третий параметр будет одно из
23 * значений из "obj1|obj2|obj3". Это значит, что для каждого вызова функции ВК RegisterExtensionAs() нам
24 * надо помнить, что записать мы должны имя объекта (obj1, obj2 или obj3)
25 * 3) - Объекты создаются сразу все в момент вызова "ПодключитьВнешнююКомпоненту()" и "Новый()" ни чего не создаёт,
26 * НО! если будет дан вызов ещё одного "Новый()", то будет создан ещё один новый экземпляр объекта.
27 *
28 * ---------------------------------------------------*/
29
30
31 // ________________________________________________
32 // Алиасы для упращения записи работы с указателями
33 alias p = void*;
34 alias ppi = immutable(p)*;
35 // ________________________________________________
36 // Вспомогательные функции. Forth фукция @
37 p dog(T)(T pz) { return *cast(p*)pz; }
38 /*
39 void msgbox(wstring msg, wstring zag) {
40 char[256] msgbuf; char[256] zagbuf;
41 wsprintf(cast(wchar*)cbuf, cast( const(wchar)*)"wstrLen = %d"w, tvar.VarEnum.vtRecWideString.wstrLen );
42 MessageBoxW(null, cast(wchar*)msgbuf, zagbuf, 0);
43 }
44 */
45 // ______________________________________________________________
46 // Выделение и освобождение памяти средствами 1С для внутренних нужд
47 // IMemoryManager --> C++ Interface representing memory manager.
48 // ______________________________________________________________
49 // Реализация интерфейса класса С++. Смысл: компилятору D рассказывается, как вызывать
50 // методы С++ класса. Однако сам класс уже создан внутри 1С (С++) и нам в D будет передан
51 // указатель на этот класс. По этому, что написано в теле самих методов (пустые) не важно,
52 // т.к. они реально не выполняются.
53 extern (C++) class CMemoryManager /* :IMemoryManager */ {
54 extern (Windows) {
55 // C++ деструктор, всегда первый
56 // ----------------------------------
57 void Destroy() {}
58 // Выделить память указанного размера
59 // ----------------------------------
60 // @InOut pMemory - двойной указатель на переменную, которая будет содержать
61 // указатель на блок памяти или null если была ошибка
62 // @In ulCountByte - размер запрашиваемого блока
63 // @return результат операции
64 bool AllocMemory(p* pMemory, uint ulCountByte) { return true; }
65 // Освободить память
66 // ----------------------------------
67 // @In pMemory - двойной указатель на переменную содержащию
68 // указатель на блок памяти
69 void FreeMemory (p* pMemory) {}
70 }
71 }
72
73 // Это входные параметы для функции "GetInterface()" которая может возвратить указатель на дополнительные
74 // интерфейсы 1С новых версий, что позволит задействовать их возможности
75 enum InterfacesEnum { eIMsgBox = 0, eIPlatformInfo }
76 enum AddInQuestionDialogModeEnum { eAQDModeOK, eAQDModeOKCancel, eAQDModeAbortRetryIgnore, eAQDModeYesNoCancel, eAQDModeYesNo, eAQDModeRetryCancel }
77 enum AddInDlgRetCodesEnum {
78 eADlgRetCodeTimeout = -1,
79 eADlgRetCodeOK = 1,
80 eADlgRetCodeCancel,
81 eADlgRetCodeAbort,
82 eADlgRetCodeRetry,
83 eADlgRetCodeIgnore,
84 eADlgRetCodeYes,
85 eADlgRetCodeNo,
86 }
87
88 // ______________________________________________________________
89 /* Представляет интерфейс для взаимодействия ВК и 1С Платформой
90 *
91 */
92 /// Base interface for object components.
93 extern (C++) class CAddInDefBase {
94 extern (Windows) @nogc @system {
95 // C++ деструктор, всегда первый
96 // ----------------------------------
97 void Destroy() {}
98
99 /// добавить error сообщение
100 /**
101 * @param wcode - error code
102 * @param source - source of error
103 * @param descr - description of error
104 * @param scode - error code (HRESULT)
105 * @return the result of
106 */
107 bool AddError(ushort wcode, immutable(wchar)* source, immutable(wchar)* descr, int scode) { return true; }
108
109 /// Reads a property value
110 /**
111 * @param wszPropName -property name
112 * @param pVal - value being returned
113 * @param pErrCode - error code (if any error occured)
114 * @param errDescriptor - error description (if any error occured)
115 * @return the result of read.
116 */
117 bool Read(wchar* wszPropName, TVariant* pVal, long* pErrCode, wchar** errDescriptor) { return true; }
118 /// Writes a property value
119 /**
120 * @param wszPropName - property name
121 * @param pVar - new property value
122 * @return the result of write.
123 */
124 bool Write(wchar* wszPropName, TVariant* pVar) { return true; }
125
126 ///Registers profile components
127 /**
128 * @param wszProfileName - profile name
129 * @return the result of
130 */
131 bool RegisterProfileAs(wchar* wszProfileName) { return true; }
132
133 /// Changes the depth of event buffer
134 /**
135 * @param lDepth - new depth of event buffer
136 * @return the result of
137 */
138 bool SetEventBufferDepth(long lDepth) { return true; }
139 /// Returns the depth of event buffer
140 /**
141 * @return the depth of event buffer
142 */
143 long GetEventBufferDepth() { return true; }
144 /// Registers external event
145 /**
146 * @param wszSource - source of event
147 * @param wszMessage - event message
148 * @param wszData - message parameters
149 * @return the result of
150 */
151 bool ExternalEvent( immutable(wchar)* wszSource, immutable(wchar)* wszMessage, immutable(wchar)* wszData) { return true; }
152 /// Clears event buffer
153 /**
154 */
155 void CleanEventBuffer() { }
156
157 // Вывести строку в StatusLine обычного приложения (не управляемые формы)
158 // ----------------------------------------------------------------------
159 // @param wszStatusLine - строка для отображения, может быть обычной "Строка для отображения"w.ptr
160 // @return результат операции
161 bool SetStatusLine(wchar* wszStatusLine) { return true; }
162
163 /// Resets the status line contents
164 // --------------------------------
165 // @return the result of
166 void ResetStatusLine() { }
167 }
168 }
169
170 extern (C++) class CAddInDefBaseEx : CAddInDefBase {
171 extern (Windows) @nogc @system {
172 // void Destroy2() {}
173 // ----------------------------------
174 // Тут есть странность. В примере С++ тут первым должен быть деструктор, но в реальности
175 // его нет!!! Получается, что компилятор как то по другому распеделяет память, либо
176 // пример устарел. Как бы там не было, но закоментировав деструктор удалось вызвать GetInterface() ...
177 // ----------------------------------
178 // void Destroy2() {}
179 // p GetInterface(InterfacesEnum iface) { return null; }
180
181 p GetInterface(InterfacesEnum iface) { return null; }
182 }
183 }
184
185 extern (C++) class CIMsgBox {
186 extern (Windows) @nogc @system {
187 // void DestroyMsgBox() {}
188 // @disable this();
189 bool Confirm(immutable(wchar)* queryText, TVariant* retVal) { return true; }
190 bool Alert(immutable(wchar)* queryText) { return true; }
191 }
192 }
193
194 alias t_Alert = extern (Windows) @nogc bool function(immutable(wchar)*);
195
196 // ================= MGW1 =================
197 p m_iConnect;
198 p m_iMsg;
199 extern (C++) class CMgw1CIInitDoneBase { // для CMgw1
200 extern (Windows) @nogc @system {
201 void Destroy() {
202 // MessageBoxA(null, "--V40-- Destructor CMgw1CIInitDoneBase()".ptr, "aution".ptr, 0);
203 }
204 bool Init(p pConnection) {
205 debug {
206 MessageBoxA(null, "--V411-- Init()".ptr, "aution".ptr, 0);
207 }
208 mgw1.ptrCPPobjIConnect = pConnection;
209 mgw1.st_iConnect = cast(CAddInDefBase*)&(mgw1.ptrCPPobjIConnect);
210 return pConnection !is null;
211 }
212 bool setMemManager(p mem) {
213 debug {
214 MessageBoxA(null, "--V42-- setMemManager()".ptr, "aution".ptr, 0);
215 }
216 // Для D нужно отодвинуть указатель, т.к. D класс "дальше" C++ класса
217 mgw1.ptrCPPobjIMemory = mem;
218 mgw1.st_iMemory = cast(CMemoryManager*)&(mgw1.ptrCPPobjIMemory);
219 return mem !is null;
220 }
221 int GetInfo() {
222 debug {
223 MessageBoxA(null, "--V43-- GetInfo()".ptr, "aution".ptr, 0);
224 }
225 return 2000;
226 }
227 void Done() {
228 debug {
229 MessageBoxA(null, "--V44-- Done()".ptr, "aution".ptr, 0);
230 }
231 }
232 }
233 }
234
235 wstring prNameExt;
236 wstring str2;
237
238 extern (C++) class CMgw1CILanguageExtenderBase { // для CMgw1
239 extern (Windows) {
240 void Destroy() {
241 // MessageBoxA(null, "--X40-- Destructor CMgw1CILanguageExtenderBase()".ptr, "aution".ptr, 0);
242 }
243 // Создает строку с char_t* wide содержащей имя ВК Последнее поле после точек
244 // Обязательно использование менеджера памяти 1С, в противном случае не работает
245 bool RegisterExtensionAs(wchar** wsExtensionName) {
246 bool rez = false;
247 // MessageBoxW(null, "--X45-- RegisterExtensionAs()"w.ptr, prNameExt.ptr, 0);
248 if(mgw1.st_iMemory !is null) {
249 int iActualSize = prNameExt.length + 1; // Длина с нулем
250 if(mgw1.st_iMemory.AllocMemory(cast(p*)wsExtensionName, wchar.sizeof * iActualSize)) {
251 wmemcpy(*wsExtensionName, prNameExt.ptr, iActualSize);
252 // MessageBoxW(NULL, cast(const(wchar)*)*wsExtensionName, NULL, 1);
253 rez = true;
254 }
255 }
256 return rez;
257 }
258 // Возвращает количество свойств, 0 = свойств нет
259 int GetNProps() {
260 // MessageBoxA(null, "--X46-- GetNProps()".ptr, "aution".ptr, 0);
261 return Props.ePropLast;
262 };
263 // Возвращает порядковый номер свойства, имя которого передается в параметрах
264 int FindProp(const(wchar)* wsPropName) {
265 int n = -1; // Вдруг не найдено
266 for(int i; i != Props.ePropLast; i++) {
267 if( 0 == wcscmp( wsPropName, listProp[i].propNameRu.ptr )) { n = i; break; }
268 else {
269 if( 0 == wcscmp( wsPropName, listProp[i].propNameEn.ptr )) { n = i; break; }
270 }
271 }
272 // wstring bufwstr = format("--X47-- FindProp() n == %s"w, n);
273 // MessageBoxW(NULL, cast(const(wchar)*)wsPropName, bufwstr.ptr, 1);
274 return n;
275 };
276 // Возвращает имя свойства по его порядковому номеру и по переданному идентификатору языка
277 p GetPropName(int lPropNum, int lPropAlias) { /* MessageBoxA(null, "--X48-- GetPropName()".ptr, "aution".ptr, 0); */ return null; };
278 // Возвращает значение свойства с указанным порядковым номером
279 bool GetPropVal(const int lPropNum, TVariant* pvarPropVal) {
280 bool rez = false;
281 // MessageBoxA(null, "--X49-- GetPropVal()".ptr, "aution".ptr, 0);
282 if(lPropNum == Props.eTest) {
283 str2 = "[[[ " ~ str1 ~ " ]]]";
284
285 wchar* t1;
286 int iActualSize = str2.length + 1; // Длина с нулем
287 if(mgw1.st_iMemory.AllocMemory(cast(p*)&t1, wchar.sizeof * iActualSize))
288 wmemcpy(t1, str2.ptr, iActualSize);
289 (*pvarPropVal).vt = ENUMVAR.VTYPE_PWSTR;
290 (*pvarPropVal).VarEnum.vtRecWideString.pwstrVal = t1;
291 (*pvarPropVal).VarEnum.vtRecWideString.wstrLen = str2.length;
292 rez = true;
293 }
294 if(lPropNum == Props.eIsLogConsole) { // естьЛогКонсоль + isLogConsole
295 (*pvarPropVal).vt = ENUMVAR.VTYPE_BOOL;
296 (*pvarPropVal).VarEnum.bVal = f_LogConsole;
297 // MessageBoxA(null, "--X49-- eIsLogConsole GetPropVal()".ptr, "aution".ptr, 0);
298 rez = true;
299 }
300 return rez;
301 };
302 // Устанавливает значение свойства с указанным порядковым номером
303 bool SetPropVal(const int lPropNum, TVariant* pvarPropVal) {
304 bool rez = false;
305 // TVariant tvar = *pvarPropVal;
306 // MessageBoxA(null, "--X50-- SetPropVal()".ptr, "aution".ptr, 0);
307 if(lPropNum == Props.eTest) {
308 import std.conv : to;
309
310 if( (*pvarPropVal).vt == ENUMVAR.VTYPE_PWSTR) {
311 str1 = to!wstring((*pvarPropVal).VarEnum.vtRecWideString.pwstrVal);
312 // mgw1.st_iConnect.ResetStatusLine();
313 // mgw1.st_iConnect.SetStatusLine(cast(wchar*)(*pvarPropVal).VarEnum.vtRecWideString.pwstrVal);
314 mgw1.st_iConnect.SetStatusLine(cast(wchar*)"Привет из ВК на D ..."w.ptr);
315 // MessageBoxW(null, cast( const(wchar)*)str1.ptr, null, 0);
316 }
317 rez = true;
318 }
319 if(lPropNum == Props.eIsLogConsole) { // естьЛогКонсоль + isLogConsole
320 if((*pvarPropVal).vt == ENUMVAR.VTYPE_BOOL) {
321 f_LogConsole = (*pvarPropVal).VarEnum.bVal;
322 consInit(f_LogConsole);
323 rez = true;
324 }
325 }
326 if(lPropNum == Props.ePrint) { // Печать на консоль
327 if( (*pvarPropVal).vt == ENUMVAR.VTYPE_PWSTR) {
328 import std.conv : to;
329 string strWs = to!string((*pvarPropVal).VarEnum.vtRecWideString.pwstrVal);
330 consPrint(strWs);
331 }
332 rez = true;
333 }
334 return rez;
335 };
336 // Возвращает флаг флаг возможности чтения свойства с указанным порядковым номером
337 bool IsPropReadable(int lPropNum) { return listProp[lPropNum].isRead; };
338 // Возвращает флаг флаг возможности записи свойства с указанным порядковым номером
339 bool IsPropWritable(int lPropNum) { return listProp[lPropNum].isWrite; };
340
341 int GetNMethods() { /* MessageBoxA(null, "--X53-- GetNMethods()".ptr, "aution".ptr, 0); */ return 0; };
342 int FindMethod(p wsMethodName) { MessageBoxA(null, "--X54-- FindMethod()".ptr, "aution".ptr, 0); return 0; };
343 p GetMethodName(int lMethodNum, int lMethodAlias) { MessageBoxA(null, "--X55-- GetMethodName()".ptr, "aution".ptr, 0); return null; };
344 int GetNParams(int lMethodNum) { MessageBoxA(null, "--X56-- GetNParams()".ptr, "aution".ptr, 0); return 0; };
345 bool GetParamDefValue(int lMethodNum, int lParamNum, p pvarParamDefValue) { MessageBoxA(null, "--X57-- GetParamDefValue()".ptr, "aution".ptr, 0); return 0; };
346 bool HasRetVal(int lMethodNum) { MessageBoxA(null, "--X58-- HasRetVal()".ptr, "aution".ptr, 0); return 0; };
347 bool CallAsProc(int lMethodNum, p paParams, int lSizeArray) { MessageBoxA(null, "--X59-- CallAsProc()".ptr, "aution".ptr, 0); return 0; };
348 bool CallAsFunc(int lMethodNum, p pvarRetValue, p paParams, int lSizeArray) { MessageBoxA(null, "--X60-- CallAsFunc()".ptr, "aution".ptr, 0); return 0; };
349 }
350 }
351
352 extern (C++) class CMgw1CILocaleBase { // для CMgw1
353 extern (Windows) {
354 void Destroy() {
355 // MessageBoxA(null, "--Z40-- Destructor CMgw1CILocaleBase()".ptr, "aution".ptr, 0);
356 }
357 void SetLocale(p loc) { /* MessageBoxA(null, "--Z61-- SetLocale ()".ptr, "aution".ptr, 0); */ };
358 }
359 }
360 // ================= MGW1 =================
361
362 enum AppCapabilities { eAppCapabilitiesInvalid = -1, eAppCapabilities1 = 1, eAppCapabilitiesLast = eAppCapabilities1 };
363 static AppCapabilities g_capabilities = AppCapabilities.eAppCapabilitiesInvalid;
364 //---------------------------------------------------------------------------//
365
366 // Определяет количество и имена методов
367 struct stProp {
368 Props num; // Номер свойства
369 wstring propNameEn; // Имя свойства En
370 wstring propNameRu; // Имя свойства Ru
371 bool isRead; // Можно читать?
372 bool isWrite; // Можно писать?
373 }
374 // Это перечисление нумерует свойства и автоматически задаёт размерность массива для listProp
375 enum Props {
376 eTest,
377 eIsLogConsole,
378 ePrint,
379 ePropLast
380 }
381 // Массив структур, каждая запись хранит описание Свойства
382 stProp[Props.ePropLast] listProp = [
383 { num: Props.eTest, propNameEn: "Test", propNameRu: "Тест", isRead: true, isWrite: true },
384 { num: Props.eIsLogConsole, propNameEn: "isLogConsole", propNameRu: "естьЛогКонсоль", isRead: true, isWrite: true },
385 { num: Props.ePrint, propNameEn: "Print", propNameRu: "Печать", isRead: false, isWrite: true }
386 ];
387
388 // _____________________________________________________________________________________
389 // Это есть аналог С++ класса с множ наследоваеием и мы в нем задействуем ещё пару полей
390 // для собственных нужд ( 3 vtbl имеет )
391 struct CCPPmgw1 {
392 // Обязательные поля, интерфейсы С++
393 ppi IInitDoneBase;
394 ppi ILanguageExtenderBase;
395 ppi ILocaleBase;
396 // Мои собственные свойства и методы
397 p ptrCPPobjIMemory; // Ссылка на объект класса С++ МенеджерПамяти
398 CMemoryManager* st_iMemory; // Указатель на указатель МенеджерПамяти для D
399 p ptrCPPobjIConnect; // Ссылка на объект класса С++ Взаимодействия с 1С
400 CAddInDefBase* st_iConnect; // Указатель на указатель Взаимодействия с 1С для D
401 CMgw1CIInitDoneBase objCInt;
402 CMgw1CILanguageExtenderBase objCLang;
403 CMgw1CILocaleBase objLocaleBase;
404 p ptrCPPobjCIMsgBox; // Ссылка на объект класса С++ Сообщения
405 CIMsgBox* st_iMsgBox; // Указатель на указатель Сообщения 1С
406 }
407
408 CCPPmgw1* mgw1; // Для mgwTest1
409
410 // Внимание!
411 // =========
412 // Имя компоненты должно совпадать с именем первого класса
413 // -------------------------------------------------------
414
415 // g_nameAddIn - строка где '|' перечислены всеимена классов
416 // 1С будет создавать экземпляры каждого класса сразу при подключении, а потом будет использовать их.
417 // Если вызвать первый раз Новый("AddIn.VK.myClass"), то будет использован уже созданный при подключении экземпляр,
418 // а если вызвать снова Новый("AddIn.VK.myClass") - то будет создан уже новый экземпляр класса.
419 static const wstring g_nameAddIn = "LogConsole";
420
421 // Имя расширения, последнее поле в имени
422 // wstring CMgw1 = "CMgw1";
423 wstring str1;
424
425 version(Windows) {
426 import core.sys.windows.windows; // GetProcAddress для Windows
427 }
428
429 //---------------------------------------------------------------------------//
430 // Функция названа неправильно. Это не имя класса, а имя AddIn, т.к. классов в этом AddIn
431 // может быть несколько. Используется в 1C:
432 // ПодключитьВнешнююКомпоненту(fullNameDll, "имяAddIn", ТипВнешнейКомпоненты.Native);
433 // ОбъектВК = Новый("AddIn.имяAddIn.ИмяЗарегКласса");
434 export extern (C) p GetClassNames() { printf("hello.../n"); return cast(p)g_nameAddIn.ptr; }
435 //---------------------------------------------------------------------------//
436 export extern (C) p GetClassObject(wchar* wsName, p* pInterface) {
437 if(*pInterface) return null; // Проверка на готовность 1С
438
439 debug {
440 char[256] cbuf;
441 MessageBoxW(NULL, cast(const(wchar)*)wsName, ">>--21--GetClassObject()"w.ptr, 1);
442 }
443
444 // Создание классов разнесено специально, что бы показать, что они могут быть совршенны разные
445 // по структуре и размеру
446
447 // Создаём класс -- mgwTest1
448 if( 0 == wcscmp( wsName, "LogConsole"w.ptr ) ) { // 1с запрашивает у нас класс mgwTest1
449 // создаю основу объекта
450 mgw1 = new CCPPmgw1;
451
452 mgw1.objCInt = new CMgw1CIInitDoneBase();
453 mgw1.objCLang = new CMgw1CILanguageExtenderBase();
454 mgw1.objLocaleBase = new CMgw1CILocaleBase();
455
456 // собираю объект клсса С++ в памяти
457 mgw1.IInitDoneBase = mgw1.objCInt.__vptr;
458 mgw1.ILanguageExtenderBase = mgw1.objCLang.__vptr;
459 mgw1.ILocaleBase = mgw1.objLocaleBase.__vptr;
460
461 // Верну в 1С указатель на созданный мной аналог C++ объекта класса
462 *pInterface = mgw1;
463 prNameExt = "LogConsole";
464 debug {
465 wsprintf(cast(wchar*)cbuf, cast( const(wchar)*)"*pInterface = %p objCInt = %p"w, *pInterface, mgw1.objCInt );
466 MessageBoxW(null, cast(wchar*)cbuf, "", 0);
467 }
468 goto m1;
469 }
470 // В примере ВК C++ возврат int ... проще вернуть указатель, чем перекодировать его в int
471 m1:
472 return *pInterface;
473 }
474 //---------------------------------------------------------------------------//
475 export extern (C) AppCapabilities SetPlatformCapabilities(AppCapabilities capabilities) {
476 debug {
477 MessageBoxA(null, "--24--SetPlatformCapabilities()".ptr, "aution".ptr, 0);
478 }
479 g_capabilities = capabilities;
480
481 debug {
482 char[256] cbuf;
483 wsprintf(cast(wchar*)cbuf, cast( const(wchar)*)"g_capabilities = %d capabilities = %d"w, g_capabilities, capabilities );
484 MessageBoxW(null, cast(wchar*)cbuf, "", 0);
485 }
486
487 return AppCapabilities.eAppCapabilitiesLast;
488 }
489 //---------------------------------------------------------------------------//
490 export extern (C) long DestroyObject(p* pInterface) {
491 debug {
492 MessageBoxW(NULL, "--22--DestroyObject()"w.ptr, NULL, 1);
493 }
494
495 // Уничтожим объект С++, Убрав ссылку на объект, отдаём его на уничтожение GC
496 if(*pInterface == mgw1) mgw1 = null;
497
498 debug {
499 char[256] cbuf;
500 wsprintf(cast(wchar*)cbuf, cast( const(wchar)*)"*pInterface = %p mgw1 = %p"w, *pInterface, mgw1 );
501 MessageBoxW(null, cast(wchar*)cbuf, "", 0);
502 }
503
504 // Для С++ 1С тоже скажем, что уничтожили
505 *pInterface = null;
506 return 0;
507 }
508 //--------------- Загрузка DLL --------------------------------------------------//
509
510 __gshared HINSTANCE g_hInst;
511
512 extern (Windows) BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
513 {
514 switch (ulReason)
515 {
516 case DLL_PROCESS_ATTACH:
517 g_hInst = hInstance;
518 dll_process_attach( hInstance, true );
519 break;
520 case DLL_PROCESS_DETACH:
521 dll_process_detach( hInstance, true );
522 break;
523 case DLL_THREAD_ATTACH:
524 dll_thread_attach( true, true );
525 break;
526 case DLL_THREAD_DETACH:
527 dll_thread_detach( true, true );
528 break;
529 default:
530 }
531 return true;
532 }
533
534 //--------------- Алиасы, константы и прочее --------------------------------------------------//
535
536 alias TGUID = byte[16];
537
538 struct TInterfaceVarRec { align (1): // iface
539 p pInterfaceVal;
540 TGUID InterfaceID;
541 }
542 struct TStringVarRec { align (1): // str
543 p pstrVal;
544 int LongWord; // количество байтов
545 }
546 struct TWideStringVarRec {align (1): // wstr
547 const(wchar)* pwstrVal; // указатель на wstring
548 int wstrLen; // количество символов
549 }
550 struct Ttm {
551 int tm_sec; // секунд после минуты (с 0)
552 int tm_min; // митуты после часа (с 0)
553 int tm_hour; // часов поле дня (с 0)
554 int tm_mday; // дней после месяца (с 1)
555 int tm_mon; // месяцев после года (с 0)
556 int tm_year; // лет после 1900 (с 0)
557 int tm_wday; // дней после воскресения (с 0)
558 int tm_yday; // дней с начала года (с 0)
559 int tm_isdst; // Daylight Saving Time flag
560 }
561 union TVarEnum {
562 byte i8Val; // = 1
563 short shortVal; // = 2
564 int lVal; // = 4
565 int intVal; // = 4
566 uint uintVal; // = 4
567 long llVal; // = 8
568 ubyte ui8Val; // = 1
569 ushort ushortVal; // = 2
570 uint ulVal; // = 4
571 ulong ullVal; // = 8
572 int errCode; // = 4
573 int hRes; // = 4
574 float fltVal; // = 4
575 double dblVal; // = 8
576 bool bVal; // = 1
577 char chVal; // = 1
578 wchar wchVal; // = 2
579 double data; // = 8
580 TGUID IDVal; // = 16
581 p pvarVal; // = 4
582 Ttm tmVal; // = 36
583 TInterfaceVarRec vtRecInterface;
584 TStringVarRec vtRecString;
585 TWideStringVarRec vtRecWideString;
586 }
587 // Сам тип Variant, именно с ним работает 1С
588 struct TVariant { align (1):
589 TVarEnum VarEnum; // Объеденение, хранит одну актуальную позицию
590 uint cbElements;
591 ushort vt; // Признак того, что за данные хранятся
592 }
593 // тип того, что лежит в Variant
594 enum ENUMVAR: ushort {
595 VTYPE_EMPTY,
596 VTYPE_NULL,
597 VTYPE_I2, //int16_t
598 VTYPE_I4, //int32_t
599 VTYPE_R4, //float
600 VTYPE_R8, //double
601 VTYPE_DATE, //DATE (double)
602 VTYPE_TM, //struct tm
603 VTYPE_PSTR, //struct str string
604 VTYPE_INTERFACE, //struct iface
605 VTYPE_ERROR, //int32_t errCode
606 VTYPE_BOOL, //bool
607 VTYPE_VARIANT, //struct _tVariant *
608 VTYPE_I1, //int8_t
609 VTYPE_UI1, //uint8_t
610 VTYPE_UI2, //uint16_t
611 VTYPE_UI4, //uint32_t
612 VTYPE_I8, //int64_t
613 VTYPE_UI8, //uint64_t
614 VTYPE_INT, //int Depends on architecture
615 VTYPE_UINT, //unsigned int Depends on architecture
616 VTYPE_HRESULT, //long hRes
617 VTYPE_PWSTR, //struct wstr
618 VTYPE_BLOB, //means in struct str binary data contain
619 VTYPE_CLSID, //UUID
620 VTYPE_STR_BLOB = 0xfff,
621 VTYPE_VECTOR = 0x1000,
622 VTYPE_ARRAY = 0x2000,
623 VTYPE_BYREF = 0x4000, //Only with struct _tVariant *
624 VTYPE_RESERVED = 0x8000,
625 VTYPE_ILLEGAL = 0xffff,
626 VTYPE_ILLEGALMASKED = 0xfff,
627 VTYPE_TYPEMASK = 0xfff
628 }
629
630 // ======================= Функции расширения ======================
631 import core.sys.windows.wincon;
632 import asc1251;
633 import terminal;
634
635 static Terminal _terminal; // Объект Консоль
636 bool f_isTerminal; // Есть консоль или нету
637 bool f_LogConsole; // 1C запоминает, есть ли консоль
638
639 // Печатать строку
640 void consPrint(string s) {
641 if(s.length == 0) return;
642 if(s.length < 3) { writeln(toCON(s)); return; }
643 if(s[1] == '|') {
644 if(s[0] == 'R') _terminal.color(Color.red, Color.DEFAULT);
645 if(s[0] == 'G') _terminal.color(Color.green, Color.DEFAULT);
646 if(s[0] == 'Y') _terminal.color(Color.yellow, Color.DEFAULT);
647 if(s[0] == 'B') _terminal.color(Color.blue, Color.DEFAULT);
648 writeln(toCON(s[2 .. $]));
649 return;
650 }
651 _terminal.color(Color.DEFAULT, Color.DEFAULT);
652 writeln(toCON(s));
653 }
654 // Инициализировать консоль
655 //__________________________
656 void consInit(bool sw) {
657 // char[256] cbuf;
658 // wsprintf(cast(wchar*)cbuf, cast( const(wchar)*)"consInit() sw = %d, f_isTerminal = %d, f_LogConsole = %d"w.ptr, sw, f_isTerminal, f_LogConsole); MessageBoxW(null, cast(wchar*)cbuf, "", 0);
659 if(f_isTerminal) {
660 if(!sw) {
661 FreeConsole();
662 f_isTerminal = false;
663 }
664 } else {
665 if(sw) {
666 AllocConsole(); freopen(cast(const(char*))"conout$".ptr, cast(const(char*))"w".ptr, core.stdc.stdio.stdout);
667 _terminal = Terminal(ConsoleOutputType.cellular);
668 _terminal.setTitle("Log console for 1C:Enterprase 8.3");
669 f_isTerminal = true;
670 }
671 }
672 }
673