При разработке механизмов интеграции в 1С:Предприятие 7.7, особенно при обмене данными с государственной системой МДЛП (Честный Знак), разработчики часто сталкиваются с критическим падением системы. Ошибка проявляется как "исключение unknown software exception 0x800000fb" или "инструкция обратилась к памяти по адресу... память не может быть read", указывая на библиотеку MFC42.DLL. В этом материале мы подробно разберем, почему возникает эта проблема и как ее решить несколькими способами.
Рассмотрим ситуацию: нам необходимо отправить JSON или XML файл размером более 500 Кб через COM-объект, например, MSXML2.ServerXMLHTTP или WinHttp.WinHttpRequest.5.1. При попытке выполнить метод Send(ТелоЗапроса) платформа 1С 7.7 аварийно завершается.
Проанализируем причину: проблема заключается в реализации механизма IDispatch внутри ядра 1С 7.7. Когда мы передаем строку из 1С во внешний COM-объект, платформа пытается выполнить маршалинг (передачу) данных типа BSTR. Для строк большого объема внутренний буфер платформы переполняется или некорректно взаимодействует с системными библиотеками управления памятью. Это не является ошибкой самой библиотеки MFC42.DLL, это ограничение архитектуры 1С 7.7, которая проектировалась в эпоху, когда передача многомегабайтных строк через OLE была редкостью.
Это самый эффективный и проверенный способ, который позволяет "обмануть" стандартный механизм вызова методов 1С. Компонента OleExSup.dll берет на себя задачу правильной передачи параметров в COM-объект, минуя проблемные участки кода платформы.
Рассмотрим по шагам, как изменить код для корректной работы:
OleExSup.dll в системе или просто положите ее в каталог с базой/бинарными файлами 1С.InvokeOLEMethod.Пример кода для отправки данных через XMLHTTP:
// Создаем объект HTTP
XMLHTTP = СоздатьОбъект("MSXML2.ServerXMLHTTP.6.0");
XMLHTTP.Open("POST", URL, 0);
// Загружаем внешнюю компоненту
Если ЗагрузитьВнешнююКомпоненту("OleExSup.dll") = 0 Тогда
Сообщить("Ошибка загрузки OleExSup.dll", "!");
Возврат;
КонецЕсли;
// Создаем вспомогательный объект
OleExSup = СоздатьОбъект("OLEExSup");
// Вместо XMLHTTP.Send(БольшоеТелоЗапроса) пишем так:
OleExSup.InvokeOLEMethod(XMLHTTP, "Send", БольшоеТелоЗапроса);
// Обрабатываем ответ
Ответ = XMLHTTP.ResponseText;
Аналогично решается проблема с объектом CDO.Message или ADODB.Stream при записи больших текстовых блоков:
Stream = БодиПарт.GetDecodedContentStream();
Stream.charset = "windows-1251";
// Опасный участок: Stream.WriteText(ОченьДлиннаяСтрока);
// Используем безопасный вызов:
OleExSup = СоздатьОбъект("OLEExSup");
OleExSup.InvokeOLEMethod(Stream, "WriteText", ОченьДлиннаяСтрока);
Если вы не хотите использовать сторонние DLL, можно попробовать метод передачи "по ссылке" через интерфейс IStream. Многие современные COM-объекты (включая WinHTTP) умеют принимать в метод Send не только строку, но и объект потока.
Разберем этот метод подробнее:
ADODB.Stream.Stream в качестве параметра. Поскольку передается ссылка на объект, а не сама гигантская строка, переполнения буфера в 1С не происходит.Посмотрим на пример реализации:
// Подготавливаем поток данных
Поток = СоздатьОбъект("ADODB.Stream");
Поток.Type = 2; // adTypeText
Поток.Charset = "utf-8";
Поток.Open();
Поток.WriteText(БольшоеТелоЗапроса);
Поток.Position = 0;
// Отправляем объект Поток вместо строки
HTTP = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
HTTP.Open("POST", URL, 0);
HTTP.Send(Поток);
Сообщить(HTTP.ResponseText);
В некоторых случаях, когда объемы данных исчисляются десятками мегабайт (например, при выгрузке 40 000 кодов маркировки), даже работа через потоки может быть нестабильной из-за нехватки оперативной памяти, выделяемой процессу 1С 7.7. В такой ситуации лучше делегировать транспортную задачу внешней утилите.
Проанализируем алгоритм:
Текст.Записать() или FSO).WScript.Shell для запуска консольной утилиты curl или специализированного прокси-сервера (например, на языке Go или Python), который примет имя файла и отправит его в МДЛП.Пример вызова через curl:
Команда = "curl -X POST " + URL + " -H ""Content-Type: application/json"" --data-binary @C:\temp\request.json -o C:\temp\response.json";
Shell = СоздатьОбъект("WScript.Shell");
Shell.Run(Команда, 0, 1); // Выполнить и ждать завершения
Важный нюанс: При работе с МДЛП обязательна криптография по ГОСТ. Если стандартные COM-объекты 1С не справляются с подписью больших данных, рекомендуем использовать stunnel-msspi для создания защищенного туннеля или внешние компоненты, умеющие работать с криптопровайдером напрямую с диска.
Хотя программные методы решения являются приоритетными, иногда стоит проверить системные настройки, чтобы повысить стабильность работы со старым ПО:
1cv7s.exe в список исключений DEP. Однако на серверных ОС это не всегда помогает полностью, так как MFC42.DLL является системным компонентом.HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems\Windows. Изменение значения SharedSection=1024,3072,512 на более высокие (например, 5120,6400,5120) увеличивает объем памяти для дескрипторов окон и системных куч, что полезно в терминальных сессиях.Подводя итог, можно сказать, что наиболее стабильным и современным решением для программиста 1С 7.7 является использование OleExSup.dll в сочетании с передачей данных через ADODB.Stream. Это позволяет сохранить логику обмена внутри кода 1С, избегая при этом критических ошибок памяти.