Форум » [x]Harbour » Снова EXCEL » Ответить

Снова EXCEL

Dima: Ранее с Excel из Harbour ни когда не работал. Поставили тут задачу. У некоторых поставщиков есть определенные формы заказов. Набраны они в Excel. Сейчас народ руками заполняет эти формы и шлет по электронке поставщикам. Задача сводится к тому что бы в этих формах находить нужные коды товара и в нужной ячейке проставлять заказ. Может ткнет кто носом с чего начать что бы не напороться на грабли. Спасибо Сами формы тут http://zalil.ru/33279066

Ответов - 300, стр: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 All

Dima: Пока что интересует: поиск в определенной колонке c определенной строки

Pasha: Да никаких особенных граблей быть не может. Примерно так: [pre]Local oExcel := Win_OleAuto():New( "Excel.Application" ) Local oBook, oSheet, oCell, xValue Local nRow := 3 Local nCol := 3, nCol2 := 5 oExcel:Visible := .f. oExcel:Workbooks:Open( cFile, 0 ) oBook := oDoc:ActiveWorkBook oSheet := oExcel:ActiveSheet while .t. oCell := oSheet( nRow, nCol ) xValue := oRange:Value if Empty(xValue) exit endif if xValue == <Kod> oSheet( nRow, nCol2 ):Value := <Zakaz> endif enddo ... oBook:Close(.f.) oExcel:Quit() [/pre]

Andrey: Dima пишет: Пока что интересует: поиск в определенной колонке c определенной строки Форма жестко задана ? Т.е. нужно найти (например: 001/001) и в ячейку "К-во (кг)" написать тебе нужную цифру ?


fil: 1. Определяем для Excel-файла ширину/высоту рабочего ранга(было на форуме) 2. Бросаем ранг в массив. Ну и ищем чего надо

Vlad04: http://files.mail.ru/X3JBC6 Пример загрузки из Excel- в базу

Dima: fil пишет: 1. Определяем для Excel-файла ширину/высоту рабочего ранга(было на форуме) что то не нашел...... Вроде все получилось , но после заполнения бланка и попытки закрытия EXCEL , он задает вопрос , не желаю ли я сохранить изменения. Как обойти этот запрос и сохраниться ?

fil: oExc:Sheets(nn):UsedRange:Rows:Count oExc:Sheets(nn):UsedRange:Columns:Count oExc:WorkBooks(имя):Close(FALSE,,FALSE)

Dima: Всем спасибо !!!

Dima: Наткнулся на грабли. MT режим. Запущенная в отдельном потоке функция по по заполнению заявок упорно не хочет запускать EXCEL. Функция постоянно выдает FALSE Private переменная oExcel объявлена из фунции которая вызывает Start_Excel() Куда копать ? PS Простой пример без потоков в MT режиме срабатывает нормально. [pre2] func Start_Excel() Local Res:=.f. #ifndef __XHARBOUR__ #xcommand TRY => BEGIN SEQUENCE WITH {|e| Break( e )} #xcommand CATCH [<!oErr!>] => RECOVER [USING <oErr>] <-oErr-> #endif TRY oExcel := GetActiveObject( "Excel.Application" ) oExcel:DisplayAlerts:=.f. Res:=.t. CATCH Res:=.f. TRY oExcel := CreateObject( "Excel.Application" ) Res:=.t. CATCH // Ole2TxtError() выдает ошибку 0x800401f0 Res:=.f. END END Return Res [/pre2]

Dima: Похоже в MT режиме и многопоточной обработкой EXCEL запустить не получиться. Или не прав я и можно как то исправить ситуацию ? PS Уж очень не хочется функцию по заполнению бланков реализовывать в виде отдельной программы и вызывать ее из основной задачи.

fil: А так можно: Открываем один oExc:=CreateObject(Excel.Application). Открываем файл в нем листы с формами На каждый трейд ActiveX():New( диалог, "OWC11.Spreadsheet" ) и на каждый кладем свою форму. Обрабатываем.

Vlad04: Private переменная oExcel объявлена из фунции Я oExcel объявляю в головном файле и стартую из любого места программы

Dima: fil пишет: Открываем один oExc:=CreateObject(Excel.Application) Dima пишет: Похоже в MT режиме и многопоточной обработкой EXCEL запустить не получиться Dima пишет: Ole2TxtError() выдает ошибку 0x800401f0

Dima: Dima пишет: Уж очень не хочется функцию по заполнению бланков реализовывать в виде отдельной программы и вызывать ее из основной задачи. Так и поступил. Работает ;)

Softlog86: Есть задача сгенерировать два XLS файла из одной DBF . Только разные условия для отбора . Пока делаю последовательно ... Можно-ли клепать их одновременно (как-бы разные листы) ? А затем сохранять каждый лист отдельно ... Но я не знаю как это делать - у меня сохраняется вся книга сразу .... Научите переключать книги и сохранять их отдельно :)

Dima: Примерно так. [pre2] proc main local oWorkBook1 local oWorkBook2 local cfile1:=CurDrive()+":\"+CurDir()+"\"+"z1.xls" local cfile2:=CurDrive()+":\"+CurDir()+"\"+"z2.xls" private oExcel if !Start_Excel() quit endif oWorkBook1 := oExcel:Workbooks:Open(cfile1) oWorkBook2 := oExcel:Workbooks:Open(cfile2) oExcel:Visible := .T. oExcel:Windows(oWorkBook1:name()):Activate() // переключение между файлами // oExcel:Windows(oWorkBook2:name()):Activate() переключение между файлами wait oWorkBook1:save() oWorkBook1:close(.f.,,.f.) oWorkBook2:save() oWorkBook2:close(.f.,,.f.) oExcel:Quit() return nil [/pre2]

Softlog86: Уже спасибки ! А как быть если XLS файлов нет ? Они создаются во время обработки данных из других DBF файлов ...... Интересует ещё команды изменения свойств ячейки ( столбца) : Тип данных , выравнивание , шаблон вывода.....

Dima: Softlog86 А посмотри примерчик \svn\harbour\contrib\hbwin\tests\testole.prg Что касаемо шаблона и выравнивания есть тема на форуме , поищи по слову Excel

fil: Всем, привет ! Excel через ole 1. Как получить текст формулы условного форматирования (ежели таковые определены для ячейки) ? 2. Можно ли программно выполнить формулу условного форматирования ?

Dima: fil Сделай макрос и все увидишь. Можно погуглить на предмет Selection.FormatConditions

fil: Ну эт понятно. Тока в свойствах FormatConditions я не нашел текста формулы. Собсно, мне нужно отловить событие изменения заливки ячеек формулой условного форматирования дабы прицепить к этим ячейкам примечания.

Dima: Formula1 Formula2 не оно разве ?

fil: Да, это. Можно теперь выполнить эту формулу в харбор синтаксисе и понять изменялась ли заливка. Лучше, конечно, через Interior:ColorIndex, но не получается

Dima: fil пишет: Лучше, конечно, через Interior:ColorIndex http://office.microsoft.com/ru-ru/excel-help/HA001136627.aspx

fil: Эт я знаю. Не получится - формула условного форматирования не меняет ColorIndex/Color. То ли есть еще какой признак цвета, то ли заливка ячейки происходит тока на экране.

Dima: fil Давай XLS файлик (пример) в студию и скажи точно что хош узнать. Поиграюсь.

fil: Победил гада ! Т.к. фомулы условного форматирования отрабатывают тока при визуализации Excel, то в момент заполнения Excel-отчета насильственно рассчитывал их из через Evaluate() и в зависимости от результата клеил комент к ячейке.

gustow: fil пишет: Победил гада ! Победу в студию плиз :) (хотя бы в простейшем примере) А то вдруг пригодится?

fil: Так рассказал же, вроде, все ?! 1. Требовалось брать инфу из исходных Excel файлов и заливать ее в некий Excel файл-шаблон 2. В шаблоне присутствуют как обычные формулы, так и формулы условного форматирования (ФУМ), красящие ячейки в разные цвета 3. ФУМ отрабатывают тока при визуализации Excel, а мне требовалось отловить событие выполнения этих ФУМ при заполнении шаблона 4. Узнать это моно так a) получить ФУМ - ..cells(x, y):FormatConditions(nn):Formula1 б) выполнить ФУМ методом - ..oExc:Evaluate(ФУМ), чтобы оценить возвращаемое значение Пример писать неохота

gustow: Более-менее понятно. Спасибо, fil , за разгадку "еще одной тайны Harbour-вселенной" :)

Dima: Как правильно ? oSheet := oExcel:ActiveSheet() или так oSheet := oExcel:ActiveSheet У меня задача работает нормально а у клиента с таким же EXCEL виснет Код примерно такой. Виснет судя по всему в цикле (временно включил oExcel:Visible) [pre2] oWorkBook := oExcel:WorkBooks:Add() oSheet := oExcel:ActiveSheet() oSheet:Cells:Font:Name := "Arial Cyr" oSheet:Cells:Font:Size := 10 oSheet:Cells( 1, 1 ):Value :=Hb_oemtoansi("Код") oSheet:Cells( 1, 2 ):Value :=Hb_oemtoansi("Наименование") oSheet:Cells( 1, 3 ):Value :=Hb_oemtoansi("Цена") oSheet:Cells( 1, 4 ):Value :=Hb_oemtoansi("Ед.изм") oSheet:Cells( 1, 5 ):Value :=Hb_oemtoansi("Группа") oSheet:Cells( 1, 6 ):Value :=Hb_oemtoansi("Фирма") oSheet:Cells( 1, 7 ):Value :=Hb_oemtoansi("Примечание") oSheet:Range(osheet:cells(1,1),osheet:cells(1,7)):HorizontalAlignment := xlCenter //центр oSheet:Range(osheet:cells(1,1),osheet:cells(1,7)):Font:Bold := .T. oSheet:Range(osheet:cells(1,1),osheet:cells(1,7)):BorderAround( xlContinuous, xlThin) for i=1 to len(mmas) oSheet:Cells( j, 1 ):Value :=mmas[1] oSheet:Cells( j, 1 ):HorizontalAlignment := xlLeft oSheet:Cells( j, 2 ):Value :=mmas[2] oSheet:Cells( j, 2 ):HorizontalAlignment := xlLeft oSheet:Cells( j, 3 ):NumberFormat:="0.00" oSheet:Cells( j, 3 ):Value :=mmas[4] oSheet:Cells( j, 3 ):HorizontalAlignment := xlRight oSheet:Cells( j, 4 ):Value :=mmas[3] oSheet:Cells( j, 4 ):HorizontalAlignment := xlCenter oSheet:Cells( j, 5 ):Value :=mmas[5] oSheet:Cells( j, 5 ):HorizontalAlignment := xlLeft oSheet:Cells( j, 6 ):Value :=mmas[6] oSheet:Cells( j, 6 ):HorizontalAlignment := xlLeft oSheet:Cells( j, 7 ):Value :=mmas[7] oSheet:Cells( j, 7 ):HorizontalAlignment := xlLeft oSheet:Range(osheet:cells(j,1),osheet:cells(j,7)):BorderAround( xlContinuous, xlThin) j++ next oSheet:Columns( 1 ):AutoFit() oSheet:Columns( 2 ):AutoFit() oSheet:Columns( 3 ):AutoFit() oSheet:Columns( 4 ):AutoFit() oSheet:Columns( 5 ):AutoFit() oSheet:Columns( 6 ):AutoFit() oSheet:Columns( 7 ):AutoFit() [/pre2]

Pasha: Я использую oExcel:ActiveSheet, но кажется разницы нет никакой. Подвисание лучше все-таки локализовать, выдавать на экран окно состояния: заполнение заголовка, номер строки массива, выравнивание столбцов. Возможно, что-то делает сам эксель: выполняет какие-то макросы, проверяет орфографию, и при этом подвисает. В коде программы ведь самые простые команды.

Dima: Dima пишет: oSheet:Cells( j, 3 ):NumberFormat:="0.00" Выяснил , падает тут , ненравится ему NumberFormat:="0.00" хммм Error WINOLE 1006 Argument Error _NumberFormat

Dima: Фсе разобрался В региональных настройках Винды в качестве разделителя целой и дробной части стояла запятая а у меня заявлена точка.

Dima: Порча какая то в Harbour 3.2 , в 2.0 было нормально. В итоговом документе Excel русский текст выглядит как китайский. Исходник [pre2] proc main local oSheet local oWorkBook private oExcel if Start_Excel() oExcel:Visible := .f. oExcel:DisplayAlerts:=.f. oWorkBook := oExcel:WorkBooks:Add() oSheet := oExcel:ActiveSheet() oSheet:Cells:Font:Name := "Arial Cyr" oSheet:Cells:Font:Size := 10 oSheet:Cells( 1, 1 ):Value :=Hb_oemtoansi("Код") oSheet:Cells( 1, 2 ):Value :=Hb_oemtoansi("Наименование") oSheet:Cells( 1, 3 ):Value :=Hb_oemtoansi("Цена") oSheet:Cells( 1, 4 ):Value :=Hb_oemtoansi("Ед.изм") oSheet:Cells( 1, 5 ):Value :=Hb_oemtoansi("Группа") oSheet:Cells( 1, 6 ):Value :=Hb_oemtoansi("Фирма") oSheet:Cells( 1, 7 ):Value :=Hb_oemtoansi("Примечание") oWorkBook:saveas(hb_CurDrive()+":\"+CurDir()+"\price.xls") oWorkBook:close(.f.,,.f.) oExcel:Quit() oWorkBook:=nil oSheet:=nil oExcel:=nil endif return ********************** func Start_Excel() Local Res:=.f. #ifndef __XHARBOUR__ #xcommand TRY => BEGIN SEQUENCE WITH {|e| Break( e )} #xcommand CATCH [<!oErr!>] => RECOVER [USING <oErr>] <-oErr-> #endif TRY oExcel := GetActiveObject( "Excel.Application" ) oExcel:DisplayAlerts:=.f. Res:=.t. CATCH Res:=.f. TRY oExcel := CreateObject( "Excel.Application" ) Res:=.t. CATCH Res:=.f. END END Return Res [/pre2]

Dima: Разобрался. Пришлось добавить REQUEST HB_CODEPAGE_RU1251 hb_cdpSelect( "RU1251" ) ранее и без этого нормально было.

Softlog86: Подскажите : Есть строковое значение Артикул - может быть как строкой так и числом (по факту в DBF базе как символьное значение) . При записи этих артикулов - EXCELL отрезает лидирующий ноль , то есть значение '0125' запишет как '125' Каким способом принудительно заставить EXCELL этого не делать ? Тоесть ячейка по факту должна быть ТЕКСТОВОЙ .... соотв. значения не модифицируются ! Какие ещё есть команды чтоб обойти эту дрянь ?

Pasha: Указать формат ячейки - текстовый, или программно: oSheet:Cells(nRow, nCol):NumberFormat := "@"

Softlog86: Символ собаки "@" - это текстовый ? Если можно - сообщите какие ещё команды управления форматами . Мне нужнее всего текстовый и дата

Andrey: Softlog86 пишет: Мне нужнее всего текстовый Пробел добавь впереди и будет тебе текстовый формат.

Pasha: Softlog86 пишет: Символ собаки "@" - это текстовый ? Если можно - сообщите какие ещё команды управления форматами . Мне нужнее всего текстовый и дата Да, текстовый. А насчет остальных форматов - сделайте запись макросов, и гляньте сами. У меня на работе и экселя то нет, чтобы посмотреть :)

Softlog86: Andrey Пробовал ! Пробел не решает сути вопроса - Эксель автоматом рубит лидирующий ноль если в строке только цифры . Так что " 0123" всё-равно получается как "123" . Паша верно подсказал - теперь всё работает как надо !

Dima: Вопросец назрел. Excel уже открыт и в нем загружена куча документов. Необходимо средствами Harbour создать документ Excel , заполнить его , сохранить и выйти. Как при этом оставить открытыми ранее документы , ведь по команде oExcel:Quit() закроются все. Как корректно это реализовать ?

Haz: Dima пишет: ведь по команде oExcel:Quit() закроются все Дима, открывай 2 объекта в примере OExcelTwo останется открыт : oExcel := CreateObject( "Excel.Application" ) oExcelTwo := CreateObject( "Excel.Application" ) oExcel:WorkBooks:Add() oExcelTwo:WorkBooks:Add() oExcelTwo:Visible := .T. oExcel:Visible := .T. oExcel:Quit()

Dima: Haz Да точно это я тормознул что то. Сенкс.

Dima: Хотя........ Я делал вот так [pre2] proc main private oExcel if Start_Excel() oExcel:WorkBooks:Add() oExcel:Visible := .t. oExcel:Quit() endif return ************** func Start_Excel() Local Res:=.f. #ifndef __XHARBOUR__ #xcommand TRY => BEGIN SEQUENCE WITH {|e| Break( e )} #xcommand CATCH [<!oErr!>] => RECOVER [USING <oErr>] <-oErr-> #endif TRY oExcel := GetActiveObject( "Excel.Application" ) oExcel:DisplayAlerts:=.f. Res:=.t. CATCH Res:=.f. TRY oExcel := CreateObject( "Excel.Application" ) Res:=.t. CATCH Res:=.f. END END Return Res [/pre2] В этом случае закрывается все в Excel Понял в чем дело.....надо переделать слегка Start_Excel() что бы понять делать ли при выходе из проги oExcel:Quit()

Haz: я делаю примерно так же но через ссылку типа того: Func Main() local oExcel StartExcel( @oExcel ) IF Valtype(oExcel) == "O" .... ELSE ... END RETURN NIL В общем смысл в том что в стартексель передаем ссылку на любую переменную, и она становится объектом ексель и какой объект закрывать вопросов не вызывает )

Dima: Haz Это понятно. А мой косяк был в том что использовал уже существующий объект EXCEL , поэтому по oExcel:Quit() все и закрывалось

Sergy: Дабы не плодить новых тем, спрошу здесь. Название темы подходящее. Программа на Harbour формирует отчет в формате XLS методом OLE. Отчет сформирован, сохранен в локальной папке, осталось его открыть. Раньше не парился, делал RUN("excel /e "+cXlsName) и все дела. Все неплохо, но если путь к Excel на машине не прописан - разумеется облом. Нужно либо прописывать путь, либо кидать батник excel.bat, содержащий строку запуска в папку с программой. Захотелось сделать все красиво и элегантно, (как сам Harbour:) ). Пробовал: 1) Создание Excel-объекта с открытием нужного файла - проблема оказалась в том, что после отработки последней строки типа oExcel.WindowState := Maximized управление передается назад программе. А она должна удалить xls файл и локальной папки. Соотв. пока Excel не "отпустит" файл - ничего не выходит. 2) Делал RUN("start /w "+xlsName) - облом на длинных именах, даже помещенных в двойные кавычки. Удивлен. 3) Пока остановился на RUN('cmd /c "'+cXlsName+'"') - и длинные имена понимает и путь к самому Excel прописывать не требуется. Но вот какой вопрос возник: если юзер УЖЕ РАБОТАЕТ с Excel (например, с другим документом) и из Harbour-программы вызывает этот отчет - он формируется, открывается и... сразу управление возвращается программе. Та пытается удалить временный файл с отчетом - разумеется облом, тк он еще открыт. Какие могут быть варианты? Пытаться зациклить программу "по кругу", пока файл можно будет удалить - мне кажется не совсем "правильным" способом. К тому-же так вышло, что создание и удаление временных файлов сосредоточено в одном месте, а вызов и обработка формата Excel - в другом. Если Excel-модуль будет пытаться удалить файл, то придется в вызывающем коде тоже городить огород. Кроме этого, есть часть отчетов, которые не должны быть удалены. Модуль формирования Excel отчетов об этом не в курсе. Подскажите плиз элегантное решение.

petr707: Можно создать "очередь" - список файлов, заявленных на удаление. Добавление в список - в одном месте кода, удаление файлов по списку можно позже и в любом другом месте кода. В рамках одного экземпляра программы - для очереди можно взять массив, для разных - таблицу. При попытке удаления одного файла - нужно проверить возможность этого: файл есть и можно открыть (и закрыть) файл XLS монопольно - fopen(f_name,FO_EXCLUSIVE) Для открытия XLS файлов __RUN("start "+f_name)

Sergy: Да, про FOPEN() как-то не подумал - СПАСИБО! Нужно будет сделать. А то уж шальные мысли в голову лезли - пытаться переименовать... По поводу "start" - только у меня эта команда тупо игнорирует длинные имена файлов? Вместо запуска Экселя на 'start "d:\dir\some long name file.xls"' открывает консольное окно (Microsoft Corporation...) и ждет команд... А по запуску Excel - запустить, когда вернется управление - лучшего решения, чем зациклить пока не получится открыть монопольно, нет ?

nick_mi: Ну если это Harbour, открыть и показать пользователю через OLE ( CreateObject("Excel.Application") ) и проверять например, получая какую-нибудь ячейку. Если это не объект, идти дальше работать

petr707: Фишка в том, что запуск __RUN("start "+xls) открывает окно EXcel, но Harbour-программа не ждет закрытия окна Excel, оно живет независимо и отдельно (похоже, так устроен вызов Win Gui приложений) а программа пилит дальше. Можно, если надо, определить через какой-то момент - запустился Excel или нет. Поэтому - не нужно сразу удалять файл и не нужно ничего ждать в цикле. пример - открывается 5 окон XLS Proc main() Local i,f_name REQUEST HB_LANG_RU866 HB_LangSelect( "RU866" ) REQUEST HB_CODEPAGE_RU866 HB_CDPSELECT( "RU866" ) for i=1 to 5 f_name := "_t_это_пример_номер_"+alltrim(str(i))+".xls" copy file ("test.xls") to (f_name) __run("start "+f_name) next i ? "Press any key" inkey(10) return

nick_mi: Но ведь Sergy писал Но вот какой вопрос возник: если юзер УЖЕ РАБОТАЕТ с Excel (например, с другим документом) и из Harbour-программы вызывает этот отчет - он формируется, открывается и... сразу управление возвращается программе. Та пытается удалить временный файл с отчетом - разумеется облом, тк он еще открыт. т.е. по идее ему нужно стоять и ждать, пока не закончится EXCEL. А вообще-то пусть уже он решает, наше дело предложить решение

PSP: Можно очищать папку с временными файлами при старте программы. В этот момент все они обычно уже не нужны. Но, если какой-то будет отрыт другим приложением, - ничего страшного, пусть остается. Удалится в следующий раз. Вот, к примеру, во временной папке пользователя в винде таких "нужных" файлов иногда десятки тысяч. И ничего, работает... )))

Dima: PSP пишет: Можно очищать папку с временными файлами при старте программы То же так делаю

Sergy: nick_mi пишет: т.е. по идее ему нужно стоять и ждать, пока не закончится EXCEL. Вопрос возникает, только если Excel был запущен раньше, чем сформирован отчет: управление сразу возвращается в программу.

Sergy: PSP пишет: Можно очищать папку с временными файлами при старте программы. В этот момент все они обычно уже не нужны. Но, если какой-то будет отрыт другим приложением, - ничего страшного, пусть остается. Удалится в следующий раз. Вот, к примеру, во временной папке пользователя в винде таких "нужных" файлов иногда десятки тысяч. И ничего, работает... ))) Согласен. Сам так делаю. Но захотелось красивого решения. Пока остановился на вызове через OLE с немедленной передачей управления назад. Это чтобы не гадать вернется/не вернется. А после возврата программа в цикле с интервалом в полсекунды пытается открыть файл в режиме FO_EXCLUSIVE. Как только открылся - значит работа с файлом завершена, а закрыл юзер Excel или продолжает в нем работать с другим документом - дело десятое...

nick_mi: Но ведь нужен вариант который будет работать правильно во всех случаях. Можно, конечно проверить, как показано у Dima oExcel := GetActiveObject( "Excel.Application" ) и в зависимости от этого выпускать или Run () или oExcel := CreateObject( "Excel.Application" ) и выполнять проверку, так как я писал выше правда, в этом случае тоже цикл, но только не FOPEN (cFile,FO_EXCLUSIVE) а на наличие объекта.Пока объект существует, программа будет ждать, независимо от того, запущен ранее EXCEL или запущен из вашей програмы

Sergy: nick_mi пишет: Пока объект существует, программа будет ждать, независимо от того, запущен ранее EXCEL или запущен из вашей програмы Хм. звучит логично. Ну вот допустим, Excel не был запущен. Юзер сформировал отчет, мы создали CreateObject("Excel.Application") и ждем, пока он не исчезнет. Но юзер решил в Экселе с сформированным отчетом открыть еще один документ: например, ему туда нужно вставить данные из только что сформированного отчета. Получается, пока он не закроет все документы и не выйдет из Excel, работать с программой он не сможет? А если ему нужно сформировать другой отчет ? Но ведь нужен вариант который будет работать правильно во всех случаях. Да и потом, не очень понятно, какая разница, чего ожидать в цикле - исчезновения объекта или возможности открыть файл в FO_EXCLUSIVE режиме ?

nick_mi: 1) Пока пользователь не закроет документ в EXCEL, программа будет ждать, если документ закрыт независимо от того работает EXCEL дальше с другим документом, или полностью из него вышли программа продолжит свою работу . 2) Разница собственно только в обращению к диску, или проверка объекта в памяти. Решать вам

SadStar55: есть такой код - сохраняет сформированную новую книгу в файл предварительно сформировав имя файла и удалив старый файл [pre2] // сохранить cFile:=wReport01.txt_Folder.Value if RIGHT(cFile, 1)#"\" cFile:=cFile+"\" endif cFile:=cFile+str(wReport01.Spinner_Year.Value,4)+ STRZERO(wReport01.COMBOBOX_MONTH.Value,2)+ ' '+aPDocs[1,5]+'.xls' if file(cFile) FILEDELETE(cFile) //--> lDeleted endif oBook:SaveAs(cFile) //oBook:SaveAs(cFile, xlExcel9795) <==== в Excell Office 2007 - падает [/pre2] проблема в команде сохранения (я отлаживаюсь на Excel 2003). 1. Если не задаю в cFile расширение '.xls' -- Excel действует хитрым образом. Если в cFile нет точек - то сам приписывает к имени файла '.xls' Если точки есть - то не приписывает. Например сохраненые файлы "C:\public\201308 Рахимов А.П" и "C:\public\201308 Склад.xls" Но первый файл совпадает с cFile и поэтому находится и удаляется. А второй - не совпадает и поэтому Excel начинает задавать вопросы - что не есть хорошо. Да и файл без расширения - очень не хорошо. обязательно приписываю +'.xls' 2. В Excel 2003 - сохраняет и открывает без вопросов. В Excel 2007 - сохраняет без вопросов. А при открытии пишет что формат файла не соответствует расширеню. И действительно - сохраняет в формате .xlsx = (упакованый набор xml-лек) но с расширением xls естесственно. Попробовал задать формат сохранения так oBook:SaveAs(cFile, xlExcel9795) в Excell Office 2007 - падает Посоветуйте либо как правильно задать формат сохранения (что предпочтительно для совместимости со старыми версиями Excel) либо как получить от Экселя расширение файла по умолчанию чтобы подставить в имя файла. либо какой нибудь третий способ решения проблемы

nick_mi: Может отлючить вывод предупреждений в EXCEL? На форуме где-то было, как это сделать. Касалось, по моему, записи, но может и на открытии прокатит.

Haz: попробуйте действительно отключить предупреждения oExcelTpl:SET( "DisplayAlerts", .F. ) ... ... ... oExcelTpl:SET( "DisplayAlerts", .T. )

SadStar55: Haz пишет: попробуйте действительно отключить предупреждения В своей программе я могу отключить. А как отключить у пользователя когда он будет открывать файл в своей Экселке? Мое решение такое [pre2] #define xlExcel9795 43 #define xlExcel8 56 ..... if val(oExcel:get("Version"))<12 oBook:SaveAs(cFile, xlExcel9795) else oBook:SaveAs(cFile, xlExcel8) endif .... [/pre2] Файлы созданные в Excel2007 и в Excell2013 без вопросов открываются в Excel2003. потому что 56 = xlExcel8 (Excel 97 through Excel 2003 formatted files used in Excel 2007, .xls) А xlExcel9795 нужен потому что Excel 2003 не знает о будущем коде формата 56 = xlExcel8

Dima: Покажите на примере плиз как сделать автосумму в определенной ячейке. Скажем в первой колонке заполнены числами 1 и 2 ячейки а в 3-й нужно сделать автосумму. Макрос смотрел и синтаксиса не понял. Спасибо.

Dima: вопрос по разделителям разрядов в макросе EXCEL тупо пишет NumberFormat:="#,##0" попробовал в Harbour получилось как то криво и даже перед 0.00 он рисует ,0.00 Переделал так NumberFormat:="# ##0"+GET_SDECIMAL()+"00" , работает нормально но у меня EXCEL 2003 и не факт что такой код сработает на более свежем EXCEL Вопрос: откуда EXCEL берет этот знак , и корректно ли если я его заменяю на пробел ? PS Как считать разделитель групп разрядов ? Для считывания разделителя дробной и целой части использую [pre2] #pragma BEGINDUMP #include "hbapi.h" #include "windows.h" HB_FUNC( GET_SDECIMAL ) { char sDec[2]; GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, (LPTSTR) sDec, 2 ); hb_retclen( sDec, 1 ); } #pragma ENDDUMP [/pre2] Dima пишет: Как считать разделитель групп разрядов ? Проехали , заюзал LOCALE_STHOUSAND

Sergy: Dima пишет: Покажите на примере плиз как сделать автосумму в определенной ячейке. Скажем в первой колонке заполнены числами 1 и 2 ячейки а в 3-й нужно сделать автосумму. Макрос смотрел и синтаксиса не понял. Не очень понятна суть вопроса... Что мешает записать в ячейку содержимое "=RC[-2] + RC[-1]" ? Получится автосумма двух ячеек слева.

Haz: или так oExcel:ActiveCell:FormulaR1C1 := "=СУММ(R[-" + NTOC(nStart) + "]C:R[-1]C) сумма колонки со строки nStart по активную строку -1

Dima: EXCEL 2003 у меня и у клиента. В ячейку цифры я пишу так .........:NumberFormat:="# ##0"+GET_SDECIMAL()+"00" Он строит у себя отчет и в сформированной таблице видит (для примера одна ячейка) 0,91 наводит на нее курсор и вверху видит 90.65 Когда я у себя строю тот же отчет то в этой же ячейке сразу вижу 90.65 У него разделитель дробной и целой части запятая у меня точка. Почему так по разному EXCEL выводит данные ? По идее у него в ячейке должно отобразится 90,65

Sergy: Dima пишет: EXCEL 2003 у меня и у клиента. В ячейку цифры я пишу так .........:NumberFormat:="# ##0"+GET_SDECIMAL()+"00" Он строит у себя отчет и в сформированной таблице видит (для примера одна ячейка) 0,91 наводит на нее курсор и вверху видит 90.65 Когда я у себя строю тот же отчет то в этой же ячейке сразу вижу 90.65 У него разделитель дробной и целой части запятая у меня точка. Почему так по разному EXCEL выводит данные ? По идее у него в ячейке должно отобразится 90,65 Не очень понятно, о чем речь. NumberFormat - это маска форматирования значения, хранящегося в ячейке. Формат сам по себе - но какое значение туда пишете, что вместо 90,65 получается 0,91 ? "Хорошо-бы увидеть самодостаточный пример" (с)... :)

Dima: Sergy пишет: "Хорошо-бы увидеть самодостаточный пример" (с)... :) Кусочек кода ;) [pre2] oSheet:Cells( jj, i+1 ):NumberFormat:="# ##0"+GET_SDECIMAL()+"00" oSheet:Cells( jj, i+1 ):Value :=vtv // число oSheet:Range(osheet:cells(jj,i+1),osheet:cells(jj,i+1)):BorderAround( xlContinuous, xlThin) oSheet:Columns(i+1 ):AutoFit() [/pre2]

Dima: Проехали , решил вопрос.

Sergy: Dima пишет: Проехали , решил вопрос. Чтобы не наступить на такие-же грабли - в чем оказалась проблема ?

Dima: Sergy Он сделал в EXCEL и винде такие же региональные настройки как у меня в плане разделителей ;)

Softlog86: Помогите решить : Нужно создать несколько файлов EXCELL(таблиц) для дальнейшей рассылки (прайс-листы) . Хочу одновременно создавать несколько листов ( для разных клиентов) в одной книге , а затем эти листы поочередно сохранять в соответствующие файлы . До сего дня подготавливал последовательно ( вызов EXCELL , создание книги , заполнение данными , сохранение книги , закрываем EXCELL ). Но для подготовки большого числа документов я решил делать одновременно : 1) Вызов EXCELL 2) Создание книги 3) Создание Лист 1 , Лист 2 ..... Лиcт N 4) В цикле заполняем листы информацией 5) СОхраняем каждый лист в отдельный файл Закрываем EXCELL Знаний команд не хватает КАК : ДОБАВИТЬ ЛИСТ ? ПЕРЕКЛЮЧИТЬСЯ НА ЛИСТ ? СОХРАНИТЬ ТОЛЬКО НУЖНЫЙ ЛИСТ ? Поможете ?

Pasha: Хоть у объекта worksheet и есть метод SaveAs, я не знаю, как он работает. Обычно сохраняется вся книга, а не отдельный лист. Во всяком случае, надо попробовать, как сработает SaveAs для отдельного листа. А насчет добавления-переключения листов: oSheets := oBook:Sheets Выбор листа по номеру: oSheet1 := oSheets:Item(1) oSheet2 := oSheets:Item(2) Переключение: oSheet2:Select() Хотя можно явно не переключаться на лист, а применять методы непосредственно к интересующему листу (oSheet2) Добавление листа (из справки): oSheets:Add(<Before>, <After>, <Count>, <Type>) Before Optional Variant. An object that specifies the sheet before which the new sheet is added. After Optional Variant. An object that specifies the sheet after which the new sheet is added. Count Optional Variant. The number of sheets to be added. The default value is one. Type Optional Variant. Specifies the sheet type. Can be one of the following XlSheetType constants: xlWorksheet, xlChart, xlExcel4MacroSheet, or xlExcel4IntlMacroSheet. If you are inserting a sheet based on an existing template, specify the path to the template. The default value is xlWorksheet.

Dima: Softlog86 пишет: Но для подготовки большого числа документов я решил делать одновременно : Одновременно все равно не получится да и будет ли такой способ быстрее , не факт. Вот ежели на каждого клиента да в отдельном потоке создавать прайс , тогда другое дело. Но к сожалению мне не удалось запустить EXCEL в отдельном потоке , вероятно он работает только в ST режиме.

Dima: Помогите с рамкой разобраться. Обычную сетку(плюс слитие ячеек) делаю так [pre2] oSheet:Range(osheet:cells(i,1),osheet:cells(i+3,1)):MergeCells:=.t. oSheet:Range(osheet:cells(i,1),osheet:cells(i+3,1)):BorderAround( xlContinuous, xlThin) [/pre2] Нужно что бы плюс к этому нижняя часть рамки была утолщенной. Макросы смотрел и не очень въехал

kia: Dima пишет: Нужно что бы плюс к этому нижняя часть рамки была утолщенной. так не пробовал? oSheet:Range(osheet:cells(i,1),osheet:cells(i+3,1)):Borders(xlEdgeBottom):LineStyle( xlContinuous) oSheet:Range(osheet:cells(i,1),osheet:cells(i+3,1)):Borders(xlEdgeBottom):Weight( xlMedium) константы These define the style of the border xlNone = -4142; Note this is the same as xlLineStyleNone xlContinuous = 1; xlDash = -4115; xlDashDot = 4; xlDashDotDot = 5; xlDot = -4118; xlDouble = -4119; xlSlantDashDot = 13; These define the weight of the border xlHairLine = 1; xlMedium = -4138; xlThick = 4; xlThin = 2; Thise is handy to make borders have the default color index xlAutomatic = -4105; These define the placement of border pieces xlDiagonalDown = 5; xlDiagonalUp = 6; xlEdgeLeft = 7; xlEdgeTop = 8; xlEdgeBottom = 9; xlEdgeRight = 10; xlInsideVertical = 11; xlInsideHorizontal = 12; ps проверить сейчас не могу. взял с рабочего софта, но на другом языке

Pasha: Я устанавливаю границы по другому: oBorder := oCell:Borders(<nNSEW>) где параметр - одно из значений : xlEdgeBottom xlEdgeLeft xlEdgeRight xlEdgeTop и затем: oBorder:LineStyle := xlContinuous oBorder:Weight := xlThin стиль границы конечно можно указать другой

Dima: kia пишет: так не пробовал? oSheet:Range(osheet:cells(i,1),osheet:cells(i+3,1)):Borders(xlEdgeBottom):LineStyle( xlContinuous) oSheet:Range(osheet:cells(i,1),osheet:cells(i+3,1)):Borders(xlEdgeBottom):Weight( xlMedium) Cпасибо , заработало вот так oSheet:Range(osheet:cells(i,1),osheet:cells(i+3,1)):Borders(xlEdgeBottom):LineStyle:=xlContinuous oSheet:Range(osheet:cells(i,1),osheet:cells(i+3,1)):Borders(xlEdgeBottom):Weight:=xlMedium

Dima: Pasha Идею понял. Тоже подойдет. Спасибо !

Dima: что еще может работать в Harbour c EXCEL кроме OLE ? Оля медленно работает.

fil: ADO видимо А в чем тормоз ?

Dima: fil пишет: А в чем тормоз ? Ну это моё наблюдение на чисто выпуклый морской глаз. Заполняю EXCEL форму 100 строк 10 колонок в цикле построчно. Если заполнять DBF базу такую же ,то это происходит раз в 5 быстрее если не больше. Реально в своей задаче я делаю выборку во временную DBF базу и затем на основании её заполняю EXCEL форму и хорошо видно что ОЛЯ работает медленнее. В общем то на форуме где то уже писали ОЛЯ медленный механизм. С ADO не работал. Он умеет с EXCEL работать ?

fil: А ты, небось, каждую ячейку строки отдельно заполняешь ? ADO умеет с EXCEL работать ? Вроде как, у Линареса посмотри

Dima: fil пишет: А ты, небось, каждую ячейку строки отдельно заполняешь ? Ну типа да ;) А что не так ?

fil: Вот поэтому и медленно. Надо типа так for st=1 to 100 oExc:ActiveSheet:Range("A"+ltrim(str(st))+":J"+ltrim(str(st))):value:=массив[st] next и будет шустро

Haz: ADO умеет с EXCEL работать ? Дима, привет. Лови пример ADO Function Read_XLS Local cFile := 'TEST.XLS' oConection = todbc():new("Driver={Microsoft Excel Driver (*.xls)};DriverId=790;Dbq="+ cFile + ";DefaultDir="+GetCurrentFolder()+";") oConection:Setsql("SELECT * FROM [ЛИСТ1$]") if !oConection:Open() ? " Error connection " return endif for n := 1 to len(oConexion:aRecordSet) for j := 1 to len(oConection:aRecordSet[n]) do case case valtype(oConection:aRecordSet[n][j]) == "C" ? alltrim(oConection:aRecordSet[n][j]) case valtype(oConection:aRecordSet[n][j]) == "N" ? alltrim(str(oConection:aRecordSet[n][j])) case valtype(oConection:aRecordSet[n][j]) == "D" ? alltrim(DtoC(oConection:aRecordSet[n][j])) case valtype(oConection:aRecordSet[n][j]) == "L" ? alltrim(oConection:aRecordSet[n][j]) end case next next oConection:Close() oConection:Destroy() Return

Dima: Haz Спасибо. Думаешь он быстрее будет ? А в нем доступны вещи типа : назначить шрифт , изменить его размер , залить фон ячейки цветом , рамочки построить и т д и тп то что доступно через Олю ? fil пишет: for st=1 to 100 oExc:ActiveSheet:Range("A"+ltrim(str(st))+":J"+ltrim(str(st))):value:=массив[st] next То есть ты заполняешь ячейки построчно с колонки А по J. А что ж тогда лежит в элементе массива ? Ведь каждую ячейку нужно заполнить своим значением.

fil: Каждый элемент массива это инфа для ячейки { {1,2,3,..10} {11,12,13...20}} чего тут неясного ? Если в форме много формул, желательно сначала отключить автоматический расчет (application.clculation), а потом включить и пересчитать

Dima: fil Прикольно , не знал что так можно делать. Проверил , работает. Сенкс !

Haz: Dima пишет: и тп то что доступно через Олю нет , только данные , лучший вариант предложил fil, а я просто внес альтернативу как пример

Dima: Haz пишет: лучший вариант предложил fil Да сделал тестовый пример , по его методе скорость выше примерно в 5-6 раз.

Andrey: Dima пишет: Да сделал тестовый пример , по его методе скорость выше примерно в 5-6 раз. А посмотреть на сам тест и пример можно ?

Dima: Andrey Да конечно. [pre2] Proc main local oExcel local oWorkBook local oSheet local secs:=0 local i oExcel := CreateObject( "Excel.Application" ) IF Valtype(oExcel) == "O" oExcel:Visible := .f. oExcel:DisplayAlerts:=.f. oWorkBook := oExcel:WorkBooks:Add() oSheet := oExcel:ActiveSheet() oSheet:Cells:Font:Name := "Arial Cyr" oSheet:Cells:Font:Size := 12 oExcel:ActiveWindow:DisplayZeros:=.F. secs:=seconds() for i=1 to 1000 oSheet:Cells( i, 1 ):Value:=1 oSheet:Cells( i, 2 ):Value:=date() oSheet:Cells( i, 3 ):Value:=time() oSheet:Cells( i, 4 ):Value:="TEST" oSheet:Cells( i, 5 ):Value:=1000 oSheet:Cells( i, 6 ):Value:=112345.123 oSheet:Cells( i, 7 ):Value:=dtos(date()) oSheet:Cells( i, 8 ):Value:=2 oSheet:Cells( i, 9 ):Value:=3 oSheet:Cells( i, 10 ):Value:=4 next ? seconds()-secs secs:=seconds() for i=1001 to 2000 oSheet:Range(osheet:cells(i,1),osheet:cells(i,10)):Value:={1,date(),; time(),"TEST1",1000,112345.123,dtos(date()),2,3,4} next ? seconds()-secs wait oExcel:Visible := .t. ENDIF return [/pre2] PS У меня при 1000 строках и 10 столбцах быстрее в 5 раз. 100 строк и 10 столбцов в 7 раз

Andrey: Dima пишет: Да конечно. Спасибо БОЛЬШОЕ !

Dima: WVT программа. Задача установить что открыт нужный лист EXCEL. Такую проверку я сделал но почему то после проверки оказываюсь в EXCEL (оно как бы понятно почему). а надо бы вернуться в программу. Как это правильно сделать ? Делаю примерно так [pre2] do while .t. if Start_EXCEL() IF Valtype(oExcel) == "O" oExcel:Visible := .f. oExcel:DisplayAlerts:=.f. oSheet := oExcel:ActiveSheet() if oSheet:UsedRange:Columns:Count#15 oExcel:Visible := .t. soob("Открыта не та книга........","r/r","gr+/r") exit endif oExcel:Visible := .t. ELSE soob("Объект не найден.........","r/r","gr+/r") exit ENDIF endif exit enddo [/pre2] Решил пробнуть hwnd:=hb_gtInfo(HB_GTI_GETWIN) а затем Hb_gtInfo( HB_GTI_SETWIN, hwnd) , но hb_gtInfo(HB_GTI_GETWIN) совсем ни чего не возвращает.

fil: Правильно ли я понял, что нужно типа листнера состояния Excel ? Тогда можно сидеть на окне и по таймеру опрашиваать

Dima: fil Нужно: опросил состояние EXCEL и остался в окне своей проги.

fil: ну так в чем проблема сделать это по таймеру ?

Haz: Dima пишет: опросил состояние EXCEL и остался в окне Дима, а :Visible := .T. зачем если не та книга ? Как еще вариант - из цикла вызывать проверку отдельным потоком , который всегда можно прибить в случае ненадобности PS. Протестировал выгрузку в Excel через ADODB - результат устроил полностью 10 000 строк выгружается 5 сек

Dima: Разобрался. Просто не нужно юзать oExcel:Visible. Странная штука. Если ячейки я могу заполнить вот так oSheet:Range(osheet:cells(1,1),osheet:cells(1,5)):Value:={1,2,3,4,5} А если сделать обратную операцию и считать значения в массив amas:=(oSheet:Range(osheet:cells(j,1),osheet:cells(j,15)):Value) То массив имеет вид не {1,2,3,4,5} а {{1},{2},{3},{4},{5}} Это нормально ?

fil: массив имеет вид не {1,2,3,4,5} а {{1},{2},{3},{4},{5}} Нормально.

Dima: Haz пишет: PS. Протестировал выгрузку в Excel через ADODB - результат устроил полностью 10 000 строк выгружается 5 сек А где можно пример посмотреть по работе с EXCEL ? Что то не нашел. Смотрел тут harbour\contrib\hbwin\tests\

Haz: Dima пишет: А где можно можно в исходниках ADORDD на core-master но я тестил проще #include 'adordd.ch' Func Test() local cFile := "TEST.XLS" local cConnectStr := 'Provider=Microsoft.Jet.OLEDB.4.0; Data Source= ' + cFile + ';Extended Properties= "Excel 8.0;HDR=YES"' local oConnection := TOleAuto():New( "ADODB.Connection" ) local oCommand local i := 0 oConnection:ConnectionString := cConnectStr oConnection:Open() oCommand := TOleAuto():New("ADODB.Command") oCommand:ActiveConnection := oConnection oCommand:CommandText = "CREATE TABLE [МояТаблица] (Символьный char(255), Дата date, Целый int, Дробный float)" oCommand:Execute() For i := 1 TO 10000 oCommand:CommandText = "INSERT INTO [МояТаблица] (Символьный, Дата, Целый, Дробный) values ('АБВГДЕЁ', '12/4/1955', '1234567', '12345,6789')" oCommand:Execute() END return nil PS если TEST.XLS есть - не сможет создать и выдаст ошибку

Dima: Haz Спасибо !

Haz: Dima пишет: Спасибо незачто Есть смысл в Excel гнать через ADO, а потом красоту наводить через OLE

Dima: а как загнать нужные строки в группу ? Что то макрос мало что сказал....

Sergy: Dima пишет: а как загнать нужные строки в группу ? Что то макрос мало что сказал.... Речь об объединении ячеек ? Мой макрос вот что показал: [pre2]Sub Макрос1() Range("D8:D10").Select With Selection .HorizontalAlignment = xlGeneral .VerticalAlignment = xlBottom .WrapText = False .Orientation = 0 .AddIndent = False .ShrinkToFit = False .MergeCells = True End With End Sub [/pre2] Работает там последняя строка. Все остальные - задают параметры вновь создаваемого объединения.

Dima: Sergy Да оно , спасибо !

Dima: EXCEL 2003 В нем вообще работает заливка фона вида Interior.Color = RGB(220,220,220) , пробовал через макрос и похоже что не работает и цвета берутся из ColorIndex PS Хотел серым цветом залить от 10 до 15 % черного и ни как.

Sergy: Dima пишет: Хотел серым цветом залить от 10 до 15 % черного и ни как. Работает в любом Экселе, от 97 до 2010 точно: ... Selection.Interior.ColorIndex = 15 вот тут: http://infostart.ru/public/58191/ есть другие цвета.

Dima: Sergy 15 не подходит в том и дело. нужно светлее. а цвета я тут смотрю http://www.databison.com/excel-color-palette-and-color-index-change-using-vba/

fil: Приветствую ! В лист Excel нужно вставить разрыв страницы - HPageBreaks. Никак не разберусь как это выглядит в Харборе ?

Dima: не оно ? http://fivetechsupport.com/forums/viewtopic.php?f=3&t=12959&p=65907&hilit=HPageBreaks#p65907

fil: Все работает

fil: Только замедление в разы

fil: Интересно, почему вставка более чем 1 разрыва страницы жутко тормозит ?

Dima: fil Процесс формирования тормозит или уже готовая таблица ?

fil: Тормозит сам ввод разрыва станицы (даже попробовал вставить разрывы после созданияих документа, таже песня). Впечатление такое, что после каждой вставки запускается некая обработка

nick_mi: А долго это сколько? Я попробовал, ну чтоб для нормальной статистики, 200 разрывов- 5 секунд. Приведите кусок кода по разрывам

Dima: nick_mi пишет: Я попробовал, ну чтоб для нормальной статистики, 200 разрывов- 5 секунд. Пример не большой можно ? Проверю на своем оффисе 2003

nick_mi: [pre2] function main () local oExel local osheet local ocell local opagebreak local line_break local time1 local time2 cls time1 := time() If ( oExcel := win_oleCreateObject( "Excel.Application" ) ) != NIL oExcel:Visible := .t. oWorkBook := oExcel:WorkBooks:open("D:\PUBLIC\harbexamp\obdc.xls") osheet := oWorkBook:WorkSheets(1) opagebreak := osheet:HPageBreaks() line_break := 0 For I:= 1 to 200 line_break := line_break + 20 ocell := osheet:cells(line_break, 1) opagebreak: add (ocell) next oExcel:Visible := .t. time2 := time () @ 1,1 say "Time1="+ time1 + " Time2=" + time2 inkey (0) EndIf [/pre2]

Dima: nick_mi пишет: 200 разрывов- 5 секунд. Так и есть , 5 секунд.

nick_mi: Мож просто комп очень медленный, поэтому жутко тормозит

fil: Вроде разобрался - тормоза это следствия леченного вируса (именно с офисои иногда проблемы)

Dima: В EXCEL (2003) в меню Сервис - Параметры - Международные ,есть галя "Использовать системные разделители". Считать системные разделители я могу. А как считать разделители в самом EXCEL если галя снята с пункта "Использовать системные разделители" ? + Как узнать в каком положении находится пункт "Использовать системные разделители" (вкл/выкл)? ЗЫ Проехали , поюзал макрос (не думал что сработает)

Softlog86: Подскажите , как узнать номер последней строки в Эксел-таблице ? То есть нужно отследить , когда заканчиваются данные . С макросом как-то не получается :(

Dima: Softlog86 oSheet:UsedRange:Rows:Count

Dima: Вот такая вот табличка Большой беленький прямоугольник в левом верхнем углу - результат работы oSheet:Range(osheet:cells(1,1),osheet:cells(2,3)):MergeCells:=.t. Вопрос: Места в нём гуляй не хочу. Каким образом можно в нём написать несколько строк текста ?

Haz: а так osheet:cells(1,1):Value := "Несколько строк текста"

Dima: Ёлки , я пробовал руками в EXCEL это сделать не получилось. А из проги в ряд строк вывести не проблема оказывается ;) oSheet:Cells(1,1):Value:="Проверка1"+chr(10)+"Проверка2"+chr(10)+"TEST"+chr(10)+"hgjhgjhg"+chr(10)+"1111111111"

Haz: Dima пишет: руками в EXCEL это сделать не получилось вместо ENTER жми ALT+ENTER

Dima: Haz Дякую

Dima: Макрос EXCEL ActiveWorkbook.Colors(15) = RGB(234, 234, 234) Как сделать на Harbour ? Пробнул так OExcel:ActiveWorkbook:Colors(15):RGB(234,234,234) не компилится ........

Haz: Dima пишет: Макрос EXCEL Дим, а цвет чего он устанавливает ?

Dima: В EXCEL есть стандартные заливки фона. Например (Harbour) oSheet:Cells(jj,2):Interior:ColorIndex:=15 ColorIndex:=15 это 25 процентов серого а мне надо всего 15 процентов серого. Попробовал в EXCEL изменить цвет этой заливки и получил макрос который привел выше

Haz: понял ) тогда так OExcel:ActiveWorkbook:Colors(15, RGB(234,234,234) )

Dima: Неа. Неверный аргумент COLORS Ошибка WinOLE/1007 Код DOS ошибки -2147352562 Я еще пробовал ячейку красить так oSheet:Cells(jj,2):Interior:Colors:=RGB(234,234,234) // до лампочки , все равно 25 процентов серого

Haz: странно у меня сработало тестил так oExcel:ActiveWorkbook:Colors(15, RGB(234,100,200) ) oSheet:Cells(1,1):Interior:ColorIndex:=15

Dima: Не фига тогда не понимаю ;) [pre2] Вот так не компилится OExcel:ActiveWorkbook:Colors(15):=RGB(234,234,234) и вот так не компилится OExcel:ActiveWorkbook:Colors(15):RGB(234,234,234) Компилится только толку ноль от такого вызова OExcel:ActiveWorkbook:Colors(15) Компилится , но в работе падает с ошибкой OExcel:ActiveWorkbook:Colors(15,RGB(234,234,234) ) [/pre2]

Haz: так тоже сработало oExcel:ActiveWorkbook:SET("Colors", 15, RGB(234,100,200) ) PS. мож от версии экселя зависит ...

Dima: Haz пишет: oExcel:ActiveWorkbook:SET("Colors", 15, RGB(234,100,200) ) Жесть а у меня снова ошибка ОЛИ

Dima: Вероятно дело не в Harbour а в версии EXCEL. У меня 2003

Haz: Dima пишет: Вероятно дело не в Harbour а в версии EXCEL. У меня 2003 и не просто в версии , а можбыть в сборке. На одной работает в 2003 на другой нет , на 2007 вроде везде работает

Haz: и так тоже работает oExcel:Selection:Interior:Color := Rgb(240, 240, 240) только Color , а не ColorS

Dima: Haz Получается что в моем EXCEL из Harbour я не смогу сменить 15-й ColorIndex на свой цвет

Dima: Haz пишет: oExcel:Selection:Interior:Color := Rgb(240, 240, 240) Игорь я писал выше что да такой вызов работает , но заливка получается не Rgb(240, 240, 240) а такая же как с ColorIndex:=15

Haz: сможешь, но пока не совсем ясно как . Макрос ведь работает , значит меняет Мож Excelсменить

Haz: Ты писал через "S" oSheet:Cells(jj,2):Interior:Colors:=RGB(234,234,234) // до лампочки , все равно 25 процентов серого

Haz: Сорь, я уехал ..... а Excel смени

Dima: Haz пишет: Ты писал через "S" Да то моя очепятка на форуме. В реале без этой буквы. Вот так Interior:Color:=RGB(234,234,234) и заливка получается БЕЛОЙ а не серый 15 %

nick_mi: вот так получается серой только последние две ячейки obook:sheets(1):cells(2,2):interior():color := RGB(234,234,234) obook:sheets(1):cells(3,3):interior():color := RGB(230,230,230) obook:sheets(1):cells(4,4):interior:color := RGB(225,225,225) obook:sheets(1):cells(5,5):interior:color := RGB(220,220,220) obook:sheets(1):cells(6,6):interior:color := RGB(210,210,210) почему так - хз, наверное, Мелкософт рулит

Dima: Ладно поставим вопрос иначе ;) Имеем макрос в EXCEL вида ActiveWorkbook.Colors(15) = RGB(234, 234, 234) В самом EXCEL он срабатывает правильно и со цветами порядок. Как правильно сказать Harbour что бы такой макрос заработал. EXCEL 2003 1. OExcel:ActiveWorkbook:Colors(15):RGB(234,234,234) // Не компилится Harbour-ом 2. OExcel:ActiveWorkbook:Colors(15, RGB(234,234,234)) // Падает прога с ошибкой WinOLE/1007 3. OExcel:ActiveWorkbook:SET("Colors", 15, RGB(234,234,234)) // Падает прога с ошибкой WinOLE/1007 Есть еще варианты ?

Andrey: Haz пишет: и не просто в версии , а можбыть в сборке. На одной работает в 2003 на другой нет , на 2007 вроде везде работает Вопрос может и не совсем в тему, но очень необходим. А как у себя из программы узнать версию EXCEL и WinWord ? Чтобы юзеру в красном окошке сообщить, что может случиться фигня из-за старой версии....

Dima: Andrey пишет: А как у себя из программы узнать версию EXCEL ? oExcel:Version // у меня 11 PS 12 - Excel 2007 11 - Excel 2003 10 - Excel 2000 и тд Или так Ob:= win_oleCreateObject("Scripting.FileSystemObject") ? Ob:GetFileVersion(Путь к EXCEL+"excel.exe") Дорогу к EXCEL можно взять в теме

Haz: Andrey пишет: А как у себя из программы узнать версию EXCEL или вариант посложнее - WMI запрос к системе SELECT VERSION FROM Win32_Product WHERE Caption Like '%EXCEL%' PS. примеры WMI в минигуи ЕСТЬ

Dima: Haz пишет: или вариант посложнее - WMI запрос к системе Или так [pre2] OLocator:=CreateObject("wbemScripting.SwbemLocator") oWMI:= oLocator:ConnectServer() arr:=oWMI:ExecQuery("SELECT * FROM Win32_Product") for each oitem in arr if hb_at("Microsoft Office",oitem:Name)>0 if hb_at("2003",oitem:Name)>0 ? 2003 elseif hb_at("2007",oitem:Name)>0 ? 2007 elseif hb_at("2010",oitem:Name)>0 ? 2010 endif endif next [/pre2]

Haz: Dima пишет: Или так Можно еще папку Program Files просканировать и по циферкам в пути понять версию \Program Files\Microsoft Office\Office15

Dima: Да и это пожалуй самый быстрый способ

Haz: есть еще быстрее из реестра взять по пути Software => Microsoft => Office => [номер версии] но мне нравится через WMI - пофиг что код длинный и долго, зато подход к задаче системный

Dima: Haz пишет: есть еще быстрее из реестра взять по пути Software => Microsoft => Office => [номер версии] Вот и нет. Я только что посмотрел туда и там есть остатки от старых версий , хотя у меня стоит 11 (2003) У меня там 12 , 11 , 8 ,9 ))

Haz: Dima пишет: там есть остатки от старых версий я ж говорил - тогда твой пример с WMI

Dima: Можно вообще не заморачиваться и если отчет заточен под конкретный EXCEL тогда в проге делать такой вызов ;) [pre2] OX:=CreateObject("Excel.Application.12") if valtype(OX)#"O" * Досвидос endif [/pre2]

Haz: Dima пишет: Можно вообще не заморачиваться А вот это правильные слова т.к. у клиента может быть аллергия на микрософт офис и он пользует исключительно опенофис

Dima: Haz что то нафлудили мы с тобой , Андрей и ответ не найдет

Haz: потри лишнее , а кто ищет - тот найдет

Dima: Нужно сделать сетку в диапазоне. Сейчас делаю так osheet:cells(1,1):BorderAround( xlContinuous, xlThin) osheet:cells(1,2):BorderAround( xlContinuous, xlThin) osheet:cells(1,3):BorderAround( xlContinuous, xlThin) Но если строк/столбцов много наверное это будет работать медленно. Если сделать вот так oSheet:Range(osheet:cells(1,1),osheet:cells(1,3)):BorderAround( xlContinuous, xlThin) то сетка будет только по периметру. Нужен быстрый способ сделать сетку на диапазон.

Haz: Dima пишет: Нужен быстрый способ сделать сетку на диапазон. а так oSheet:Range(oSheet:Cells(nRowStart, 1), oSheet:Cells(nRow, 13)):Select() WITH OBJECT oExcel:Selection :Borders(xlDiagonalDown):LineStyle := xlNone :Borders(xlDiagonalUp):LineStyle := xlNone :Borders(xlEdgeLeft):LineStyle := xlContinuous :Borders(xlEdgeLeft):Weight := xlContinuous :Borders(xlEdgeTop):LineStyle := xlContinuous :Borders(xlEdgeTop):Weight := xlContinuous :Borders(xlEdgeBottom):LineStyle := xlContinuous :Borders(xlEdgeBottom):Weight := xlContinuous :Borders(xlEdgeRight):LineStyle := xlContinuous :Borders(xlEdgeRight):Weight := xlContinuous :Borders(xlInsideVertical):LineStyle := xlContinuous :Borders(xlInsideVertical):Weight := xlContinuous :Borders(xlInsideHorizontal):LineStyle := xlContinuous :Borders(xlInsideHorizontal):Weight := xlContinuous ENDWITH

Dima: А это быстрее будет чем делать поячеячно ?

Haz: Dima пишет: А это быстрее будет чем делать поячеячно точно попробуй на большом диапазоне

Dima: Да сделал тестик ;) 100 колонок 1000 строк. Твой способ - доли миллисекунды ;) Мой - 2 минуты. Сложил методу в свою копилку

Dima: Игорь а как снять отметку то что отметилось в Select() ? Гугл копал но нормального ответа не увидел.

Haz: Dima пишет: Игорь а как снять отметку то что отметилось попробуй переселектить cells(1,1):Select()

Dima: Haz пишет: попробуй переселектить cells(1,1):Select() Ну это понятно. Я думал что есть что то типа UNSelect() А каким образом в диапазоне поменять цвет фона ячеек ? Все нашел что то типа :Interior:ColorIndex:=36 в WITH OBJECT oExcel:Selection

Haz: Dima пишет: А каким образом в диапазоне поменять цвет фона ячеек я делел так oHoja:Range(oHoja:Cells(nRow1, nCol1), oHoja:Cells(nRow2, nCol2)):Interior:Color := nColor

Dima: Создаю отчетик в EXCEL и при завершении в проге выдаю oExcel:Visible := .t. В Windows XP сразу появлялось окно EXCEL поверх моей программы и было активным окном. В Windows 7 , оно появляется , но не поверх а рядом. Как изменить такое поведение в Windows 7 ?

Haz: Dima пишет: Как изменить такое поведение в Windows 7 hWnd := oExcel:hWnd ShowWindow(hWnd, 3) //SW_MAXIMIZE=3 SW_NORMAL=1 SW_MINIMIZE=6 BringWindowToTop(hWnd)

Dima: Спасибо Игорь попробую. Надеюсь этот код будет и в XP себя также вести. ЗЫ Проверил. Работает отлично.

Haz: Dima пишет: Надеюсь этот код будет и в XP себя также вести. Да вроде везде одинаково себя ведет. Более того по hWnd можно это окно двигать или менять размеры т.е. можно разделить экран и использовать excel типа для предпросмотра )

Dima: Haz пишет: Более того по hWnd можно это окно двигать или менять размеры т.е. можно разделить экран и использовать excel типа для предпросмотра ) Круто !

Andrey: Haz пишет: hWnd := oExcel:hWnd ShowWindow(hWnd, 3) //SW_MAXIMIZE=3 SW_NORMAL=1 SW_MINIMIZE=6 BringWindowToTop(hWnd) А я долбился года 2 назад, как поверх всех окон выводить Ёксель в Win7 и выше... Спасибо ! А как изменять размеры окна Ёкселя ?

Haz: Andrey пишет: А как изменять размеры окна Ёкселя MoveWindow( hWnd, ...)

Pasha: Пришлось тут заполнять большую форму в экселе: много листов, строки разбиты на множество клеточек Получилось мееееедленно. Строку заполнял традиционным способом: oCell := oSheet:Cells(nRow, nCol) oCell:Value := c1 oCell := oCell:Next oCell:Value := c2 ... Как оказалось, допустим такой синтаксис: aValue := {c1, c2, ...} oSheet:Range(oSheet:Cells(nRow, nCol), oSheet:Cells(nRow, nCol+len(aValue)-1)):Value := aValue При этом заполняется значениями сразу вся строка документа, что значительно быстрее. Некоторые ячейки при этом можно пропускать: aValue := {c1,, c3, ...}

Dima: Pasha Паш об этом уже писалось. И про сеточку и про заполнение.

Pasha: Действительно, я прозевал этот трюк. Но пока сам не пощупаешь.. действительно быстрее в разы Еще лучше преобразовывать адрес ячеек сразу в текст: Вместо: oSheet:Range(oSheet:Cells(nRow, nCol), oSheet:Cells(nRow, nCol2)) использовать oSheet:Range(; if(nCol>26,Chr(Int((nCol-1)/26)+64),'')+Chr((nCol-1)%26+65) + LTrim(Str(nRow)) + ':' +; if(nCol2>26,Chr(Int((nCol2-1)/26)+64),'')+Chr((nCol2-1)%26+65) + LTrim(Str(nRow)) ) это минус вызов 2-х методов excel

Dima: Там еще одна мелочушка. Если присвоение делаем так :={1,2} А вот если в с того же Range считать данные то получим уже в таком формате {{1},{2}}

Dima: В Ёксель задаю отступы листа , но иногда бывает что широкая таблица целиком на страницу не влазит при печати и начинаются авто-переносы. Что надо сказать Ёкселю что бы он вписал таблицу в нужную ширину скажем за счет какой то колонки ?

Dima: Вроде нашлось ;) .FitToPagesWide = 1 .FitToPagesTall = 32000

Dima: Окончательный вариант oSheet:PageSetup:FitToPagesWide:= 1 oSheet:PageSetup:Zoom:= .f. // это обязательно oSheet:PageSetup:FitToPagesTall:= 32000

Haz: Dima пишет: oSheet:PageSetup:Zoom:= .f. // это обязательно все верно делаю так oExcel:ActiveSheet:PageSetup:Zoom := FALSE oExcel:ActiveSheet:PageSetup:FitToPagesWide := 1 oExcel:ActiveSheet:PageSetup:FitToPagesTall := 10 oExcel:ActiveSheet:PageSetup:Orientation := xlLandscape PS. Раньше ответить не мог - винда рухнула, пол дня ставил

Dima: Haz пишет: oExcel:ActiveSheet:PageSetup:Orientation := xlLandscape я в портрет хотел вписать , xlLandscape был не вариант ;) Haz пишет: PS. Раньше ответить не мог - винда рухнула, пол дня ставил Беккап не юзаем конечно (типа Acronis True Image) и точки восстановления тоже ? ЗЫ Если винты у тебя Сигейт или WD , есть бесплатный вариант ATI. Научу что надо делать. Вещь не заменимая. Ну или аналог Paragon Домашний Эксперт Там все довольно просто Игорь.

Andrey: Привет всем. Есть ли у кого простой текст программы для переноса dbf в xls ? База небольшая 30-40 записей. Ну и вверху листа экселя сделать титул и шапку на русском... Или дайте пожалуйста схему как сделать без всяких наворотов. А то я до этого делал обратную задачу из xls в dbf.

Alex_Cher: Например : #define xlWorkbookNormal -4143 FUNCTION MAIN() LOCAL oExcel, oWorkBook, _tec_dir := GetCurrentFolder(), _line := 3 SET LANGUAGE TO RUSSIAN oExcel := TOleAuto():New( "Excel.Application" ) oWorkBook := oExcel:WorkBooks:Open( _tec_dir + "\TEST1.DBF" ) oWorkBook:Cells:Font:Name := "Arial" // Офолрмление колонок, ячеек oWorkBook:Cells:Font:Size := 10 oWorkBook:Columns( 15 ):Set( "NumberFormat", '@' ) oWorkBook:Cells(3, 3):Borders():LineStyle := 1 oWorkBook:Range("A2:D2"):Borders():LineStyle := 1 oWorkBook:columns(14):columnwidth := 18 oWorkBook:Cells( 1, 3):Value := "Титул" DO WHILE .NOT.EOF() oWorkBook:Cells( _line, 1):Value := 1->PU // значени полей DBF oWorkBook:Cells( _line, 2):Value := 1->KF oWorkBook:Cells( _line, 4):Value := 1->TV oWorkBook:Cells( _line, 4 ):Set( "NumberFormat", '@' ) // текстовая ячейка oWorkBook:Cells( _line, 12):Value := 1->ZU oWorkBook:Cells( _line, 12 ):Set( 'NumberFormat', '########0,00' ) // числовая ячейка ....... _line++ SKIP ENDDO oWorkBook:SaveAs( _tec_dir + "\NEW.XLS", xlWorkbookNormal ) oExcel:Visible = .T. RETURN NIL

Andrey: Спасибо БОЛЬШОЕ !

Andrey: Есть цвет из МиниГуи {234,240,207}. Как сделать заливку ячейки в Экселе этим цветом ?

Dima: Как то так ActiveWorkbook.Colors(1) = RGB(234,240,207) Затем красим с индексом 1

Andrey: Alex_Cher пишет: oExcel := TOleAuto():New( "Excel.Application" ) oWorkBook := oExcel:WorkBooks:Open( _tec_dir + "\TEST1.DBF" ) А как сделать без открытия базы ? База у меня открывается в другом месте и не все поля нужно перетаскивать в Эксель. Как создать новый документ xls ?

Andrey: Dima пишет: А посмотри примерчик \svn\harbour\contrib\hbwin\tests\testole.prg Нашёл. Спасибо !

Andrey: Задал фонт на таблицу: oSheet:Cells:Font:Name := "Arial" oSheet:Cells:Font:Size := 15 Как узнать ширину строки заголовка таблицы (например "Кол-во товара") по этому фонту, чтобы установить ширину колонки: oSheet:columns( 2 ):columnwidth := ???

Dima: Сделай проще oSheet:Columns(2):AutoFit()

Andrey: Dima пишет: Сделай проще oSheet:Columns(2):AutoFit() Классно ! Работает. Спасибо !

Andrey: Делаю вывод чисел так: oSheet:Cells( nLine, nI ):SET( 'NumberFormat', '########0,00' ) // числовая ячейка а для целых чисел какой вывод нужно делать ? И как определить по значению - целое число или дробное ?

Dima: Andrey пишет: а для целых чисел какой вывод нужно делать ? гугл ни кто не отменял NumberFormat := '#,##0' ЗЫ // Установим формат целых чисел с разделителем тысяч

Dima: Andrey пишет: И как определить по значению - целое число или дробное ? считай , преобразуй в символьную и чекани строку на предмет ".000" если TRUE значит целое. Хотя может в Ёксель что то есть в этом плане. Гуглить надо.

Andrey: Dima пишет: Хотя может в Ёксель что то есть в этом плане. Гуглить надо. Я это и имел ввиду, что может уже кто знает. Спасибо, погуглил... Решение то оказывается на поверхности лежит: IF INT(xValue) == xValue // значит целое число oSheet:Cells( nLine, nI ):SET( 'NumberFormat', '########0' ) // числовая ячейка ELSE oSheet:Cells( nLine, nI ):SET( 'NumberFormat', '########0,00' ) // числовая ячейка ENDIF

Andrey: Сделал прогу, под Ёкселем 2003 - работает нормально. 5 сек. и появляется таблица. У клиента стоит Ёксел 2007, окно не появляется, пока не залезть в Диспетчер задач и не переключиться на "Microsoft Office Excel - проверка совместимости" и в этом дурацком окне нужно нажать кнопку "Продолжить" !!! Блин, юзера выть будут... Погуглил, решения не нашёл. Подскажите пожалуйста решение ? Или отключить в Ёкселе 2007 эту проверку или при создание в ОЛЕ прописать, что файл 2007 версии.

Dima: Начинаешь так ? CreateObject( "Excel.Application" ) Заканчиваешь так ? oExcel:Visible := .t. ЗЫ Вижу...http://www.planetaexcel.ru/forum/?PAGE_NAME=read&FID=8&TID=23794 Дело не в этом похоже о чем выше я написал. Думаю нужно определять активную версию оффиса ну и дописывать цифирки после точки в "Excel.Application.999" Нужно выложить готовую функцию думаю для проверки версии (100 % работающую) , мне такая была не нужна так как все сидят на 2003. Функцию для CreateObject( "Excel.Application"+VersEXCEL() )

Andrey: Делаю так: oExcel := TOleAuto():NEW( "Excel.Application" ) oWorkBook := oExcel:WorkBooks:Add() Dima пишет: Думаю нужно определять активную версию оффиса ну и дописывать цифирки после точки в "Excel.Application.999" А какие цифирьки для 2007 поставить нужно ?

Dima: Andrey пишет: А какие цифирьки для 2007 поставить нужно ? Погугли я точно не помню так как не использую НО они есть. Где то было на форуме.....лень искать Гугл :) ' open Excel 2003 Set obj1 = CreateObject("Excel.Application.11") ' open Excel 2007 Set obj2 = CreateObject("Excel.Application.12")

Andrey: Ещё нашел такой ключ: ActiveWorkbook.CheckCompatibility = False Может его к себе в прогу засунуть ? Dima пишет: Функцию для CreateObject( "Excel.Application"+VersEXCEL() ) Пишем с точкой или без точки - "Excel.Application.999" - ? Увидел ответ на свой вопрос... Уже ответил. Спасибо !

Andrey: Dima пишет: ? oExcel:Version А как тогда создаем CreateObject("Excel.Application.11"), если версию можем получить после создания объекта ?

Dima: Версию получить нужно ДО создания. Поищи на форуме что то типа "Excel.Application.11"

Dima: http://clipper.borda.ru/?1-4-0-00000578-000-0-0-1345918268 Пост 92 Там же твой ответ "спасибо попробую" , но похоже руки не дошли. Бывает. PS Если разобрался , выкладывай готовую функцию , проверим.

Andrey: Dima пишет: Если разобрался , выкладывай готовую функцию , проверим. Делаю отдельный пример. Как сделаю - выложу !

Dima: Andrey В этой теме посмотри посты номер 4662 , 518

Andrey: Сделал тест. На Excel 2013 тоже работает без проблем. Поставил в виртуалке 2007. Опять фигня, уже в другом месте: Строка 226 - oExcel:ActiveSheet:PageSetup:Zoom := FALSE Что не нравиться опять 2007 ? Блин, ни одного принтера в виртуалке нет... Как у себя в проге проверить, чтобы не вылетало ?

Andrey: Нашёл функцию: oExcel:ActivePrinter - возвращает "неизвестный принтер (проверте Панель Управления)"

Andrey: http://clipper.borda.ru/?1-20-0-00000371-000-0-0-1195742832 Pasha - Пост N: 645 В конце концов остановился на функции Function MSExcel_PATH Return GetRegistry(, "SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\excel.exe", 'Path' ) которая использует стандартные средства харбора для работы с реестром Не работает ! Возвращает NIL

PSP: Andrey пишет: Не работает ! Возвращает NIL А так? "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\excel.exe"

Dima: тоже не пашет с HBWIN win_regRead( "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\excel.exe" ) + это win_regRead( "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Opera.exe" ) win_regRead( "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\firefox.exe" )

PSP: Работает так: win_regRead( "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\excel.exe\Path" )

Dima: PSP Точно !

PSP: Dima пишет: Точно ! И даже больше: если в конце не указывать Path, а оставить только слэш, win_regRead( "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\excel.exe\ то вернет значение параметра "По умолчанию". Просто, если нет слэша, то функция возвращает NIL, потому что "excel.exe" - название раздела, а не параметра.

Dima: PSP пишет: то вернет значение параметра "По умолчанию". Да и имена папок в формате 8.3

PSP: Dima пишет: Да и имена папок в формате 8.3 Для excel - да, для firefox - нормально )))

Andrey: А как заменить внизу: "Лист 1", "Лист 2" ....

Dima: PSP То есть корректно получить версию можно так...или туплю слегка. Первое что пришло в голову left(right(win_regRead( "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\excel.exe\Path" ),3),2)

Dima: Andrey пишет: А как заменить внизу: "Лист 1", "Лист 2" .... Включить макрос как минимум на запись и переименовать руками После смотрим что же там........... [pre2] Sheets("Лист1").Select Sheets("Лист1").Name = "XXX" [/pre2] затем это превращаем в код Harbour. PS Спать ночью надо Андрей

PSP: Dima пишет: То есть корректно получить версию можно так...или туплю слегка. Вот еще есть кое-что: "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office". В этом разделе должен быть подраздел с номером версии, в котором, в свою очередь, подразделы для всех установленных программ. Не знаю, удаляются ли эти ветки из реестра в случае деинсталляции офиса. В принципе, можно проверить, существует ли файл, к примеру excel.exe, по пути из соответствующего подраздела, т.е. File( win_regRead( "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\15.0\Excel\InstallRoot\Path" ) + "\Excel.exe" )

Dima: PSP в этой ветке вижу у себя 11.0 и 9.0 стрянно , ставил только 2003 оффис

Dima: PSP пишет: В принципе, можно проверить, существует ли файл я понял корректного получения номера оффиса нет (включая 32 или 64 бит) , или есть ?

PSP: Dima пишет: PSP в этой ветке вижу у себя 11.0 и 9.0 стрянно , ставил только 2003 оффис Нужно проверять наличие соответствующих путей к exe-шникам в обоих ветках. Если есть и там, и там, - использовать более свежее.

Dima: PSP Понял. Бум думать :) PS 2-х офисов (или более) надеюсь не может быть установлено

PSP: Dima, а какие переменные есть в объекте, который возвращает CreateObject( "Excel.Application" ) ? Сам не могу глянуть сейчас. Нет ли там номера версии?

Dima: PSP Номерок то есть НО после CreateObject( "Excel.Application" ) а нужно ведь сразу создать правильный CreateObject( "Excel.Application"+ExVer() ) типа так oExcel:Version

PSP: Dima пишет: Номерок то есть НО после CreateObject( "Excel.Application" ) а нужно ведь сразу создать правильный CreateObject( "Excel.Application"+ExVer() ) Ну, ок... А если создать без номера версии, прочитать версию, закрыть, а потом создать с нужным номером? Понимаю, что не очень красиво, но, имхо, правильней, чем в реестре рыться.

Dima: PSP Кстати да , вариант.

Andrey: Dima пишет: Sheets("Лист1").Select Sheets("Лист1").Name = "XXX" Спасибо ! Получилось ! Почту свою напомни ?

Andrey: PSP пишет: А если создать без номера версии, прочитать версию, закрыть, а потом создать с нужным номером? Понимаю, что не очень красиво, но, имхо, правильней, чем в реестре рыться. Да не обязательно это делать ! Лист создаётся нормально, только при записи файла вылазит ОКНО-СОВМЕСТИМОСТИ ! Я для себя уже сделал проверку: IF nVerExcel > 11 // Excel 2003 // проверка совместимости на версиях старше 2003 // нельзя записать файл, так как вылазит ОКНО-СОВМЕСТИМОСТИ // из-за этого пускай юзер сам пишет файл lSave := .F. ENDIF

Pasha: Если при заполнении строки листа значениями из массива командой oSheet:Range(oSheet:Cells(nRow, nCol), oSheet:Cells(nRow, nCol2)):Value := aArray внутри строки есть формулы, то эти формулы сносятся, даже если в соответствующей позиции aArray находится значение nil Нет ли какой настройки, чтобы формулы сохранялись ? Или без вариантов ?

Панченко: В Foxpro есть следующая полезная фишка по быстрому заполнению области листа данными из массива с использованием указателя на него: aArray[ nRow, nCol ] - массив данных [pre2]WITH oEcel .WorkBooks.Add .Range(.Cells(x,y), .Cells(x+nRow-1,y+nCol-1)).Value=GetPtr("aArray") ENDWITH . . . Function GetPtr(cArrName) Return @&cArrName[/pre2] Очень удобно и быстро. Как добиться аналогичного результата в Harbour?

Dima: Панченко [pre2] oSheet:Range(osheet:cells(i,1),osheet:cells(i,15)):Value:=; {elem[1],elem[2],elem[3],elem[4],elem[5],elem[6],elem[7],; elem[8],elem[9],elem[10],elem[11],elem[12],elem[13],elem[14],dtoc(elem[15])} [/pre2] Выдрал у себя из сырца , думаю понятно. Впрочем можно и через WITH oEcel

Панченко: Dima Может быть я непонятно написал. Речь идет не о применении WITH или заполнении однрй строки. В моем примере заполняется весь прямоугольный диапазон ячеек за один раз за счет передачи в VALUE указателя на массив значений.

Dima: Панченко Смотри в этой теме пост 239 (от fil) и 3304 (от Pasha) Впрочем я показал тот же подход где VALUE присваивается массив

Панченко: Dima Эти сообщения я видел. Везде речь идет о заполнении ОДНОЙ строки. В примере на ФОКСе заполняется НЕСКОЛЬКО строк и колонок, что дает значительное сокращение времени. Т.е.: [pre]oSheet:Range( oSheet:Cells(5,5),oSheet:Cells(10,70)):Value = ...[/pre]

Панченко: Задача сводится к получению адреса массива. Кто знает С - подскажите, как должна выглядеть эта функция.

Dima: Панченко пишет: oSheet:Range( oSheet:Cells(5,5),oSheet:Cells(10,70)):Value = ... Думаю и тут чудно сработает oSheet:Range( oSheet:Cells(5,5),oSheet:Cells(10,70)):Value: =твой массив

Панченко: Dima пишет: Думаю и тут чудно сработает Увы... Уже проверял - не работает, заполнения всего диапазона не происходит.

Dima: счас подумаем

Pasha: В харборе массив всегда передается по адресу, так что его адрес получать не надо. Надо просто привоить ячейкам значение: <obj>:Value := aArray

Панченко: И в харборе, и в фоксе при присвоении :VALUE = aArray не заполняются 2, 3 и т.д. строки диапазона. В фоксе при присвоении :VALUE = <указатель на массив> все заполняется великолепно. Если же применить промежуточное присвоение типа <переменная> = <указатель на массив> :VALUE = <переменная> то получается заполнение то ли только первой строки, то ли все заполняется первым элементом массива - уже не помню. Кроме того, в функции, возвращающей указатель, массив должен быть виден (например, глобально). Хотел проверить это в харборе, но как получить указатель на массив? В С я "непонимэ".

fil: Считать в массив можно любой ранг из Excel, а вот писать только однострочный массив (по край мере не получилось) но всегда есть ADO..

Панченко: И все-таки, Си-шники, может кто-нибудь набросать функцию, возвращающую указатель на массив по его имени?

Панченко: Может это и бессмысленно, но нужна функция на С, на входе получающая массив (скажем R) и заканчивающаяся return &R. Увы, не знаю синтаксиса С.

Dima: Панченко Хочешь сказать что это ты сам реально проверил ? То есть вот так в Фоксе сработает правильно .Range(.Cells(x,y), .Cells(x+nRow-1,y+nCol-1)).Value=GetPtr("aArray") А вот так уже нет .Range(.Cells(x,y), .Cells(x+nRow-1,y+nCol-1)).Value=aArray

Панченко: Dima пишет: Хочешь сказать что это ты сам реально проверил ? А в чем сомнения? Первый вариант работает во многих моих программах, давно и надежно. Что не так со вторым - я писал выше, что уже не помню. Сегодня специально проверил - весь диапазон заполняется значением первого элемента массива.

Панченко: Именно поэтому и потому, что на практике сталкивался с разными "чудесами" в разных языках, я и прошу пример функции на С, которая принимала бы aArray или "aArray" и возвращала бы (без всяких промежуточных присваиваний) &aArray. Хочу проверить в харборе вариант присваивания ...:Value := <имя_этой_фунции>(aArray /или "aArray"/). Можешь написать?

Dima: Панченко пишет: Можешь написать? Нет я не дружу с СИ Панченко пишет: Сегодня специально проверил - весь диапазон заполняется значением первого элемента массива. Ну это не совсем так. Я спецом тестил. Диапазон был 10 на 10 , 100 ячеек и ему я скормил массив из 100 элементов. Результат по всех строках был одинаков - первые 10 элементов массива. Панченко пишет: А в чем сомнения? Да просто подумал , что ты вычитал где то в инете а на практике , не проверял. Значит я ошибся !

Панченко: Dima пишет: Ну это не совсем так. Я спецом тестил. Диапазон был 10 на 10 , 100 ячеек и ему я скормил массив из 100 элементов. Результат по всех строках был одинаков - первые 10 элементов массива. Странно. Мой массив: 11 12 21 22 31 32 Во все ячейки занеслось 11.

Pasha: Вопрос не в том, как передать массив по ссылке, или как это сделать на С. В харборе массивы и так передаются по ссылке. Вопрос в том, как заполнить диапазон ячеек в Excel из массива В книге Excel добавляю такой макрос: Sub Макрос1() ' Dim AStr(1 To 6) As String AStr(1) = "1" AStr(2) = "2" AStr(3) = "3" AStr(4) = "4" AStr(5) = "5" AStr(6) = "6" Range("A1:C2").Value = AStr Range("A1:C2").Select End Sub после его выполнения ячейки заполняются так: 1 2 3 1 2 3 Точно так же делает харбор через механизм OLE. А как можно заполнить диапазон в fox ? Желательно, чтобы это можно было бы воспроизвести через VBA ?

Dima: И у меня так же [pre2] local j:=1 local arr:={} local oExcel := CreateObject( "Excel.Application" ) local oWorkBook := oExcel:WorkBooks:Add() local oSheet := oExcel:ActiveSheet() for j=1 to 100 aadd(arr,j) next oExcel:Visible := .t. oSheet:Range(osheet:cells(1,1),osheet:cells(10,10)):Value:=arr [/pre2] http://shot.qip.ru/00Pp9x-5Ha2NU8N7/

Панченко: Pasha пишет: В харборе массивы и так передаются по ссылке. Я выше уже писал, что фоксовский трюк работает только напрямую, без промежуточного присвоения адреса. Вся разница в том, в терминах харбор @r - это число, а r - это имя переменной, хранящей адрес первого элемента массива. С интерпретацией этого значения в харборе вопросов не возникает. А при передаче в Excel желаемого эффекта не происходит. Поэтому я и хотел попробовать передать в Excel именно число.

Dima: Панченко пишет: r - это имя переменной, хранящей адрес первого элемента массива Примерчик выше проверь .

Dima: А вот такой макрос заполнит столбец в диапазоне [pre2] Sub Macros1() Dim a(1 To 10, 1 To 1) For i = 1 To 10 a(i, 1) = i Next Worksheets("Лист1").Range(Cells(1, 1), Cells(10, 1)).Value = a End Sub [/pre2]

Dima: Фокус покус [pre2] Sub FillCellRect1() Dim lngRows As Long, intCols As Integer Dim lngRow As Long, intCol As Integer Dim lngStep As Long, lngVal As Long Dim alngValues() As Long Dim rgRange As Range lngVal = 1 lngStep = 1 lngRows = Val(InputBox("Количество ячеек в высоту")) intCols = Val(InputBox("Количество ячеек в ширину")) ReDim alngValues(1 To lngRows, 1 To intCols) Set rgRange = ActiveCell.Range(Cells(1, 1), Cells(lngRows, intCols)) For lngRow = 1 To lngRows For intCol = 1 To intCols alngValues(lngRow, intCol) = lngVal lngVal = lngVal + lngStep Next intCol Next lngRow ' Перенос значений из массива в таблицу rgRange.Value = alngValues End Sub [/pre2] Сырец тут http://www.studfiles.ru/preview/3568974/page:2/ Листинг 2.27.Заполнение диапазона

Haz: Dima пишет: rgRange.Value = alngValues Дима, в VB это работает и полно примеров присвоения двумерного массива. Если это все перенести в Harbour то не работает. Просто назначается всему диапазону первая строка массива

Dima: Haz Да , пытался преобразовать в Harbour , не получилось

Панченко: Панченко пишет: С интерпретацией этого значения в харборе вопросов не возникает. Тоже не совсем так. Имеем массив r := { 1, 2, 3, 4, 5 } и функции [pre2]function fun1( arr ) arr[ 5 ] := 9 return nil function fun2( arr ) arr := { 7, 8, 9 } return nil[/pre2] Если fun1( r ) и fun1( @r ) дают одинаковый результат, то fun2( r ) и fun2( @r ) - разный. Несмотря на то, что Pasha пишет: В харборе массивы и так передаются по ссылке.

Pasha: По-видимому, причина того, что в харборе не работает заполнение диапазона ячеек, следующая: Для типа VARIANT двумерный массив можно представить и как одномерный массив, каждый элемент которого является массивом, и как двумерный вариантный массив. Харбор, что естественно, использует первый вариант. А для заполнения диапазона ячеек нужен второй вариант. Вот в харборе заполнение и не работает.

Pasha: Панченко пишет: Тоже не совсем так. Имеем массив r := { 1, 2, 3, 4, 5 } и функции function fun1( arr ) arr[ 5 ] := 9 return nil function fun2( arr ) arr := { 7, 8, 9 } return nil Если fun1( r ) и fun1( @r ) дают одинаковый результат, то fun2( r ) и fun2( @r ) - разный. Несмотря на то, что Pasha пишет: цитата: В харборе массивы и так передаются по ссылке. В харборе массивы передаются всегда по ссылке. Благодаря этому функция, которая получает массив в качестве параметра, может изменять значение массива, а так же изменять его размерность. Когда в такой функции выполняется присвоение вида: arr := {...} первоначальный массив arr уничтожается, вернее, уменьшается на единицу счетчик его использования, и, если он будет равен нулю, при последующей сборке мусора эти элементы будут уничтожены. А переменной arr присваивается новый массив. Если же переменная arr передана функции по ссылке: как @arr, то вызывающей функции будет доступен новый массив.

Dima: Pasha пишет: Вот в харборе заполнение и не работает. В принципе есть костыль для этого (идея не моя). Массив "правильно" сложить в буффер обмена а затем сделать вставку в Excel.

Haz: Dima пишет: есть костыль Этот костыль успешно прижился в методе :Excel() из класса TsBrowse в Minigui

Pasha: Причем формат буфера обмена там предельно простой: разделитель столбцов по строке - табуляция Chr(9), а разделитель строк - Chr(13). Надо попробовать у себя такой вариант. Все-таки будет быстрее работать, причем гораздо. Правда, при этом теряется информация о типе ячеек - все вставляется как строки. Но такая информация не очень - то и нужна, Excel сам преобразовывает типы данных. Правда, иногда так преобразовывает, что лучше бы не преобразовывал. Но это уже другой вопрос.

Haz: Pasha пишет: Надо попробовать у себя такой вариант. Пробовал , работает и быстрее, Pasha пишет: Правда, при этом теряется информация о типе ячеек - все вставляется как строки. Да, так и есть. Если не доверять Excel самостоятельно определить тип - то можно перед вставкой задать тип на все колонки через ОЛЮ [pre2] Пример для колонки 1 oSheet:Columns(1):Set( "NumberFormat", "(# ##0,00)" ) [/pre2] В догонку: Вставка из буфера обмена производится в выделенный диапазон. К примеру для массива 10 х 10 Можно использовать Range: [pre2] oSheet:Range( osheet:cells(1,1),osheet:cells(10,10) ):Select() oSheet:Paste() [/pre2] Можно ресайсить ячейку [pre2] oSheet:Cells(1,1):Resize(10,10):Select() oSheet:Paste() [/pre2] Результат будет одинаков

Pasha: Excel иногда преподносит сюрпризы. Скажем, обычная строка вида 03/07 или 07/13 неожиданно становится "03 июля" или "июль 2013" Такой же фокус может случиться с числом. Причем фокус-покус происходит, если просто вводить такие данные с клавиатуры. И отключить автоматическое преобразование типов в Excel никак нельзя.

Haz: Pasha пишет: И отключить автоматическое преобразование типов в Excel никак нельзя. Паша, можно перед записью в ячейку указать формат. Можно указать формат всей строки, всей колонки , любого диапазона ячеек или одной ячейки Если попытаться через ОЛЮ записать в ячейку (1:1) строку вида вида 03/07 то Excel преобразует ее к дате и получим бред "03 июля" т.е. простое oSheet:Cells(1,1):Value := "03/07" выдаст "03 июля" Если перед записью указать формат oSheet:Columns(1):Set( "NumberFormat", "@" ) // Вся первая колонка листа назначается символьного формата oSheet:Cells(1,1):Value := "03/07" выдаст правильную строку в ячейке "03/07" все это справедливо и с цифрами. Аналогично и при вводе с клавиатуры , если задать формат ДО ввода - автопреобразования не происходит

Pasha: Паша, можно перед записью в ячейку указать формат Конечно, так и поступаю. По другому никак.

Pasha: Нашел я в коде это место: Строки 712-720 из contrib\hbwin\olecore.c: SAFEARRAYBOUND sabound[ 1 ]; HB_SIZE n, nLen; nLen = hb_arrayLen( pItem ); sabound[ 0 ].lLbound = 0; sabound[ 0 ].cElements = ( long ) nLen; pSafeArray = SafeArrayCreate( VT_VARIANT, 1, sabound ); если заменить на что-то вроде: SAFEARRAYBOUND sabound[ 2 ]; HB_SIZE n, nLen1, nLen2; nLen1 = hb_arrayLen( pItem ); nLen2 = ... sabound[ 0 ].lLbound = 0; sabound[ 0 ].cElements = ( long ) nLen1; sabound[ 1 ].lLbound = 0; sabound[ 1 ].cElements = ( long ) nLen2; pSafeArray = SafeArrayCreate( VT_VARIANT, 2, sabound ); и далее заменить присваивание, то будет создаваться двумерный вариантный массив. Проблема в том, что в каких-то случаях нужен одномерный массив, а в каких-то - двумерный.

Haz: Pasha пишет: Проблема в том, что в каких-то случаях нужен одномерный массив, а в каких-то - двумерный. Паша, проблема в другом ... на форуме, почти для всех ( для многих точно ) все что написано выше цитируемой строки это китайская грамота PS. за упорство - спасибо. Будем хоть знать где это зло живет

Панченко: Pasha Так, может быть, имеет смысл оформить все это дело отдельной функцией?

Haz: Панченко пишет: Так, может быть, имеет смысл оформить все это дело отдельной функцией? Это пол OLE переписать

Панченко: Haz пишет: Это пол OLE переписать Pasha пишет: Строки 712-720 а остальное (как я понял) без изменений. Хотя не утверждаю, что прав. Если это большие трудозатраты, то действительно нет смысла. Будем продолжать работать через буфер обмена.

Pasha: Чтобы не плодить темы, задам маленький вопрос здесь: Open Office Calc Берем ячейку по номеру строки и столбца oCell := oSheet:getCellByPosition(nCol-1, nRow-1) А как теперь выбрать эту ячейку ? Что-то подобное на метод Select() для Excel ? Хочу затем вставить из буфера обмена фрагмент в данную ячейку.

Dima: Паша а там макросы есть в Open Office Calc ? Можно с ним поиграться и посмотреть как выбрать ячейку.

Haz: Open Office Calc Паша, а как в Excel не проходит ? у меня Open не установлен oCell := oSheet:Cells( 10, 2) oCell:Select()

Pasha: Да там макросы не той системы. Фактически в ОО есть 2 структуры объектов, и запись макросов не дает тот результат, как в экселе.

Dima: Дернул в инете , не оно ? //позиционируемся на ячейке Reference< XCell > rCell = rSpSheet->getCellByPosition(x, y); //устанавливаем значение ячейки rCell->setValue(val);

Haz: так работает IF ( oServiceManager := win_oleCreateObject( "com.sun.star.ServiceManager" ) ) != NIL oDesktop := oServiceManager:createInstance( "com.sun.star.frame.Desktop" ) oDoc := oDesktop:loadComponentFromURL( "private:factory/scalc", "_blank", 0, {} ) oSheet := oDoc:getSheets:getByIndex( 0 ) ControlCell := oSheet:getCellByPosition(5, 10) oDoc:CurrentController:Select(ControlCell)

Pasha: Это метод для записи в ячейку, а не для выбора Вот нашел какой-то пример из Delphi, буду пробовать: ControlCell := Sheet.getCellByPosition(j, i); Document.CurrentController.Select(ControlCell);

Pasha: Haz Спасибо, похоже, это то, что нужно

Sergy: Pasha пишет: И отключить автоматическое преобразование типов в Excel никак нельзя. В Экселе всё можно. Сначала для ПУСТЫХ ячеек задать формат. Например, "числовой". Дальше туда пишем что нужно. Например, "07/03" по умолчанию дает у меня "07.мар", если ячейка перед этим была помечена как числовая - 2,33, если как текст - 07/03.

Sergy: Панченко пишет: С интерпретацией этого значения в харборе вопросов не возникает. Тоже не совсем так. Имеем массив r := { 1, 2, 3, 4, 5 } и функции function fun1( arr ) arr[ 5 ] := 9 return nil function fun2( arr ) arr := { 7, 8, 9 } return nil Если fun1( r ) и fun1( @r ) дают одинаковый результат, то fun2( r ) и fun2( @r ) - разный. Несмотря на то, что Pasha пишет: В харборе массивы и так передаются по ссылке. fun2(r) - передача оригинального массива в виде его адреса. fun2(@r) - передача указателя на адрес оригинального массива. Команда arr := {7, 8, 9} внутри функции меняет указатель (адрес) массива на новый. Если был переда адрес - вызывающий код не узнает об этом изменении. Если передать указатель на адрес - узнает.

Dima: Имеем ячейку с общим форматом EXCEL Нужно сложить туда дату в формате DD.MM.YY , собственно так и ложу , но Ёксель преобразует значение к формату DD.MM.YYYY. Как не меняя формат ячейки сложить в нее значение в формате DD.MM.YY ?

Pasha: Наверное, только изменив региональные установки windows. Я искал ответ на этот вопрос: как отключить автоматическое преобразование типов в экселе. Нашел ссылку на страницу ms, где было написано английским по белому: никак. Сейчас я конечно эту ссылку не найду. То есть, надо только прямо указывать формат ячейки. Эксель умный, знает что надо делать лучше, чем мы.

Dima: Pasha пишет: Эксель умный, знает что надо делать лучше, чем мы. Понятно Просто я заполняю чужой бланк из Harbour и затем отсылаю его по почте из той же проги. В нем я должен только заполнять данные , не меняя форматы ячеек. Вероятно у получателя тоже есть автоматическая обработка бланка. На свой страх и риск заменил Общий формат на Текстовый , надеюсь его прога не слетит

Sergy: Dima пишет: Имеем ячейку с общим форматом EXCEL Нужно сложить туда дату в формате DD.MM.YY , собственно так и ложу , но Ёксель преобразует значение к формату DD.MM.YYYY. Как не меняя формат ячейки сложить в нее значение в формате DD.MM.YY ? Dima пишет: Просто я заполняю чужой бланк из Harbour и затем отсылаю его по почте из той же проги. В нем я должен только заполнять данные , не меняя форматы ячеек. Вероятно у получателя тоже есть автоматическая обработка бланка. На свой страх и риск заменил Общий формат на Текстовый , надеюсь его прога не слети В данном случае, на первый взгляд, ничего менять не нужно. Дата - она в любом случае датой останется. Что в "общем" формате, что в "дате": Чтобы получить такое отображение, нужно задать формат ячейки "ДД.ММ.ГГ" вместо "ДД.ММ.ГГГГ" Неужели принимающая сторона сообщает об ошибках ?

Dima: Sergy пишет: Неужели принимающая сторона сообщает об ошибках ? Пока нет , так как тестю :) Что касаемо картинки ....проделывал уже такой эксперимент , результат выше описал. PS Оффис 2003



полная версия страницы