Solved

Send an RTF as Read Only

Posted on 2008-10-10
12
894 Views
Last Modified: 2013-11-28
I have a report that I send via email in rtf format. Is there any way to make the file read only so that the recipient can't modify the document?
0
Comment
Question by:shanej
  • 6
  • 3
  • 2
  • +1
12 Comments
 
LVL 74

Expert Comment

by:Jeffrey Coachman
ID: 22692630
shanej,

No

In order to create a Read-Only Document, you can use the "SnapShot" format or save the Report as a PDF.

There are tons of free utilities to convert your report to PDF's.
here are two:
http://www.cutepdf.com/
http://www.lebans.com/reporttopdf.htm

If you want to use the Snapshot then you must ensure that each recipient has the viewer, that is why PDF is preferred.

JeffCoachman
0
 

Author Comment

by:shanej
ID: 22692637
Okay, thanks.  But how do I attach the PDF file you describe using SendObject?
0
 
LVL 23

Expert Comment

by:irudyk
ID: 22692693
You could attempt to output the report as an RTF, then use code to open the RTF document and resave it as a protected form (thus making it read-only) and then create a new email with the RTF file added as an attachment.  The code below could be modified to meet your specific needs.
Function SendReadOnlyReport()
 

'output report to RTF

DoCmd.OutputTo acOutputReport, "NameOfReport", acFormatRTF, "C:\NameOfReport.rtf"
 

'make RTF read-only

Dim wd As Object

Set wd = CreateObject("Word.Application")

With wd.Application

    .Documents.Open "C:\NameOfReport.rtf"

    .ActiveDocument.Protect 2, True, "EnterPasswordHere"

    .ActiveDocument.Save

    .ActiveDocument.Close

    .Quit

End With
 

'create/display email with RTF attachment

Dim ol As Object

Dim olNameSpace As Object

Dim olMessage As Object

Set ol = CreateObject("Outlook.Application")

Set olNameSpace = ol.GetNamespace("MAPI")

Set olMessage = ol.CreateItem(0)

olMessage.Attachments.Add "C:\NameOfReport.rtf"

olMessage.Display
 

Set olMessage = Nothing

Set olNameSpace = Nothing

Set ol = Nothing
 

End Function

Open in new window

0
 

Author Comment

by:shanej
ID: 22692742
Thanks!  Where do I place the code and how do I call the function?  Should it go behind the button I am using to call the SendObject method?  Here is the code as it appears currently:

Private Sub btnEmail_Click()
On Error GoTo Err_btnEmail_Click

    Dim stDocName As String
   
    stDocName1 = "POEmailReportShipTo"
    stDocName2 = "POEmailReportRemoveFrom"
    stDocName3 = "POEmailReportReleaseTo"
    stDocName4 = "POEmailReportWorkAddress"
   
    On Error Resume Next
       
    Me!POUser = CurrentUser
   
    DoCmd.RunCommand acCmdSaveRecord
   
    If Me!ShipRemoveRelease = "1" Then
        DoCmd.SendObject acReport, stDocName1, acFormatRTF, Me!VendorEmail, , , "NIS Purchase Order"
    End If
    If Me!ShipRemoveRelease = "2" Then
        DoCmd.SendObject acReport, stDocName2, acFormatRTF, Me!VendorEmail, , , "NIS Purchase Order"
    End If
    If Me!ShipRemoveRelease = "3" Then
        DoCmd.SendObject acReport, stDocName3, acFormatRTF, Me!VendorEmail, , , "NIS Purchase Order"
    End If
    If Me!ShipRemoveRelease = "4" Then
        DoCmd.SendObject acReport, stDocName4, acFormatRTF, Me!VendorEmail, , , "NIS Purchase Order"
    End If

Exit_btnEmail_Click:
    Exit Function

Err_btnEmail_Click:
    MsgBox Err.Description
    Resume Exit_btnEmail_Click
   
End Function
0
 
LVL 23

Assisted Solution

by:irudyk
irudyk earned 400 total points
ID: 22692782
Try revising you code as follows:

Private Sub btnEmail_Click()

On Error GoTo Err_btnEmail_Click
 

    Dim stDocName(4) As String

    

    stDocName(1) = "POEmailReportShipTo"

    stDocName(2) = "POEmailReportRemoveFrom"

    stDocName(3) = "POEmailReportReleaseTo"

    stDocName(4) = "POEmailReportWorkAddress"

    

    On Error Resume Next

        

    Me!POUser = CurrentUser

    

    DoCmd.RunCommand acCmdSaveRecord

    

    'output report to RTF

    DoCmd.OutputTo acOutputReport, stDocName(Me!ShipRemoveRelease), acFormatRTF, "C:\" & stDocName(Me!ShipRemoveRelease) & ".rtf"
 

    'make RTF read-only

    Dim wd As Object

    Set wd = CreateObject("Word.Application")

    With wd.Application

        .Documents.Open C:\" & stDocName(Me!ShipRemoveRelease) & ".rtf"

        .ActiveDocument.Protect 2, True, "EnterPasswordHere"

        .ActiveDocument.Save

        .ActiveDocument.Close

        .Quit

    End With
 

    'create/display email with RTF attachment

    Dim ol As Object

    Dim olNameSpace As Object

    Dim olMessage As Object

    Set ol = CreateObject("Outlook.Application")

    Set olNameSpace = ol.GetNamespace("MAPI")

    Set olMessage = ol.CreateItem(0)

    olMessage.To = Me!VendorEmail

    olMessage.Subject = "NIS Purchase Order"

    olMessage.Attachments.Add C:\" & stDocName(Me!ShipRemoveRelease) & ".rtf"

    olMessage.Display

    'or to send (you will likely get an Outlook security prompt appear)

    'olMessage.Send

    Set olMessage = Nothing

    Set olNameSpace = Nothing

    Set ol = Nothing
 

    'delete output file

    Kill C:\" & stDocName(Me!ShipRemoveRelease) & ".rtf"
 

Exit_btnEmail_Click:

    Exit Function
 

Err_btnEmail_Click:

    MsgBox Err.Description

    Resume Exit_btnEmail_Click

    

End Function

Open in new window

0
 

Author Comment

by:shanej
ID: 22692835
ShipRemoveRelease is an Access 97 frame control.  In my case, there are four options of reports that can be chosen using radio buttons inside the frame control.  Hence the four If, Then statements in my code sample that are used to choose and process the reports.  Am I correct in assuming that your code would be placed in its entirety inside each of my If, Then statements for each of the four possible reports with the lines of your code referencing my reports changed as necessary?
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 23

Expert Comment

by:irudyk
ID: 22692873
No, I am suggesting that you replace your entire Sub btnEmail_Click() with my version of Sub btnEmail_Click().
I use an array stDocName(4) to store and select the correct report name based upon the value of the ShipRemoveRelease.  So for ShipRemoveRelease values of 1, 2, 3 and 4 the report names would be:
    stDocName(1) = "POEmailReportShipTo"
    stDocName(2) = "POEmailReportRemoveFrom"
    stDocName(3) = "POEmailReportReleaseTo"
    stDocName(4) = "POEmailReportWorkAddress"
Also, I'm using DoCmd.OutputTo and not DoCmd.SendObject which is why I have a section called
     'create/display email with RTF attachment
wherein I've replicated the recipient and subject for the email in additon to the document to be attached.
0
 

Author Comment

by:shanej
ID: 22692887
Got it.  I will evaluate and let you know ASAP if I have any more questions or clarifications.  I appreciate your time and effort and I promise I'll get back to you.  I am in California, USA and have to hit the hay for an early day tomorrow.  So, I'll say goodnight for now.....

Shane
0
 

Accepted Solution

by:
shanej earned 0 total points
ID: 22694515
Thank you IRUDYK.  The code that actually works is pasted below.  I had to add a " (quote) prior to the C:\ in each line that referenced it.  You'll notice, too, that I had to change the Exit and End statements to reference the Sub and not a function.  These function references were left in there by mistake from previous trials of other code.

I do have one more question, though.  The Dim statement references stDocName(4).  My limited coding ability makes me think it should be a requirement to Dim stDocName(1), (2), and (3) as well.  Why isn't this necessary?



Private Sub btnEmail_Click()
On Error GoTo Err_btnEmail_Click
 
    Dim stDocName(4) As String
   
    stDocName(1) = "POEmailReportShipTo"
    stDocName(2) = "POEmailReportRemoveFrom"
    stDocName(3) = "POEmailReportReleaseTo"
    stDocName(4) = "POEmailReportWorkAddress"
   
    On Error Resume Next
       
    Me!POUser = CurrentUser
   
    DoCmd.RunCommand acCmdSaveRecord
   
    'output report to RTF
    DoCmd.OutputTo acOutputReport, stDocName(Me!ShipRemoveRelease), acFormatRTF, "C:\" & stDocName(Me!ShipRemoveRelease) & ".rtf"
 
    'make RTF read-only
    Dim wd As Object
    Set wd = CreateObject("Word.Application")
    With wd.Application
        .Documents.Open "C:\" & stDocName(Me!ShipRemoveRelease) & ".rtf"
        .ActiveDocument.Protect 2, True, "EnterPasswordHere"
        .ActiveDocument.Save
        .ActiveDocument.Close
        .Quit
    End With
 
    'create/display email with RTF attachment
    Dim ol As Object
    Dim olNameSpace As Object
    Dim olMessage As Object
    Set ol = CreateObject("Outlook.Application")
    Set olNameSpace = ol.GetNamespace("MAPI")
    Set olMessage = ol.CreateItem(0)
    olMessage.To = Me!VendorEmail
    olMessage.Subject = "NIS Purchase Order"
    olMessage.Attachments.Add "C:\" & stDocName(Me!ShipRemoveRelease) & ".rtf"
    olMessage.Display
    'or to send (you will likely get an Outlook security prompt appear)
    'olMessage.Send
    Set olMessage = Nothing
    Set olNameSpace = Nothing
    Set ol = Nothing
 
    'delete output file
    Kill "C:\" & stDocName(Me!ShipRemoveRelease) & ".rtf"
 
Exit_btnEmail_Click:
    Exit Sub

Err_btnEmail_Click:
    MsgBox Err.Description
    Resume Exit_btnEmail_Click
   
End Sub
0
 
LVL 26

Expert Comment

by:dannywareham
ID: 22694698
Not to hijack (do not accept as an answer)

The Dim statement simply tells Access/Jet to reserve a certain amount of memory for a variable.

In the case of an array, Dim stDocName(4) As String, you reserve a piece of memory for string information and declare that the array will have four seperate values.

You don't need to declare Dim stDocName(1) As String etc, as it's aready declared with the Dim stDocName(4) As String statement

Does that help?
0
 

Author Comment

by:shanej
ID: 22694783
Yeah... I guess I thought that since the other Dim statements are referencing discrete objects, that they would have to be individually "Dim'd."  Does this work because only one object at a time is used during the session, therfore allowing the "blanket Dim'g" of the variables that are available?  Sorry to be so nebulus in my writing, but this stuff is harder than h... for me to describe.
0
 
LVL 26

Assisted Solution

by:dannywareham
dannywareham earned 100 total points
ID: 22694832
The easiest way to think of it is that a Dim'd variable is a box.
The box can hold different types of things - numbers, letters, dates or a variety.

An array is a Dim'd variable with a number in brackets. This changes the box from a standard cardboard box into more of a chocolate box - with lots of little areas for your chocolates.

You only need to say "Hey Access, this is a box, but it'sgoing to have four chocolate areas in it".

So:

Dim myVariable as String
means "Access - there's a box and I'm gonna keep letters in it"

Whereas:

Dim myVariable (3) as String
means "Access - there's a box and I'm gonna keep letters in it, but there's going to be three little areas in that box"

Does that make sense?
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Introduction The Visual Basic for Applications (VBA) language is at the heart of every application that you write. It is your key to taking Access beyond the world of wizards into a world where anything is possible. This article introduces you to…
In a multiple monitor setup, if you don't want to use AutoCenter to position your popup forms, you have a problem: where will they appear?  Sometimes you may have an additional problem: where the devil did they go?  If you last had a popup form open…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
With Microsoft Access, learn how to start a database in different ways and produce different start-up actions allowing you to use a single database to perform multiple tasks. Specify a start-up form through options: Specify an Autoexec macro: Us…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now