среда, 11 ноября 2009 г.

Открытие приложенного документа Word и перенос некоторых полей в документ

Данный скрипт был создан еще для 3.6. Думаю он будет полезен и сейчас.

Пример взаимодействия с внешним приложением MS Word. Рассматриваемый скрипт карточки открывает приложенный файл *.doc, и производит вставку значений полей секции «Основная информация» в текст документа.
Вставка производится следующим образом: В тексте документа размещены названия полей в виде @Name или @Digest – т.н. теги. Скрипт производит замену этих тегов на значения из полей с таким же названием.



Function DoEvent(UserSession, CardFrame, CardData, ActivateFlags, ModeID, FolderID)
    'Открываем файл, присоединенный к карточке
    
    'Создается объект FileList
    Dim sFilesID
    sFilesID = CardDa-ta.Sections.Item(CardData.Type.Sections.GetByAlias("MainInfo").ID).FirstRow.Value("FilesID") & ""
    If sFilesID = vbNullString Then Exit Function
    Dim oFileList
    Set oFileList = CreateObject("TOFileList.FileList")
    Set oFileList.UserSession = UserSession
    
    Dim rows
    Set rows = CardDa-ta.Sections.Item(CardData.Type.Sections.GetByAlias("Properties").ID).rows
    Set oFileList.PropertyRows = rows
    
    oFileList.ID = sFilesID
    
    'Количество файлов
    Dim n: n = oFileList.FileRefs.Count
    
    'Если нет файлов, то выход
    If n = 0 Then
        Exit Function
    End If

    'Открытие файла
    Dim oFile
    Set oFile = oFileList.FileRefs.Item(1)
    oFile.OpenFile

    'Получаем объект WORD
    Dim objWord
    Set objWord = GetObject(, "Word.Application")
    
    'Меняем
    Dim arrFields, strField, oFlag
    arrFields = Array("Name", "Digest") 'Здесь перечислены все теги и поля
    Dim rngStory
    Dim oMainRow
    Set oMainRow = CardData.Sections.Item(CardData.Type.Sections.GetByAlias("MainInfo").ID).FirstRow
        
    Do
        oFlag = False
        For Each strField In arrFields
            objWord.Selection.Start = 0
            objWord.Selection.End = 0
            objWord.Selection.Find.Forward = True
            If objWord.Selection.Find.Execute("@" & strField) = True Then
                If IsNull(oMainRow.Value(strField)) Then
                    objWord.Selection.TypeText (" ")
                Else
                    objWord.Selection.TypeText (oMainRow.Value(strField))
                End If
              oFlag = True
            End If
        Next
    Loop Until oFlag = False

  
    Set oFileList = Nothing
End Function


9 комментариев:

  1. А чем этот метод полезнее чем тот что описан в
    "Курс DV903 Практические работы Часть 1.pdf"
    в разделе:
    "Практическая работа №6. Настройка шаблонов
    карточек документов. Синхронизация
    пользовательских свойств карточек и файла."?

    Там так же создается *.doc со свойствами, вкладывается в карточку а при открытии значения свойств передаются автоматически.
    ЗАчем писать дополнительно скрипт для этого?

    ОтветитьУдалить
  2. Действительно, можно синхронизировать свойства карточки со свойствами файла. Это кусок кода, как пример, который показывает, как можно работать с MS Word из скрипта. Так же свойства документа MS Word имеют ограничение на размер 255 символов, и перенести длинный текст содержания, через синхронизацию свойств нельзя.

    ОтветитьУдалить
  3. Оказалось, что свойство MS Word принимает значения свойств любого размера, но отображает только 255. При этом если вывести свойство в документ (через Fields) то будет выведено значение полностью.

    Так, что код, только как пример работы с Word :)

    ОтветитьУдалить
  4. Если использовать такой скрипт, то свободно можно отказаться и от использования "офисных" свойств, перейти на использование закладок и вставлять напрямую из полей карточки в место документа, где расположена закладка. Так что код надо совсем немного модифицировать.
    Вот пример такой реализации на C#:

    Object missing = System.Reflection.Missing.Value;
    Object oTrue = true;
    Object oFalse = false;

    // Для совместимости с языковыми настройками
    System.Globalization.CultureInfo oldCI = System.Threading.Thread.CurrentThread.CurrentCulture;
    System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
    System.Threading.Thread.CurrentThread.CurrentCulture = oldCI;

    //Creating objects of word and document
    Microsoft.Office.Interop.Word.Application oWord = new Microsoft.Office.Interop.Word.Application();
    object fileName = sFilePath;
    object readOnly = false;
    object isVisible = true;
    Microsoft.Office.Interop.Word.Document oWordDoc = oWord.Documents.Open(ref fileName, ref missing, ref
    readOnly, ref missing, ref missing, ref missing, ref
    missing, ref missing, ref missing, ref missing, ref
    missing, ref isVisible, ref missing, ref missing, ref
    missing, ref missing);

    object bm;
    Range rng_bm;
    // Прописываем номер договора
    try {
    bm = "Dog_number";
    rng_bm = oWordDoc.Bookmarks.get_Item(ref bm).Range;
    rng_bm.Text = Dog_FullNumber;
    }
    catch(Exception ex)
    {
    // запись в журнал ошибки исполнения
    process.LogMessage("При прописывании номера договора. Ошибка выполнения скрипта:" + ex.Message);
    }

    ОтветитьУдалить
  5. А как стандартная автоматическая синхронизация реализована в ДВ?

    Почему она работает только при открытии из списка приложенных файлов, а например при открытии той же карточки файла помещенной в пользовательское свойство на вкладке "Свойства" - синхронизация свойств не происходит?

    Был бы удобный способ вкладывания синхронизируемого офисного документа во все карточки вида через значение по умолчанию св-ва вида, без применения шаблонов (неудобно это) или написания скриптов.

    ОтветитьУдалить
  6. Как модернизировать скрипт для случая когда карточка файла в пользовательском свойстве?

    Dim props: Set props = CardData.Sections("{B822D7D1-2280-4B51-AE58-A1CF757C5672}")
    Dim row: Set row = props.FindRow("@Name=""файл""")
    Dim propId: Set propId = row.Value("Value") //это InstanceID карточки файла

    Dim oFile
    Set oFile = ???
    oFile.OpenFile

    Есть ее InstanceID, но как получить из него объект oFile в строке 28, который затем открывается и с которым идет работа?
    Не присваиванием элемента oFileList, а имея только InstanceID карточки файла.

    ОтветитьУдалить
  7. Сергей, в этом случае нужно по карточке файла получить объект типа IFile у которого должен быть метод CheckOut

    Структура ссылок такова
    Карточка файла - карточка файла с версиями - Файл.

    Структуру ссылок посмотрите через CardManager. Список методов IFile лучше просмотреть через ObjectBrowser в Visual Studio, подключив библиотеку ObjectManager.dll

    ОтветитьУдалить
  8. У меня ругается вот тут.

    object fileName = sFilePath;

    не догоняю.

    ОтветитьУдалить
  9. Возможно ли через подобный скрипт выполнить подстановку таблицы в указанное место?

    ОтветитьУдалить