Страницы: 1
RSS
VBA. Как сохранить книгу без макросов в формате .xls
 
Добрый день.
В Excel сделал небольшую форму для приема заказов на мебельном производстве.
И потом заявку нужно сохранить в отдельном .xls файле , для импорта в другую программу.
Код макроса содержится на листе + отдельный модуль...
На листе обработчик на событие Workbook_Open

Что делаю:
1.Копирую текущий лист в новую книгу, удаляю все лишнее на листе (управляющие кнопки (shape), лишние строки .итд)
2. Удаляю макросы (внизу код)
3. сохраняю как файл .xls (xlExcel8)
Код
Sheets("Новый Заказ").Copy
Call Delete_Macroses
ActiveWorkbook.SaveAs FileName:=ПутьСохранения & "\" & Fname, FileFormat:=xlExcel8, Password:="", WriteResPassword:="", ReadOnlyRecommended:=False, CreateBackup:=False

Этой процедурой удаляю макросы (пытаюсь)
Код
Sub Delete_Macroses()
    Dim oVBComponent As Object, lCountLines As Long
    'Проверяем, защищен проект или нет
 
    For Each oVBComponent In ActiveWorkbook.VBProject.VBComponents
        On Error Resume Next
        With oVBComponent
            Select Case .Type
            Case 1    'Модули
                .Collection.Remove oVBComponent
            Case 2    'Модули Класса
                .Collection.Remove oVBComponent
            Case 3    'Формы
                .Collection.Remove oVBComponent
            Case 100    'ЭтаКнига, Листы
                    lCountLines = .CodeModule.CountOfLines
                    .CodeModule.DeleteLines 1, lCountLines
            End Select
        End With
    Next
    Set oVBComponent = Nothing
End Sub
В результате
Файл занимает 52 КБ, а не 9, как если бы я сохранил его вручную в формат .xls
И при открытии всплывает сообщение "включить содержимое".

Что не так? Что не удаляется?


Вопрос.
А можно ли сохранить заявку из этого файла без макросов, не прибегая к обращению к объектной модели?
Т.к. этот файлик рассылается клиентам, и нужно обязательно делать соотв. настройки у них..
А клиенты разные и нервные.. Можно ли как-то этого избежать?
 
Можно. Побаловался макрорекордером и у меня получилось  :)  
 
Спасибо за ответ
Только я ничего не понял, почему у меня не работает. Вроде код такой же :)

А зачем это?
Код
Kill Addr & "Файл без макросов 2007.xlsx
 
PATRI0T, Код ниже удаляет весь код во всех модулях активной книги.
Код
Sub test()
Set VBComp = ActiveWorkbook.VBProject.VBComponents
 For Each cl In VBComp
   cl.CodeModule.DeleteLines 1, cl.CodeModule.CountOfLines
 Next
End Sub
 
Цитата
PATRI0T написал: не понял, почему у меня не работает.
Покажите Ваш файл с кодом, который не работает. Смею предположить, что Вы что-то не так или не туда вставили или что-то не так сделали, а так же невнимательно посмотрели код, иначе не возникло бы вопроса:[QUOTE]PATRI0T написал: А зачем это?  Kill Addr & "Файл без макросов 2007.xlsx[/CODE]
В модуле к этой и еще к нескольким строкам есть комментарии.
Так же обратите внимание на названия файлов в коде. Мои названия поменяйте на Ваши
 
Александр, здравствуйте! Но тогда пользователю нужно лезть в параметры, ставить доверенный доступ и перезапускать приложение, что для пользователя, думаю не очень удобно. Поэтому по-моему проще это все сделать просто пересохранением файлов, а потом лишний файл удалить. ИМХО, конечно  :)  
 
_Igor_61, ну так, наше дело предложить вариант  :) .
У ТСа так же, может быть только 2003 версия офиса, без конвертера. Тогда в .xlsx он не сможет сохранять. А так, была уже похожая тема на форуме.
Изменено: Александр П. - 06.10.2017 10:19:58
 
Уважаемый PATRI0T, в приложенном к сообщению файле макросов нет, зато есть два "битых" имени книги. Удалите их через "Диспетчер имен" и проблема с открытием должна уйти.
Владимир
 
Цитата
Александр П. написал:
У ТСа так же, может быть только 2003 версия офиса
Да, если это так, то не удивительно, что у него мой макрос не работает, если он его в xls помещает.  Но почему-то он про этот момент молчит. А я решил, что у него изначальный файл в xlsm, глядя на картинку  :)  
 

Вы копируете лист со всеми потрохами. Копируйте только то, что Вам нужно. Сделайте новый лист и на него скопируйте диапазон ячеек.

Изменено: LAD - 07.10.2017 04:58:21
 
Цитата
_Igor_61 написал:
   MsgBox "Блин, кажись, получилось...", 64, "ВАУ!"
_Igor_61, Вставьте это в модуль копируемого листа, и вау съедят мыши.

Код
Sub Мяу()
    Dim sfName1$, sfName2$
    Dim sh As Worksheet, nm As Name
    sfName1 = ThisWorkbook.FullName
    sfName1 = Replace(sfName1, "xlsm", "xlsx")
    sfName2 = Left(sfName1, Len(sfName1) - 1)
    Application.ScreenUpdating = False
    Application.CopyObjectsWithCells = False
    Sheets(Array(1, 3)).Copy
    For Each sh In ActiveWorkbook.Worksheets
        sh.UsedRange.Value = sh.UsedRange.Value
    Next
    For Each nm In ActiveWorkbook.Names
        nm.Delete
    Next
    Application.DisplayAlerts = False
    ActiveWorkbook.SaveAs sfName1, 51
    ActiveWorkbook.Close False
    Workbooks.Open sfName1
    ActiveWorkbook.SaveAs sfName2, 56
    ActiveWorkbook.Close False
    Kill sfName1
    Application.DisplayAlerts = True
    Application.CopyObjectsWithCells = True

End Sub
Изменено: RAN - 07.10.2017 10:51:58
 
RAN, не, не съедят, еще больше "ВАУ"!   :)
Надеюсь, я тоже когда-то такие задачки буду сходу решать, но пока - изучаю VBA в основном на уровне макрорекордера, т.к. не хватает времени учебники читать. И в Вашем коде многое для меня - темный лес. Например, я не знаю, какую роль выполняет $ в названиях переменных sfName, также не понимаю, как и почему одной и той же переменной (стр.4 и 5) можно присвоить разные значения (или это функции - не знаю), ну и т.д. - короче, мне в этом коде понятны только строки после "Next", и то не все, например, не знаю что значат "51" и "56", ну и т.д. не буду все перечислять, т.к. для каждого моего вопроса придется делать отдельную тему  :)
Ради интереса попробовал поместить Ваш код в файл xls, ошибка 400, новая книга с копируемым листом создается, но код в модуле листа остается.
А ТС пока так и молчит - из какой версии ему в xls нужно сохранять  :)  
 
$ в имени переменной - это тип (аналог as String). Вот табличка соответствий:
Integer - %
Long - &
Single - !
Doble - #
Currency - @
String - $
По поводу строк 4 и 5: сначала получили путь, а потом в этой строке произвели замену: xlsm заменили на xlsx. В принципе можно было и в одной строке сделать.
51 и 56 - это константы типов файлов.
===
// константы форматов 2003

//  xlCSVWindows = 23;
//  xlDBF2 = 7;
//  xlDBF3 = 8;
//  xlDBF4 = 11;
//  xlDIF = 9;
//  xlExcel9795 = 43;
//  xlTextWindows = 20;
//  xlUnicodeText = 42;
//  xlWebArchive = 45;
//  xlXMLSpreadsheet = 46;
//  xlXMLData = 47;

// основные константы 2007
//  These are the main file formats in Excel 2007-2010:
//  51 = xlOpenXMLWorkbook (without macro's in 2007-2010, xlsx)
//  52 = xlOpenXMLWorkbookMacroEnabled (with or without macro's in 2007-2010, xlsm)
//  50 = xlExcel12 (Excel Binary Workbook in 2007-2010 with or without macro's, xlsb)
//  56 = xlExcel8 (97-2003 format in Excel 2007-2010, xls)

//  57 = PDF
//  60 = xlOpenDocumentSpreadsheet  OpenDocument Spreadsheet

 
Блин, как же я люблю этот форум! Каждый раз какое-то "ВАУ" для себя нахожу! Юрий М, спасибо большое! Сохранил Ваши пояснения, они очень пригодятся в дальнейшем. Не знал, что части кода можно цифрами задавать (хотя, нет, пример уже знаю -  в MsgBox 64, 32, 48), это, видимо, что-то подобное, если правильно понимаю. Т.е. вместо "xlOpenXMLWorkbook (without macro's in 2007-2010, xlsx) " пишем "51" и выполняется это действие, так? И я так понимаю, что RAN своим кодом вносит изменения в XML? Дальше - вообще не понимаю - ведь если открыть файл через WinRAR, там же куча папок и файлов XML, т.е. в данном случае через "51" производятся манипуляции с конкретным XML файлом, "51" его находит и выполняет свою задачу?
 
XML тут нет ) Просто заменяем длинную строку числом )
 
xlOpenXMLWorkbook - тогда это просто указание на книгу xlsx 2007-2010, этим кодом ее открываем?
 
Нет, открываем по имени, а это указание ТИПА файла - книга без макросов.
 
А, кажется понял:  ActiveWorkbook.SaveAs sfName1, 51 - сохраняем активную книгу с заданным именем (sfName1) в xlsx (xlOpenXMLWorkbook (without macro's in 2007-2010, xlsx) . И равнозначно - можно записать текстом "xlOpenXMLWorkbook (without macro's in 2007-2010, xlsx", а можно "51".  Я правильно понимаю?
Простите за навязчивость, просто хочу правильно все уяснить для себя, чтобы все правильно понимать и в дальнейшем правильно использовать, если понадобится
 
RAN,
Скопировал ваш макрос в личную книгу макросов.
Создал пустой файл Книга1.xlsm с 6 листами.
Открыл его и запустил ваш макрос.
Ошибка. Выделена строка.
ActiveWorkbook.SaveAs sfName1, 51
И табличка.

Что нужно изменить что бы макрос заработал из личной книги макросов. Из листа текущей книги отрабатывает корректно.
Изменено: Николай - 07.10.2017 19:42:37
 
Игорь, всё верно.
 
Юрий М, спасибо!
 
sfName1 = ThisWorkbookActiveWorkbook.FullName
............................................
  ActiveWorkbook. Sheets(Array(1, 3)).Copy
  .................................
Изменено: RAN - 07.10.2017 20:30:39
 
_Igor_61,
F1, Search results for enumeration
 
Кнопка цитирования не для ответа [МОДЕРАТОР]

sfName1 = ActiveWorkbook.FullName
Оказалось достаточно, работает.Но изменил и
ActiveWorkbook. Sheets(Array(1, 3)).Copy
Работает.
Адаптирую под свои нужны отпишу.
 
На тестовой книге.
Ошибка в строке
ActiveWorkbook.SaveAs sfName1, 51
При этом сохранение новой книги происходит.
Вот код.
Код
Sub кол_вх()
Dim s As String, fldr As String
fldr = "D:\111\"
s = Dir(fldr & "*.xls")
Do While s <> ""
    With Workbooks.Open(fldr & s)
    Dim sfName1$, sfName2$
    Dim sh As Worksheet, nm As Name
    sfName1 = ActiveWorkbook.FullName
    sfName1 = Replace(sfName1, "xlsm", "xlsx")
    sfName2 = Left(sfName1, Len(sfName1) - 1)
    Application.ScreenUpdating = False
    Application.CopyObjectsWithCells = False
    ActiveWorkbook.Sheets(Array(1, 2, 3, 4)).Copy
    For Each sh In ActiveWorkbook.Worksheets
        sh.UsedRange.Value = sh.UsedRange.Value
    Next
    For Each nm In ActiveWorkbook.Names
        nm.Delete
    Next
    Application.DisplayAlerts = False
    ActiveWorkbook.SaveAs sfName1, 51
    ActiveWorkbook.Close False
    Workbooks.Open sfName1
    ActiveWorkbook.SaveAs sfName2, 56
    ActiveWorkbook.Close False
    Kill sfName1
    Application.DisplayAlerts = True
    Application.CopyObjectsWithCells = True
        .Close 0
    End With
    s = Dir
Loop
End Sub

И скрин ошибки.
Файла  Книга1.xls в каталоге НЕТ.
 
Опа.
Удаление строк
Код
Workbooks.Open sfName1
    ActiveWorkbook.SaveAs sfName2, 56
    ActiveWorkbook.Close False
    Kill sfName1

Решило проблему.
 
Вот как стал выглядеть код в итоге.
Код
Sub Микро_на_сдачу()
    Dim sFolder As String, sFiles As String
    'диалог запроса выбора папки с файлами
    With Application.FileDialog(msoFileDialogFolderPicker)
        If .Show = False Then Exit Sub
        sFolder = .SelectedItems(1)
    End With
    With UserForm1
        .Show 0
        .Label1.Caption = "Работаем..."
        .Repaint
        For i = 1 To 100000000
        Next
    sFolder = sFolder & IIf(Right(sFolder, 1) = Application.PathSeparator, "", Application.PathSeparator)
    'отключаем обновление экрана, чтобы наши действия не мелькали
    Application.ScreenUpdating = False
    sFiles = Dir(sFolder & "*№*.xlsm")
    Do While sFiles <> ""
        'открываем книгу
        Workbooks.Open sFolder & sFiles
        'действия с файлом         
        Sheets("Приложение № 7 ").Select
        ActiveSheet.Unprotect 'снимаем блокировку с листа
        Cells.Select 'выделяем весь лист
        Selection.Copy 'Копируем
        Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
            :=False, Transpose:=False ' вставляем в лист значения за место формул
        Range("A1").Select
        Sheets("Приложение № 3 ").Select
        ActiveSheet.Unprotect
        Cells.Select
        Selection.Copy
        Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
            :=False, Transpose:=False
        Range("A1").Select
        Sheets("Титульный").Select
        Range("A1").Select
        Sheets("Микроучасток").Select
        Range("Таблица1[[#Headers],[№ п.п]]").Select
        ActiveWindow.Zoom = 100
        'Преорбазуем таблицы в диапазоны
        Dim sh1 As Worksheet
        Dim iObj As ListObject
        For Each sh1 In Worksheets
        For Each iObj In sh1.ListObjects
            iObj.Unlist
        Next
        Next
        'Макрос сохранения книги со старым именем и новым расширением xlsx
        Dim sfName1$
        Dim sh As Worksheet, nm As Name
        sfName1 = ActiveWorkbook.FullName
        sfName1 = Replace(sfName1, "xlsm", "xlsx")
        Application.ScreenUpdating = False
        Application.CopyObjectsWithCells = False
        ActiveWorkbook.Sheets(Array(1, 2, 3, 5)).Copy
        'Преобразование формул в значения, не всегда работает корректно, оставил просто так.
        For Each sh In ActiveWorkbook.Worksheets
            sh.UsedRange.Value = sh.UsedRange.Value
        Next
        'Удаление именнованных диапазонов показать по ctrl+F3
         For Each n In ActiveWorkbook.Names:
        On Error Resume Next
        n.Delete:
        Next
        
        Application.DisplayAlerts = False
        ActiveWorkbook.SaveAs sfName1, 51
        ActiveWorkbook.Close False
        Application.DisplayAlerts = True
        Application.CopyObjectsWithCells = True
    
        'Закрываем книгу с сохранением изменений
        ActiveWorkbook.Close False 'если поставить False - книга будет закрыта без сохранения
        sFiles = Dir
    Loop
    'возвращаем ранее отключенное обновление экрана
    Application.ScreenUpdating = True
    .Label1.Caption = "ГОТОВО"
    End With
End Sub


Огромная благодарность RAN, за его код сохранения файлов.
Изменено: Николай - 08.10.2017 12:38:36
 
Не думал, что можно так сильно извратить.
Страницы: 1
Наверх