Оптимальным решением является установка
Bullzip PDF Printer . После установки в системе появляется виртуальный принтер, с помощью которого можно "печатать" в файл pdf из любого приложения. Программа бесплатная, работает в терминале и имеет поддержку русского языка.
После установки, можно печатать напрямую используя код:
Код 1C v 8.х
//Таб - ТабличныйДокумент
//ИмяФайла – путь для сохранения файла PDF (например «D:\Torg12.pdf»)
Процедура СоздатьФайлПДФ(Таб, ИмяФайла)
Попытка
ПДФПринтер = Новый ComObject(«Bullzip.PDFPrinterSettings»);
ПДФПринтер.SetValue(«output», ИмяФайла);
ПДФПринтер.SetValue(«ShowSaveAS», «never»);
ПДФПринтер.SetValue(«ShowProgress», «no»);
ПДФПринтер.SetValue(«ShowProgressFinished», «no»);
ПДФПринтер.SetValue(«ShowSettings», «never»);
ПДФПринтер.SetValue(«ShowPDF», «no»);
ПДФПринтер.SetValue(«ConfirmOverwrite»,»no»);
ПДФПринтер.WriteSettings();
Таб.Автомасштаб = Истина;
Таб.ИмяПринтера = «Bullzip PDF Printer»;Таб.Напечатать(Истина);
PDFФайл = Новый Файл(ИмяФайла);
Пока НЕ PDFФайл.Существует() Цикл
ОбработкаПрерыванияПользователя();
КонецЦикла;
Исключение
Сообщить(ОписаниеОшибки());
Сообщить(«Скорее всего необходимо установить или переустановить «»Bullzip PDF Printer»);
КонецПопытки;
//устанавливаем принтер по умолчанию
Таб.ИмяПринтера = ПолучитьПринтерПоУмолчанию();
КонецПроцедуры
Здесь функция
ПолучитьПринтерПоУмолчанию() нужна для того чтобы вернуть печатной форме принтер по умолчанию, т.к. если напечатать без предварительного просмотра то печать пойдет на виртуальный PDF принтер BullzipPDFPrinter.
Код 1C v 8.х //получаем принтер по умолчанию
Функция ПолучитьПринтерПоУмолчанию()
Скрипт = Новый ComObject(«MSScriptControl.ScriptControl»);
Скрипт.Language = «vbscript»;
Скрипт.AddCode(»
|Function GetDefaultPrinter()
|GetDefaultPrinter=vbNullString
|Set objWMIService=GetObject(«»winmgmts:»" _
|& «»{impersonationLevel=impersonate}!\\.\root\cimv2″»)
|Set colInstalledPrinters=objWMIService.ExecQuery _
|(«»S_elect * from Win32_Printer»")
|For Each objPrinter in colInstalledPrinters
|If objPrinter.Attributes and 4 Then
|GetDefaultPrinter=objPrinter.Name
|Exit For
|End If
|Next
|End Function»);
Возврат СокрЛП(Скрипт.run(«GetDefaultPrinter»));
КонецФункции
Печать в PDF используя bioPDF Зарегистрированная внешняя компонента хранится в реестре следующим образом:
Предположим, что у нас есть внешняя компонента E:\Events\Events.dll.
В 1С мы пишем:
Код 1C v 7.x
ЗагрузитьВнешнююКомпоненту("e:\Events\Events.dll");
vk=СоздатьОбъект("Addin.Events");
Теперь зайдем в программу regedit.exe (Пуск-Выполнить-Regedit.exe).
Если регистрация прошла успешно, то в реестре мы увидим следующие записи (я сделал поиск по подстроке "AddIn.Events" в редакторе реестра regedit.exe, нажав сочетание клавиш Ctrl-F):
Код
[HKEY_CLASSES_ROOT\AddIn.Events\Clsid]
@="{2E5E6B2C-EFE0-4872-9AB6-DF187B9CE397}"
[HKEY_CLASSES_ROOT\CLSID\{2E5E6B2C-EFE0-4872-9AB6-DF187B9CE397}]
@="V7 AddIn 2.0"
[HKEY_CLASSES_ROOT\CLSID\{2E5E6B2C-EFE0-4872-9AB6-DF187B9CE397}\InprocServer32]
@="E:\\Events\\Events.dll"
[HKEY_CLASSES_ROOT\CLSID\{2E5E6B2C-EFE0-4872-9AB6-DF187B9CE397}\ProgID]
@="AddIn.Events"
Значение {2E5E6B2C-EFE0-4872-9AB6-DF187B9CE397} является уникальным для каждого OLE-объекта идентификатором (CLSID). Его должен явно задать разработчик в коде внешней компоненты.
Значение ProgID, которое в нашем случае - "AddIn.Events" также задает разработчик внешней компоненты.
Чтобы в реестре появились эти записи, необходимы права доступа:
Начиная с Windows 2000, обычный пользователь не имеет прав доступа к указанным выше ветвям реестра. Нужны права или администратора, или привилегированного пользователя Windows. После первой загрузки компонента пропишет себя в реестре, и ее смогут использовать и непривилегированные пользователи Windows.
Где 1С ищет внешнюю компоненту?
Если при загрузке внешней компоненты вы не указываете полный путь, такой как E:\Events\Events.dll или сетевой путь наподобие \\ВашСервер\ПапкаГдеЛежатВК\Events.dll, то 1С ищет внешние компоненты
-относительно папки 1Cv7\BIN (КаталогПрограммы())
-относительно каталога информационной базы (КаталогИБ())
Метод ЗагрузитьВнешнююКомпоненту(), обнаружив ВК по новому пути, обновляет ее регистрацию в реестре
Это означает, например, что на терминальном сервере программист, который вошел в тестовую базу, где лежит ВК, и потом ее стер, оставит у всех пользователей запись в реестре о несуществующей ВК.
Аналогичная проблема - когда ВК по данному пути недоступна тем или иным пользователям.
А поскольку пользователи не имеют права на изменение записей в реестре, то у них перестанет загружаться и внешняя компонента.
В 1С:Предприятие 8.0 убрана возможность загрузки ВК относительно каталога ИБ.
В 7.7 же, чтобы избежать проблем, всегда убирайте ВК из каталога ИБ, и прописывайте полные пути (или складывайте DLL в общую для всех пользователей папку BIN).
Кардинальное решение проблемы - VKLoader и RegsvrEx
Имеется компонента VKLoader.dll (автор - Александр Орефков), которая позволяет решить проблемы с регистрацией компонент.
http://openconf.1cpp.ru/vk/vkloader/
Цитата:
"vkloader (далее ВК) - внешняя компонента для 1С-Предприятия 7.7, которая может загружаться без ее регистрации в реестре, и загружать другие внешние компоненты без их регистрации. Предназначена для беспроблемной загрузки внешних компонент пользователями, не имеющими прав на запись в HKCR ветку реестра.
Принцип работы основан на перехвате обращения 1С к WinAPI функциям CLSIDF
rom ProgID и CoCreateInstance.
Также ВК решает проблему "зависания" процесса 1С в памяти при закрытии программы при использовании несовсем корректно написанных сторонних внешних компонент".
Пример использования vkloader:
Код 1C v 7.x ЗагрузитьВнешнююКомпоненту("vkloader.dll"); //регистрации не требует
Загрузчик = СоздатьОбъект("ЗагрузчикВК");
Результат = Загрузчик.ЗагрузитьВК("Events.dll", "Addin.Events=2E5E6B2C-EFE0-4872-9AB6-DF187B9CE397");
Замечу, что сама vkloader "умеет" загружать себя без прав доступа к реестру.
Еще одно решение: RegsvrEx
Автор - AlexQC.
Регистрирует компоненты (OLE-объекты) в пользовательской ветке реестра.
RegsvrEX
Пример использования:
Код 1C v 7.x Попытка
Объект=СоздатьОбъект("cool.object");
Исключение
ИмяДЛЛ=КаталогИБ()+"cool.ocx";
КомандаСистемы(КаталогИБ()+"regsvrex.exe /s /c "+ИмяДЛЛ);
Попытка
Объект=СоздатьОбъект("cool.object");
Исключение
Сообщить("Ошибка загрузки компоненты: "+ИмяDLL,"!");
КонецПопытки;
КонецПопытки;
При разработке отчетов или обработок рано или поздно приходится сталкиваться с необходимостью определения имени локального диска, сменного накопителя (флешки), сетевого диска. В данной статье представлены 3 способа получения списка дисков компьютера:
Примеры для 8-ой версии, для того чтобы заработало в 7-ой замените:
Код 1C v 8.х Новый COMОбъект(
на
Код 1C v 7.x СоздатьОбъект(
1-вый способ:
Код 1C v 8.х FSO = Новый COMОбъект("Scripting.FileSystemObject");
// Выборка объектов из коллекции Drives
Для каждого Диск Из FSO.Drives Цикл
// Диск.DriveLetter - буква диска
Стр = Диск.DriveLetter;
// Диск.DriveType = 1 - Flash накопитель
// Диск.DriveType = 2 - Локальный жесткий диск
// Диск.DriveType = 3 - Сетевой диск
// Диск.DriveType = 4 - CD/DVD дисковод
Если Диск.DriveType = 3 Тогда // если это сетевой диск, то укажем сетевой путь
Стр = Стр + " - " + Диск.ShareName;
ИначеЕсли Диск.IsReady Тогда
Стр = Стр + " - " + Диск.VolumeName;
Иначе
Стр = Стр + " - [Диск не найден]";
КонецЕсли;
Сообщить(Стр);
КонецЦикла;
2-ой способ:
Код 1C v 8.х
//При помощи скрипта получаем перечень всех дисков компьютера:
Попытка
ScrptCtrl = Новый COMОбъект("MSScriptControl.ScriptControl");
ScrptCtrl.Language="vbscript";
ScrptCtrl.addcode("
|Function GetComputers()
| Set objWMIService = GetObject(""winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2"")
| Set colDisks = objWMIService.ExecQuery (""Select * from Win32_LogicalDisk"")
| For Each objDisk in colDisks
| disk = disk & objDisk.DeviceID & "";"" & objDisk.DriveType& "";""
| Next
| GetComputers = disk
|End Function
|");
Текст=СокрЛП(ScrptCtrl.Run("GetComputers"));
Исключение
Предупреждение(ОписаниеОшибки());
КонецПопытки;
//Далее создадим таблицу дисков компьютера
ТабДисков = Новый ТаблицаЗначений;
ТабДисков.Колонки.Добавить("Диск");
ТабДисков.Колонки.Добавить("Описание");
//Переберая полученную информацию из скрипта добавляем ее в таблицу
Пока СтрДлина (Текст)> 0 Цикл
Строка = ТабДисков.Добавить();
Строка.Диск = Лев(Текст,2);
// Далее определим тип диска:
// 1 - Дисковод
// 2 - Flash накопитель
// 3 - Локальный жесткий диск
// 4 - Сетевой диск
// 5 - CD/DVD дисковод
Строка.Описание = Сред(Текст,4,1);
Текст = Сред(Текст,6,СтрДлина (Текст)-5);
КонецЦикла;
// Далее переберая элементы таблицы выведем флешки в окно сообщений
Сообщить("Флешки:");
Для Каждого Элемента Из ТабДисков Цикл
Если Элемента.Описание = "2" Тогда
Сообщить(Элемента.Диск);
КонецЕсли;
КонецЦикла;
3-ий способ:
Код 1C v 8.х //Попытка подключения к WMI на локальном компьютере
Попытка
Locator = Новый COMОбъект("WbemScripting.SWbemLocator");
Исключение
Сообщить(ОписаниеОшибки());
Возврат;
КонецПопытки;
ServicesSet = Locator.ConnectServer(".");
//Извлечение экземпляров класса Win32_LogicalDisk
ObjectSet = ServicesSet.InstancesOf("Win32_LogicalDisk");
Для каждого Item Из ObjectSet Цикл
Сообщить("Имя: " + Item.Caption);
Сообщить("Описание: " + Item.Description); // здесь выводится тип диска
Сообщить("Файловая система: " + Item.FileSystem);
Сообщить("Свободное место: " + Item.FreeSpace);
Сообщить("Метка диска: " + Item.VolumeName);
Сообщить ("=======================") ;
КонецЦикла;
Автор:
Мигачев Евгений Код 1C v 8.х Ex = Новый COMObject("Excel.Application");
Ex.Workbooks.Open(Путь);
Ex.Visible = 1;
ТекЛист=Ex.WorkSheets(1);
Для Ячейка = 1 по 400 цикл
Если НЕ ТекЛист.Cells(Ячейка,1).Value = Неопределено тогда
Сообщить(Строка(ТекЛист.Cells(Ячейка,1).Value));
Карта = Справочники.Номенклатура.НайтиПоКоду(ИзЧислаВСтроку(ТекЛист.Cells(Ячейка,1).Value));
Если Карта.Пустая() тогда
Сообщить(" Пустой элемент " + ТекЛист.Cells(Ячейка,1));
иначе
Объект = Карта.ПолучитьОбъект();
Объект.ОсновнойПоставщик = ОсновнойКлиент;
Объект.Записать();
конецесли;
конецесли;
конеццикла;
Примеры процедур для чтения данных из EXCEL
Код 1C v 8.х
// Функция получает данные из файла Excel
//
// Параметры:
// пФайл - Имя файла
// пЛист - Имя листа с данными
// СтруктураКолонок - Структура вида "ИмяКолонки" - "НомерКолонки"
// если не задано, созадуться колонки вида "К1", "К2"
//
// Возвращаемое значение:
// ТаблицаЗначений
//
Функция Excel_ПолучитьДанные_ADO(пФайл, пЛист, СтруктураКолонок = Неопределено, Знач НачСтрока = 0, Знач КонСтрока = 0) Экспорт
#Если Клиент Тогда
Состояние("Установка соединения с Excel");
#КонецЕсли
//ЗаголовкиВСтроке1 = "HDR=YES;"
ЗаголовкиВСтроке1 = "HDR=NO;";
СтрокаСоединения ="Provider=Microsoft.Jet.OLEDB.4.0;Data Source= " + СокрЛП(пФайл) +" ;Extended Properties=""Excel 8.0;" + ЗаголовкиВСтроке1 + "IMEX=1;""";
Connection = Новый COMОбъект("ADODB.Connection");
Connection.ConnectionString = СтрокаСоединения;
Попытка
Connection.Open();
Исключение
Сообщить ("Проблемы с подключением к Excel" );
Возврат Неопределено;
КонецПопытки;
RS = Новый COMОбъект("ADODB.Recordset");
ТекстЗапроса =
"S_elect
| Лист.*
|FROM
| [" + пЛист + "$] as Лист";
Попытка
RS.Open(ТекстЗапроса, Connection);
Исключение
Сообщить ("Проблемы с выполнением запроса");
Возврат Неопределено;
КонецПопытки;
Таблица = Новый ТаблицаЗначений;
Если СтруктураКолонок = Неопределено Тогда
Для Счетчик = 1 По RS.Fields.Count Цикл
Поле = RS.Fields.Item(Счетчик - 1);
Колонка = Таблица.Колонки.Добавить("К" + Счетчик, , Поле.Name);
КонецЦикла;
Иначе
Для каждого КлючИЗначение Из СтруктураКолонок Цикл
Колонка = Таблица.Колонки.Добавить(КлючИЗначение.Ключ);
КонецЦикла;
КонецЕсли;
НомерСтроки = 0;
КолвоСтрок = RS.RecordCount;
Пока RS.EOF() = 0 Цикл
НомерСтроки = НомерСтроки + 1;
#Если Клиент Тогда
Состояние("Чтение файла: " + Формат(НомерСтроки) + " из " + Формат(КолвоСтрок));
ОбработкаПрерыванияПользователя();
#КонецЕсли
Если НомерСтроки < НачСтрока Тогда
RS.MoveNext();
Продолжить;
КонецЕсли;
Если КонСтрока > 0 И НомерСтроки > КонСтрока Тогда
Прервать;
КонецЕсли;
НоваяСтрока = Таблица.Добавить();
Если СтруктураКолонок = Неопределено Тогда
Для Счетчик = 1 По RS.Fields.Count Цикл
Поле = RS.Fields.Item(Счетчик - 1);
НоваяСтрока["К" + Счетчик] = Поле.Value;
КонецЦикла;
Иначе
Для каждого КлючИЗначение Из СтруктураКолонок Цикл
Поле = RS.Fields.Item(КлючИЗначение.Значение - 1);
НоваяСтрока[КлючИЗначение.Ключ] = Поле.Value;
КонецЦикла;
КонецЕсли;
// Обработка других полей
RS.MoveNext();
КонецЦикла;
// Завершение работы
RS.Close();
Connection.Close();
Возврат Таблица;
КонецФункции
// Функция получает данные из файла Excel
//
// Параметры:
// пФайл - Имя файла
// пЛист - Имя листа с данными
// СтруктураКолонок - Структура вида "ИмяКолонки" - "НомерКолонки"
// если не задано, созадуться колонки вида "К1", "К2"
// XLSОбъект - COM объект типа "Excel.Application"
//
// Возвращаемое значение:
// ТаблицаЗначений
//
Функция Excel_ПолучитьДанные_COM(пФайл, пЛист, СтруктураКолонок = Неопределено, Знач НачСтрока = 0, Знач КонСтрока = 0, XLSОбъект = Неопределено) Экспорт
#Если Клиент Тогда
Состояние("Открытие Excel");
#КонецЕсли
Если XLSОбъект = Неопределено Тогда
XLSОбъект = Новый COMОбъект("Excel.Application");
XLSОбъект.Visible = Ложь;
XLSОбъект.DisplayAlerts = Ложь;
КонецЕсли;
Попытка
Book = XLSОбъект.Workbooks.Open(пФайл, , Истина);
Исключение
Сообщить ("Проблемы с подключением к Excel" );
Возврат Неопределено;
КонецПопытки;
Лист = Book.Sheets(1);
КолвоКолонок = Лист.Cells(1,1).SpecialCells(11).Column;
КолвоСтрок = Лист.Cells(1,1).SpecialCells(11).Row;
Таблица = Новый ТаблицаЗначений;
Если СтруктураКолонок = Неопределено Тогда
Для Счетчик = 1 По КолвоКолонок Цикл
Колонка = Таблица.Колонки.Добавить("К" + Счетчик);
КонецЦикла;
Иначе
Для каждого КлючИЗначение Из СтруктураКолонок Цикл
Колонка = Таблица.Колонки.Добавить(КлючИЗначение.Ключ);
КонецЦикла;
КонецЕсли;
НачСтрока = ?(НачСтрока = 0, 1, НачСтрока);
КонСтрока = ?(КонСтрока = 0, КолвоСтрок, КонСтрока);
КонСтрока = Мин(КонСтрока, КолвоСтрок);
Для НомерСтроки = НачСтрока По КонСтрока Цикл
#Если Клиент Тогда
Состояние("Чтение файла: " + Формат(НомерСтроки) + " из " + Формат(КонСтрока));
ОбработкаПрерыванияПользователя();
#КонецЕсли
НоваяСтрока = Таблица.Добавить();
Если СтруктураКолонок = Неопределено Тогда
Для НомерКолонки = 1 По КолвоКолонок Цикл
Поле = Лист.Cells(НомерСтроки, НомерКолонки);
НоваяСтрока["К" + Формат(НомерКолонки, "ЧГ=0")] = Поле.Value;
КонецЦикла;
Иначе
Для каждого КлючИЗначение Из СтруктураКолонок Цикл
Поле = Лист.Cells(НомерСтроки, КлючИЗначение.Значение);
НоваяСтрока[КлючИЗначение.Ключ] = Поле.Value;
КонецЦикла;
КонецЕсли;
КонецЦикла;
XLSОбъект.Application.Quit();
Возврат Таблица;
КонецФункции
// Функция получает данные из файла Excel
//
// Параметры:
// пФайл - Имя файла
// пЛист - Имя листа с данными
// СтруктураКолонок - Структура вида "ИмяКолонки" - "НомерКолонки"
// если не задано, созадуться колонки вида "К1", "К2"
// XLSОбъект - COM объект типа "Excel.Application"
//
// Возвращаемое значение:
// ТаблицаЗначений
//
Функция Excel_ПолучитьДанные_COMArray(пФайл, пЛист, СтруктураКолонок = Неопределено, Знач НачСтрока = 0, Знач КонСтрока = 0, XLSОбъект = Неопределено) Экспорт
#Если Клиент Тогда
Состояние("Открытие Excel");
#КонецЕсли
Если XLSОбъект = Неопределено Тогда
XLSОбъект = Новый COMОбъект("Excel.Application");
XLSОбъект.Visible = Ложь;
XLSОбъект.DisplayAlerts = Ложь;
КонецЕсли;
Попытка
Book = XLSОбъект.Workbooks.Open(пФайл, , Истина);
Исключение
Сообщить ("Проблемы с подключением к Excel" );
Возврат Неопределено;
КонецПопытки;
Лист = Book.Sheets(1);
КолвоКолонок = Лист.Cells(1,1).SpecialCells(11).Column;
КолвоСтрок = Лист.Cells(1,1).SpecialCells(11).Row;
Таблица = Новый ТаблицаЗначений;
Если СтруктураКолонок = Неопределено Тогда
Для Счетчик = 1 По КолвоКолонок Цикл
Колонка = Таблица.Колонки.Добавить("К" + Счетчик);
КонецЦикла;
Иначе
МаксимальныйНомерКолонки = 0;
Для каждого КлючИЗначение Из СтруктураКолонок Цикл
Колонка = Таблица.Колонки.Добавить(КлючИЗначение.Ключ);
МаксимальныйНомерКолонки = Макс(МаксимальныйНомерКолонки, КлючИЗначение.Значение);
КонецЦикла;
КолвоКолонок = Мин(КолвоКолонок, МаксимальныйНомерКолонки);
КонецЕсли;
НачСтрока = ?(НачСтрока = 0, 1, НачСтрока);
КонСтрока = ?(КонСтрока = 0, КолвоСтрок, КонСтрока);
КонСтрока = Мин(КонСтрока, КолвоСтрок);
// Массив типа COMSafeArray
Массив = Лист.Range(Лист.Cells(НачСтрока, 1), Лист.Cells(КонСтрока, КолвоКолонок)).Value;
КолвоСтрок = Массив.GetUpperBound(1);
Для НомерСтроки = 1 По КолвоСтрок Цикл
#Если Клиент Тогда
Состояние("Чтение файла: " + Формат(НомерСтроки) + " из " + Формат(КолвоСтрок));
ОбработкаПрерыванияПользователя();
#КонецЕсли
НоваяСтрока = Таблица.Добавить();
Если СтруктураКолонок = Неопределено Тогда
Для НомерКолонки = 1 По КолвоКолонок Цикл
НоваяСтрока["К" + Формат(НомерКолонки, "ЧГ=0")] = Массив.GetValue(НомерКолонки, НомерСтроки);
КонецЦикла;
Иначе
Для каждого КлючИЗначение Из СтруктураКолонок Цикл
НоваяСтрока[КлючИЗначение.Ключ] = Массив.GetValue(КлючИЗначение.Значение, НомерСтроки);
КонецЦикла;
КонецЕсли;
КонецЦикла;
XLSОбъект.Application.Quit();
Возврат Таблица;
КонецФункции
// Функция получает список листов Excel
//
// Параметры:
// пФайл - Имя файла
// XLSОбъект - COM объект типа "Excel.Application"
//
// Возвращаемое значение:
// СписокЗначений
//
Функция Excel_ПолучитьСписокЛистов(пФайл, XLSОбъект = Неопределено) Экспорт
Если XLSОбъект = Неопределено Тогда
XLSОбъект = Новый COMОбъект("Excel.Application");
XLSОбъект.Visible = Ложь;
XLSОбъект.DisplayAlerts = Ложь;
КонецЕсли;
Попытка
Book = XLSОбъект.Workbooks.Open(пФайл, , Истина);
Исключение
Возврат Новый СписокЗначений;
КонецПопытки;
СписокЛистов = Новый СписокЗначений;
Для каждого Лист Из XLSОбъект.Sheets Цикл
СписокЛистов.Добавить(Лист.Name);
КонецЦикла;
XLSОбъект.Application.Quit();
Возврат СписокЛистов;
КонецФункции
Код 1C v 7.x Попытка
Excel = СоздатьОбъект("Excel.Application");
Исключение
Сообщить(ОписаниеОшибки()+"; программа Excel не установлена на данном компьютере!");
Возврат;
КонецПопытки;
РабочиеКниги=Excel.WorkBooks; // создаем рабочую книгу
Попытка // открываем файл
Отчет=РабочиеКниги.Open(Каталог+ИмяФайла);
Исключение
Сообщить(ОписаниеОшибки()+"; фаил с макросом не найден!");
Возврат;
КонецПопытки;
// заносим в таблицу какие-либо данные
Лист = Отчет.Worksheets(1);
Для Ном=1 По 20 Цикл
Ячейка = Лист .Cells(ном,1); Ячейка.Value;
Сообщить(Ячейка );
КонецЦикла;
Excel.Visible=1;
Попытка
Отчет.Save();
Исключение
Сообщить(ОписаниеОшибки()+"; не могу сохранить отчет!");
Возврат;
КонецПопытки;
Наиболее эффективно это можно сделать с помощью объектов OLE Automation , работа с которыми осуществляется при помощи:
sp_OACreate, sp_OAGetProperty, sp_OASetProperty, sp_OAMethod, sp_OAGetErrorInfo, sp_OADestroy (подробное описание есть в http://technet.microsoft.com/ru-ru/library/ms203721(sql.90).aspx).
Рабочий пример процедуры (была написана для сохранения zip-архивов, хранящихся в базе):
Код CREATE PROCEDURE dbo.SaveRequestDataAsFile (
@FileName varchar(1024) --имя файла
,@FilePath varchar(1024) --путь файла
,@ReqID --некое условие на таблицу
)
AS
BEGIN
DECLARE
@Stream integer,
@Buffer varbinary(4096),
@Size integer,
@Pos integer,
@BufSize integer,
@FileNameLocal varchar(1024),
@HR integer
if RIGHT(@FilePath, 1)<>'&# 092;' begin set @FilePath=@FilePath+'&# 092;' end
set @FileNameLocal = @FilePath + @FileName
SET @BufSize = 4096
EXEC @HR = sp_OACreate 'ADODB.Stream',@Stream OUT
if @HR<>0
begin
--обработка ошибки создания объекта
EXEC [dbo].[sp_displayoaerrorinfo] @Stream ,@HR
end
EXEC @HR = sp_OASetProperty @Stream,'Type',1 -- binary
EXEC @HR = sp_OASetProperty @Stream,'Mode',3 -- write|read
EXEC @HR = sp_OAMethod @Stream,'Open'
S_elect
@Size = DATALENGTH(SrvRequests.RequestData)
FROM SrvRequests WHERE SrvRequests.RequestID = @ReqID
Set @Pos=0
WHILE @Pos < @Size BEGIN
SET @BufSize = CASE WHEN @Size - @Pos < 4096 THEN @Size - @Pos ELSE 4096 END
S_elect @Buffer = substring(SrvRequests.RequestData ,@Pos+1, @BufSize)
from SrvRequests where SrvRequests.RequestID = @ReqID
EXEC @HR = sp_OAMethod @Stream, 'Write', NULL, @Buffer
SET @Pos = @Pos + @BufSize
END
EXEC @HR = sp_OAMethod @Stream,'SaveToFile',null, @FileNameLocal,2
EXEC @HR = sp_OAMethod @Stream,'Close'
EXEC @HR = sp_OADestroy @Stream
END
Рекомендуется создать еще пару процедур для внятного описания ошибок в случае их возникновения
Код CREATE PROCEDURE sp_hexadecimal
@binvalue varbinary(255),
@hexvalue varchar(255) OUTPUT
AS
DECLARE @charvalue varchar(255)
DECLARE @i int
DECLARE @length int
DECLARE @hexstring char(16)
S_elect @charvalue = '0x'
S_elect @i = 1
S_elect @length = DATALENGTH(@binvalue)
S_elect @hexstring = '0123456789abcdef'
WHILE (@i <= @length)
BEGIN
DECLARE @tempint int
DECLARE @firstint int
DECLARE @secondint int
S_elect @tempint = CONVERT(int, SUBSTRING(@binvalue,@i,1))
S_elect @firstint = FLOOR(@tempint/16)
S_elect @secondint = @tempint - (@firstint* 16)
S_elect @charvalue = @charvalue +
SUBSTRING(@hexstring, @firstint+1, 1) +
SUBSTRING(@hexstring, @secondint+1, 1)
S_elect @i = @i + 1
END
----------------------------------------------------------------------
CREATE PROCEDURE sp_displayoaerrorinfo
@object int,
@hresult int
AS
DECLARE @output varchar(255)
DECLARE @hrhex char(10)
DECLARE @hr int
DECLARE @source varchar(255)
DECLARE @description varchar(255)
PRINT 'OLE Automation Error Information'
EXEC sp_hexadecimal @hresult, @hrhex OUT
S_elect @output = ' HRESULT: ' + @hrhex
PRINT @output
EXEC @hr = sp_OAGetErrorInfo @object, @source OUT, @description OUT
IF @hr = 0
BEGIN
S_elect @output = ' Source: ' + @source
PRINT @output
S_elect @output = ' Description: ' + @description
PRINT @output
END
ELSE
BEGIN
PRINT ' sp_OAGetErrorInfo failed.'
RETURN
END
Ниже привожу пример функции нечеткого сравнения строк. Возвращаемое значение - от 0 (вообще не совпадает) до 1 (совпадает полностью)
По опыту, результат сравнения можно считать достоверным при совпадении больше 0.8 (80%)
Код CREATE FUNCTION fn_FuzzyCompareString(
@Stri1 varchar(250),
@Stri2 varchar(250),
@MaxLen int)
RETURNS float
AS
BEGIN
DECLARE @Str1 varchar(250), @Str2 varchar(250), @SCountVar int,
@SCountEq int, @LenStr int, @Res float
DECLARE @NumSymbStr2 int
DECLARE @Cnt1 int, @Cnt2 int
DECLARE @SubStr varchar(250)
SELECT
@LenStr=1,
@SCountVar=0 ,
@SCountEq=0,
@res=0
Set @Str1 = replace(LTRIM(RTRIM(upper(@Stri1))),'.',' ')
Set @Str2 = replace(LTRIM(RTRIM(upper(@Stri2))),'.',' ')
if ((@MaxLen <= 0) or (Len(@Str1)=0) or (Len(@Str2)=0))
Begin
Set @Res=0
End
else
begin
While (@LenStr<=@MaxLen)
BEGIN
Set @NumSymbStr2=1
Set @Cnt2=0
While ((@Cnt2+@LenStr)<=LEN(@Str2))
BEGIN
Set @SubStr = '%'+SUBSTRING(@Str2,@NumSymbStr2,@LenStr)+'%'
if (PATINDEX(@SubStr, @Str1)<>0)
begin
Set @SCountEq=@SCountEq+1
end
Set @SCountVar=@SCountVar+1
Set @NumSymbStr2=@NumSymbStr2+1
Set @Cnt2 = @Cnt2+1
END
Set @NumSymbStr2=1
Set @Cnt2=0
While ((@Cnt2+@LenStr)<=LEN(@Str1))
BEGIN
Set @SubStr = '%'+SUBSTRING(@Str1,@NumSymbStr2,@LenStr)+'%'
if (PATINDEX(@SubStr, @Str2)<>0)
begin
Set @SCountEq=@SCountEq+1
end
Set @SCountVar=@SCountVar+1
Set @NumSymbStr2=@NumSymbStr2+1
Set @Cnt2 = @Cnt2+1
END
Set @LenStr=@LEnStr+1
END
end
if @SCountVar=0
SET @Res=0
Else
BEGIN
SET @Res=Convert(Numeric (10,5),@SCountEq)/Convert(Numeric (10,5),@SCountVar)
END
RETURN @Res
END
Использование этой функции (на примере прямого запроса к справочнику ФизЛица для 1С:ТиС 7.7): в выборку попадут все физлица, у которых релевантность выше 0.8
Код DECLARE @FIO varchar(250)
Set @FIO = 'Иванов Петр'
SELECT
Спр.Code as [ФизЛицоКод],
Спр.ID as [ФизЛицо],
Спр.DESCR as [ФИО],
dbo.fn_FuzzyCompareString(dbo.fn_FIO(Спр.DESCR),@FIO,3) As [Релевантность]
FROM
SC503 as Спр (nolock)
where
ISMARK = 0
and
ISFOLDER = 2
and
dbo.fn_FuzzyCompareString(dbo.fn_FIO(Спр.DESCR),@FIO,3)>=0.8
GO