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