简体   繁体   English

使用Word模板VBA从Excel进行邮件合并

[英]Mailmerge from Excel using Word template VBA

I have created a Userform where you can flag records as "In Progress", "Completed", and "Not Completed". 我创建了一个用户窗体,您可以在其中将记录标记为“进行中”,“已完成”和“未完成”。

This will reflect on the sheet as below: 这将反映在工作表上,如下所示:

Records marked as "In Progress" will have the letter "P" in the status column. 标记为“进行中”的记录在状态栏中将带有字母“ P”。 Records marked as "Completed" will have the letter "Y" in the status column. 标记为“已完成”的记录在状态栏中将带有字母“ Y”。 Records marked as "Not Completed" will have the letter "N" in the status column. 标记为“未完成”的记录在状态栏中将带有字母“ N”。

DataSheet http://im39.gulfup.com/VZVxr.png ! DataSheet http://im39.gulfup.com/VZVxr.png

I want to run a mailmerge using the below buttons on the user form: 我想使用用户表单上的以下按钮运行邮件合并:

Userform http://im39.gulfup.com/98isU.png ! 用户表单http://im39.gulfup.com/98isU.png

I have created this work template for the fields. 我已经为字段创建了此工作模板。

Document http://im39.gulfup.com/4WMLh.png ! 文档http://im39.gulfup.com/4WMLh.png

This word template file called "MyTemplate" will be in the same directory as the excel file. 名为“ MyTemplate”的单词模板文件将与excel文件位于同一目录中。

I am trying to figure out how: (1) Select recepients by filtering the "Status" column, so if the user pressed the first button, it will run the mail merge only for records with "P" in the status column. 我试图弄清楚如何:(1)通过过滤“状态”列选择接收者,因此,如果用户按下第一个按钮,它将仅对状态列中带有“ P”的记录运行邮件合并。

(2) Run mailmerge without displaying Microsoft Word and only displaying the "Save As" dialog where the user can select where to save the file. (2)运行mailmerge,而不显示Microsoft Word,仅显示“另存为”对话框,用户可以在其中选择保存文件的位置。

(3) This file should be saved in PDF format. (3)此文件应以PDF格式保存。

I am running Office 2013 and so far I have the code in bits and pieces and had no luck when trying to run it. 我正在运行Office 2013,到目前为止,我的代码有些零碎,尝试运行它时没有运气。 I have uploaded the data I am trying to work on: MyBook: https://db.tt/0rLUZGC0 MyTemplate: https://db.tt/qPuoZ0D6 我已经上传了我要处理的数据:MyBook: https ://db.tt/0rLUZGC0 MyTemplate: https ://db.tt/qPuoZ0D6

Any help will be highly appreciated. 任何帮助将不胜感激。 Thanks. 谢谢。

(1) What I use is the WHERE clause (on the OpenDataSource, you probably don't need all those options) (1)我使用的是WHERE子句(在OpenDataSource上,您可能不需要所有这些选项)

' setup the SQL
Dim sSQLModel As String, sSQLWhere As String
sSQLModel = " Where  ( AssignLtrType = 'T1' or AssignLtrType = 'T2'  ) ;"

' replace the appropriate value(s)
sSQLWhere = sSQLModel                   ' never replace in the model
sSQLWhere = Replace(sSQLWhere, "T1", mydatavariable)

' open the MERGE
doc.MailMerge.OpenDataSource Name:=sIn, _
    ConfirmConversions:=False, readOnly:=False, LinkToSource:=True, _
    AddToRecentFiles:=False, PasswordDocument:="", PasswordTemplate:="", _
    WritePasswordDocument:="", WritePasswordTemplate:="", Revert:=False, _
    Format:=wdOpenFormatAuto, Connection:= _
    "Provider=Microsoft.Jet.OLEDB.4.0;Password="""";" & _
    "User ID=Admin;" & _
    "Data Source=" & sXLSPathFile & ";" & _
    "Mode=Read;Extended Properties=" & _
    "HDR=YES;IMEX=1;"";Jet OLEDB:System database="""";" _
    , SQLStatement:="SELECT * FROM `Detail$`", _
    SQLStatement1:=sSQLWhere, _
    SubType:=wdMergeSubTypeAccess

' do the MERGE
With doc.MailMerge
    .Destination = wdSendToPrinter
    .SuppressBlankLines = True
    With .DataSource
        .FirstRecord = wdDefaultFirstRecord
        .LastRecord = wdDefaultLastRecord
    End With
    .Execute Pause:=False
End With

(2) Prior to the above, make the doc Visible (or Invisible) (2)在执行上述操作之前,请使文档可见(或不可见)

' setup the template document
Dim doc As Word.Document
Set doc = wrdApp.Documents.Add(sPathFileTemplate)
wrdApp.Visible = True   ' you can say False

(3) I have Adobe PDF as a Printer (the registry routines were from the web--Google them). (3)我有Adobe PDF作为打印机(注册表例程来自网络-Google)。 Put this prior to OpenDataSource. 将其放在OpenDataSource之前。

' Get current default printer.
SetDefaultPrinter "Adobe PDF"
'Create the Registry Key where Acrobat looks for a file name
CreateNewRegistryKey HKEY_CURRENT_USER, _
    "Software\Adobe\Acrobat Distiller\PrinterJobControl"

'Put the output filename where Acrobat could find it
SetRegistryValue HKEY_CURRENT_USER, _
    "Software\Adobe\Acrobat Distiller\PrinterJobControl", _
    wrdApp.Application.Path & "\WINWORD.EXE", sPathFilePDF

In the SQL, change the tab name from Detail$ to yourTab$ (needs trailing $) 在SQL中,将选项卡名称从Detail $更改为yourTab $(需要在后跟$)

added later-- 以后添加-

Dim sIn As String
sIn = SelectAFile(sInitial:=sDriveSAO, sTitle:=" XLS file")
If (sIn = "" Or sIn = "False") Then Exit Sub

and Google for SelectAFile 和Google for SelectAFile

added 1/22 aft 添加1/22尾

'   ============= added ===========
Dim xls As Excel.Application   ' for me, because I am running in MSAccess as mdb
Set xls = New Excel.Application
Dim wrdApp As Word.Application  ' for you, to have WORD running
Set wrdApp = New Word.Application
Dim sPathFileTemplate As String
sPathFileTemplate = xls.GetOpenFilename(" docx file,*.docx", , "Template file")
'   ============= added ===========

' changed    you only need one variable
sSQLModel = " Where  ( Status = 'T1'  ) ;"

' changed    replace, possibly with some screen value
sSQLWhere = Replace(sSQLWhere, "T1", "P")

' changed because your tab is named Sheet1
    , SQLStatement:="SELECT * FROM `Sheet1$`", _


'   ============= added ===========
doc.Close False
Set doc = Nothing
wrdApp.Quit False
Set wrdApp = Nothing
'   ============= added ===========

OK so with a lot of help from @donPablo I finally got a working code which does exactly what I want. 好的,因此在@donPablo的大量帮助下,我终于得到了一个可以正常运行的代码。

BTW the "Status" in sSQLModel = " Where ( Status = 'T1' ) ;" 顺便说一句, sSQLModel = " Where ( Status = 'T1' ) ;"的“状态” sSQLModel = " Where ( Status = 'T1' ) ;" can be change to any other column heading, but in my case I am filtering based on a value in the column F (Status). 可以更改为任何其他列标题,但就我而言,我是根据列F(状态)中的值进行过滤。 The "P" in sSQLWhere = Replace(sSQLWhere, "T1", "P") can also be change to the value been filtered on, but in my case I want all the records containing "P" in the "Status" column. sSQLWhere = Replace(sSQLWhere, "T1", "P")也可以更改为已过滤的值,但是在我的情况下,我希望“状态”列中所有包含“ P”的记录。

The "Sheet1" in , SQLStatement:="SELECT * FROM Sheet1$ ", _ can be changed to the name of the sheet containing the source data for the merge. 可以将, SQLStatement:="SELECT * FROM Sheet1 $ ", _ Sheet1 ", _更改为包含合并源数据的工作表的名称。 (Don't forget to include the $ sign at the end of the sheet name. (不要忘记在工作表名称的末尾添加$符号。

Before proceeding make sure to load the Microsoft Word Object Library ( VBA - Tools - References ) 在继续之前,请确保加载Microsoft Word对象库( VBA-工具-参考

And here is the working code: 这是工作代码:

Private Sub CommandButton1_Click()

Dim xls As Excel.Application
Set xls = New Excel.Application
Dim wrdApp As Word.Application
Set wrdApp = New Word.Application
Dim sPathFileTemplate As String
sPathFileTemplate = ThisWorkbook.Path & "\MyTemplate.docx" 'This gets the file called MyTemplate from the same directory
                                                           'in which this excel file is running from

' setup the template document
Dim doc As Word.Document
Set doc = wrdApp.Documents.Add(sPathFileTemplate)
wrdApp.Visible = False   ' Make MS Word Invisible

Dim sIn As String
sIn = ThisWorkbook.FullName 'This Workbook is set the merge data source

' setup the SQL
Dim sSQLModel As String, sSQLWhere As String
sSQLModel = " Where  ( Status = 'T1'  ) ;"

' replace the appropriate value(s)
sSQLWhere = sSQLModel
sSQLWhere = Replace(sSQLWhere, "T1", "P")

' open the MERGE
doc.MailMerge.OpenDataSource Name:=sIn, _
    ConfirmConversions:=False, ReadOnly:=False, LinkToSource:=True, _
    AddToRecentFiles:=False, PasswordDocument:="", PasswordTemplate:="", _
    WritePasswordDocument:="", WritePasswordTemplate:="", Revert:=False, _
    Format:=wdOpenFormatAuto, Connection:= _
    "Provider=Microsoft.Jet.OLEDB.4.0;Password="""";" & _
    "User ID=Admin;" & _
    "Data Source=" & sXLSPathFile & ";" & _
    "Mode=Read;Extended Properties=" & _
    "HDR=YES;IMEX=1;"";Jet OLEDB:System database="""";" _
    , SQLStatement:="SELECT * FROM `Sheet1$`", _
    SQLStatement1:=sSQLWhere, _
    SubType:=wdMergeSubTypeAccess

' do the MERGE
With doc.MailMerge
    .Destination = wdSendToNewDocument
    .SuppressBlankLines = True
    With .DataSource
        .FirstRecord = wdDefaultFirstRecord
        .LastRecord = wdDefaultLastRecord
    End With
    .Execute Pause:=False
End With


'If you want you can delete this part and proceed to diretly define the
'filename and path below in "OutputFileName"
On Error Resume Next
Dim FileSelected As String
FileSelected = Application.GetSaveAsFilename(InitialFileName:="Export", _
                                         FileFilter:="PDF Files (*.pdf), *.pdf", _
                                         Title:="Save PDF as")
If Not FileSelected <> "False" Then
MsgBox "You have cancelled"
doc.Close False
Set doc = Nothing
wrdApp.Quit False
Set wrdApp = Nothing
Exit Sub
End If

If FileSelected <> "False" Then
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

wrdApp.Application.Options.SaveInterval = False

'Saves Documents as PDF and does not open after saving, you can change OpenAfterExport:=False to True
wrdApp.Application.ActiveDocument.ExportAsFixedFormat OutputFileName:=FileSelected, _
ExportFormat:=wdExportFormatPDF, OpenAfterExport:=False, OptimizeFor:=wdExportOptimizeForPrint, _
Range:=wdExportAllDocument, FROM:=1, To:=1, Item:=wdExportDocumentContent, IncludeDocProps:=True, _
KeepIRM:=True, CreateBookmarks:=wdExportCreateNoBookmarks, DocStructureTags:=True, _
BitmapMissingFonts:=True, UseISO19005_1:=False

doc.Close False
Set doc = Nothing
wrdApp.Quit False
Set wrdApp = Nothing

MsgBox "Done"

End If  ' this EndIf pretains to the SaveAs code above

End Sub

I cannot stress enough how much help was @donPablo, thanks again, you just made my weekend and I am selecting your answer as accepted :) 我不能强调@donPablo有多少帮助,再次感谢,您刚刚度过了我的周末,我选择的答案是可以接受的:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM