none
VB 2010 Express - Word 2010 - Insert Docvariables into active document when command button is clicked RRS feed

  • Question

  • The title of this question says it all, really...

    I've done this in an older version of visual basic, the code of which is below:

    Private Sub CmdOK_Click()
     Set oVars = ActiveDocument.Variables
     oVars("LastName").Value = Me.ListBox2.Column(0)
     oVars("FirstName").Value = Me.ListBox2.Column(1)
     oVars("Address").Value = Me.ListBox2.Column(2)

    etc. (there are a total of about 30 columns/variables)

     ActiveDocument.Fields.Update

    End Sub

    Using Visual Basic 2010 Express, I have an MS Access Database as my datasource, which is connected to my form with a DataGridView along with the corresponding details.  What I'm looking for is assistance in duplicating the above result into VB 2010 Express so that when I click a command button, the text contained in the textboxes associated with the DataGridView populate and update the fields within the active document template I have open.

    Any assistance would be much appreciated.

    Thank you!

    Friday, May 11, 2012 2:34 AM

Answers

  • Hi LAssist

    Thank you for the code. I see a number of things that could be tripping you up; let's see if we can get it sorted...

    (1) You declare and create a Word application process and a Word document:

        Private Sub BtnOpenNew_Click(sender As System.Object, e As System.EventArgs) Handles BtnOpenNew.Click

           
    Dim oWord As Word.Application
           
    Dim odoc As Word.Document

            oWord
    = CreateObject("Word.Application")

    While this is done correctly, as it stands, the problem is that the oWord and odoc variables will go out of scope when the Sub ends. At some point, the .NET garbage collection will clean them up and, at that point, as far as your VS app is concerned, it knows nothing about Word or the document.

    So, currently, all you're doing is starting up the application and creating a new document. But after you do so, you have no way of doing anything more with Word.

    If you declare odoc at the class level, then the object will remain available to your project until the project unloads or until you specifically release the object. So more like this:

    Public Class MstrLtrTemplate
        Dim odoc as Word.Document

       
    Private Sub BtnOpenNew_Click(sender As System.Object, e As System.EventArgs) Handles BtnOpenNew.Click

           
    Dim oWord As Word.Application

    Now you can reference odoc from all procedures in your class.

    (2) In BtnProcess_Click you declare the object Dim odoc As Word.Variables and then try to use it. But you haven't defined where your project should find these Word.Variables, nor assigned them to the object you've declared. That's why you're getting the error message and it's telling you exactly this.

    In the code in point (1), you set oWord and odoc = to something. That's what's missing here.

    (3) The problem in (2) cannot be resolved without first taking care of (1) because in your current code, you have no way to access the document you created in (1). After declaring odoc as a class level variable, you can access it in BtnProcess_Click. So something more like this for BtProcess_Click:

    Private Sub BtnProcess_Click(sender As System.Object, e As System.EventArgs) Handles BtnProcess.Click
           
    Dim ovars As Word.Variables = odoc.Variables

     

    (4) The combination of points (1) through (3) should get things working, but you have another problem you don't know about, yet. That's making sure that you clean up properly.

    .NET cleans up after itself when a project finishes - it releases all objects from memory. COM doesn't do this automatically in all cases; the COM developer is aware of this and learns early on about releasing objects. VBA developers who work within a single application don't usually learn about this. So moving from VBA to .NET can be a bit "dangerous" when working with COM...

    What you need to do is to explicitly release all objects you create for Word, especially those declared at the class level, but it's also a good idea to do it within procedures.

    This means that, at the end of BtnOpenNew_Click you should have the line
        oWord = Nothing

    And at the end of BtnProcess_Click you should have the line
      ovars = Nothing

    Where to release odoc is a bit trickier, because it depends on at what point you no longer need to access the document you created. If you want the document to be available until the user closes the Windows Form, then you should put the line in the event FormClosing or FormClosed.


    Cindy Meister, VSTO/Word MVP

    • Marked as answer by MBuchok Sunday, May 13, 2012 11:11 AM
    Sunday, May 13, 2012 7:29 AM
    Moderator

All replies

  • Hi LAssist

    I seem to have seen another version of this question, recently? In the VSTO forum? And did I move it somewhere the other day because it wasn't VSTO-related? (Just trying to do some house-keeping...)

    At what point are you "stuck" with this? You're able to access the document, generally? Are you able to assign values to the document variables (not worrying about the DataGrid view - just assign values)? Is the problem extracting the data from the DataGridView?


    Cindy Meister, VSTO/Word MVP

    Friday, May 11, 2012 1:39 PM
    Moderator
  • Below is my code in its entirety.  I know the bottom portion about the 2nd command button is incorrect (BtnProcess), but if you could instruct me how to correct this I would appreciate it.

    Imports Microsoft.Office.Interop
    Imports Microsoft.Office.Interop.Word
    
    Public Class MstrLtrTemplate
    
        Private Sub BtnOpenNew_Click(sender As System.Object, e As System.EventArgs) Handles BtnOpenNew.Click
    
            Dim oWord As Word.Application
            Dim odoc As Word.Document
    
            oWord = CreateObject("Word.Application")
            oWord.Visible = True
    
            If ComboBoxDocReq.Text = "Doc1" Then
                odoc = oWord.Documents.Add("C:\Doc1.dotx")
            ElseIf ComboBoxDocReq.Text = "Doc2" Then
                odoc = oWord.Documents.Add("C:\Doc2.dotx")
            ElseIf ComboBoxDocReq.Text = "Doc3" Then
                odoc = oWord.Documents.Add("C:\Doc3.dotx")
            ElseIf ComboBoxDocReq.Text = "Doc4" Then
                odoc = oWord.Documents.Add("C:\Doc4.dotx")
            ElseIf ComboBoxDocReq.Text = "Doc5" Then
                odoc = oWord.Documents.Add("C:\Doc5.dotx")
            ElseIf ComboBoxDocReq.Text = "Doc6" Then
                odoc = oWord.Documents.Add("C:\Doc6.dotx")
            ElseIf ComboBoxDocReq.Text = "Doc7" Then
                odoc = oWord.Documents.Add("C:\Doc7.dotx")
            ElseIf ComboBoxDocReq.Text = "Doc8" Then
                odoc = oWord.Documents.Add("C:\Doc8.dotx")
            End If
        End Sub
    
        Private Sub Client_InformationBindingNavigatorSaveItem_Click(sender As System.Object, e As System.EventArgs) Handles Client_InformationBindingNavigatorSaveItem.Click
            Me.Validate()
            Me.Client_InformationBindingSource.EndEdit()
            Me.TableAdapterManager.UpdateAll(Me.Client_InformationDataSet)
    
        End Sub
    
        Private Sub MstrLtrTemplate_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            'TODO: This line of code loads data into the 'Client_InformationDataSet.Client_Information' table. You can move, or remove it, as needed.
            Me.Client_InformationTableAdapter.Fill(Me.Client_InformationDataSet.Client_Information)
    
        End Sub
    
        Private Sub BtnProcess_Click(sender As System.Object, e As System.EventArgs) Handles BtnProcess.Click
            Dim odoc As Word.Variables
    
            odoc("LastName").Value = Client_Last_NameTextBox.Text
            odoc("FirstName").Value = Client_First_NameTextBox.Text
    
        End Sub
    End Class

    Again, I can successfully open whichever document I select from the combobox in the first portion of the code, but I can't get the docvariables as referenced in the BtnProcess_Click event to populate the variables from the textboxes associated with the details of the datagridview into the template I open from the combobox.

    The error I receive comes from the BtnProcess_Click event in which it tells me "Object reference not set to an instance of an object".

    Any suggestions?

    Friday, May 11, 2012 10:45 PM
  • Hi LAssist

    Thank you for the code. I see a number of things that could be tripping you up; let's see if we can get it sorted...

    (1) You declare and create a Word application process and a Word document:

        Private Sub BtnOpenNew_Click(sender As System.Object, e As System.EventArgs) Handles BtnOpenNew.Click

           
    Dim oWord As Word.Application
           
    Dim odoc As Word.Document

            oWord
    = CreateObject("Word.Application")

    While this is done correctly, as it stands, the problem is that the oWord and odoc variables will go out of scope when the Sub ends. At some point, the .NET garbage collection will clean them up and, at that point, as far as your VS app is concerned, it knows nothing about Word or the document.

    So, currently, all you're doing is starting up the application and creating a new document. But after you do so, you have no way of doing anything more with Word.

    If you declare odoc at the class level, then the object will remain available to your project until the project unloads or until you specifically release the object. So more like this:

    Public Class MstrLtrTemplate
        Dim odoc as Word.Document

       
    Private Sub BtnOpenNew_Click(sender As System.Object, e As System.EventArgs) Handles BtnOpenNew.Click

           
    Dim oWord As Word.Application

    Now you can reference odoc from all procedures in your class.

    (2) In BtnProcess_Click you declare the object Dim odoc As Word.Variables and then try to use it. But you haven't defined where your project should find these Word.Variables, nor assigned them to the object you've declared. That's why you're getting the error message and it's telling you exactly this.

    In the code in point (1), you set oWord and odoc = to something. That's what's missing here.

    (3) The problem in (2) cannot be resolved without first taking care of (1) because in your current code, you have no way to access the document you created in (1). After declaring odoc as a class level variable, you can access it in BtnProcess_Click. So something more like this for BtProcess_Click:

    Private Sub BtnProcess_Click(sender As System.Object, e As System.EventArgs) Handles BtnProcess.Click
           
    Dim ovars As Word.Variables = odoc.Variables

     

    (4) The combination of points (1) through (3) should get things working, but you have another problem you don't know about, yet. That's making sure that you clean up properly.

    .NET cleans up after itself when a project finishes - it releases all objects from memory. COM doesn't do this automatically in all cases; the COM developer is aware of this and learns early on about releasing objects. VBA developers who work within a single application don't usually learn about this. So moving from VBA to .NET can be a bit "dangerous" when working with COM...

    What you need to do is to explicitly release all objects you create for Word, especially those declared at the class level, but it's also a good idea to do it within procedures.

    This means that, at the end of BtnOpenNew_Click you should have the line
        oWord = Nothing

    And at the end of BtnProcess_Click you should have the line
      ovars = Nothing

    Where to release odoc is a bit trickier, because it depends on at what point you no longer need to access the document you created. If you want the document to be available until the user closes the Windows Form, then you should put the line in the event FormClosing or FormClosed.


    Cindy Meister, VSTO/Word MVP

    • Marked as answer by MBuchok Sunday, May 13, 2012 11:11 AM
    Sunday, May 13, 2012 7:29 AM
    Moderator
  • Perfect!  Exactly what I needed.

    I'm pretty new to VB.Net and didn't really think to put items in the class level.  I also wasn't aware of releasing objects from memory.  Thanks for your help!

    If you don't mind me asking - what is the effect of not releasing objects from memory on the form?  Or is it that it affects my computer?...


    • Edited by MBuchok Sunday, May 13, 2012 11:13 AM
    Sunday, May 13, 2012 11:11 AM
  • Unreleased COM objects can lead to "memory leaks". Basically, what can happen is that, since a "pointer" to the office application is held in memory, the application cannot be closed properly. The user probably can't see it any more, but it will still be listed in the processes of the Task Manager and won't go away until Windows shuts down.

    This can also lead to problems if your application tries to re-use objects, or when the user wants to work normally with the Office application.


    Cindy Meister, VSTO/Word MVP

    Sunday, May 13, 2012 1:58 PM
    Moderator
  • That would explain why I saw WINWORD.EXE in my taskmanager about 10 times the other day lol

    I just tried my form again and that doesn't happen anymore.  Thanks once again.  You've been very helpful :-)

    Sunday, May 13, 2012 2:07 PM