External incoming mail marked as draft and unsent - outlook

My question is similar to but not the same to the one below,
Mark a mailitem as sent (VBA outlook)
Basically, something (AV, bug in Outlook or Exchange or both), has modified hundreds of incoming (external emails) to a particular user as drafts and now appear as unsent. This means the user cannot reply to these messages and the suggested alternative of copying and pasting looks very unprofessional and confusing to the user's clients. Thankfully whatever was causing it stopped but the damage is done.
I need some way to modify the PR_MESSAGE_FLAGS programmatically. I am comfortable with VB script, VBA, VB.Net and even C#/C++ but I am coming up empty for how to do it.
Should it matter, the server is Exchange 2013 and client is Outlook 2010 or 2016 (32 or 64bit). The entire mailbox has been exported to PST and can be worked on offline if that helps. :)

Based on Dmitry's answer, here is the code that clones the old messages and marks them as sent so they can be replied to.
Only concern with it is that it seems to be breaking Conversations.
Dim mysession
Sub doFixDrafts()
log " Starting scan!"
Set mysession = CreateObject("Redemption.RDOSession")
mysession.Logon
Const sRootFolder = "\\Mailbox\Inbox"
Set oRootFolder = mysession.getfolderfrompath(sRootFolder)
'Set oRootFolder = mysession.PickFolder
doCleanupFolder oRootFolder, sRootFolder
log "Scan complete!!"
End Sub
Sub doCleanupFolder(oFolder, sFolder)
Dim c: c = 0
Dim i: i = 0
Dim tc: tc = Format(oFolder.Items.Count, "0000")
'Get start timestamp so we can report in at regular intervals...
Dim st: st = Now()
log "Checking... " & sFolder
Dim aMsgIDs()
'Make a list of 'unsent' messages
For Each Item In oFolder.Items
i = i + 1
If Not Item.Sent Then
c = c + 1
msgID = Item.EntryID
ReDim Preserve aMsgIDs(1 To c)
aMsgIDs(c) = msgID
c = Format(c, "0000")
End If
'Give update for large folders...
ct = Now()
td = DateDiff("s", st, ct)
If td > 15 Then
log c & "/" & i & "/" & tc & " so far..."
st = ct
End If
DoEvents
Next
c = Format(c, "0000")
log c & "," & tc & "," & sFolder
'Fix the corrupt messages
For m = 1 To CInt(c)
Set badMsg = mysession.GetMessageFromID(aMsgIDs(m))
sSender = badMsg.Sender
sSubject = badMsg.Subject
dSentDate = badMsg.SentOn
Set newMsg = oFolder.Items.Add("IPM.Note")
newMsg.Sent = True
badMsg.CopyTo (newMsg)
newMsg.Save
badMsg.Delete
Dim a As String
a = Format(m, "0000") & "," & sSender & ","
a = a & Chr(34) & sSubject & Chr(34) & ","
a = a & Chr(34) & dSentDate & Chr(34)
log a
DoEvents
Next m
For Each Item In oFolder.Folders
doCleanupFolder Item, sFolder & "\" & Item.Name
Next
End Sub
Sub log(s As String)
d = Format(Now(), "yyyy-mm-dd hh:mm:ss")
t = d & " " & s
Debug.Print t
Const logfile = "c:\temp\fixdrafts.txt"
Open logfile For Append As #1
Print #1, t
Close #1
End Sub

The answer is still the same - on the low (Extended MAPI) level, sent/unsent status (MSGFLAG_UNSENT bit in the PR_MESSAGE_FLAGS property) can only be changed before the item is saved for the very first time.
Outlook Object Model is subject to the same limitation of course, and the only way to create an item in the sent state is to create a PostItem object - it is created in the sent state. You will then need to change the message class back to IPM.Note and remove the icon related properties to make sure the item looks right.
Redemption (I am its author) lets you change the item's state (RDOMail.Sent is read/write before the first call to Save).
It should be pretty easy to create copies of existing unsent messages in the sent state - loop through the problematic messages (it is better to avoid using "for each" if you will be creating new items in the same folder - your "for each" loop will start picking up new messages. Loop through the messages first and store their entry ids in a list or array), create new item using Redemption (RDOFolder.Items.Add), set the Sent property to true (RDOMail.Sent = true), open the problematic message by its entry ids (RDOSession.GetMessageFromID), copy the problematic message into the new message using RDOMail.CopyTo(AnotherRDOMailObject), call RDOMail.Save on the new message and RDOMail.Delete on the old message.

Related

How to send lotus notes mail with VB script with other mail box

Hi I am sending lotus notes mail with VB script . Now I want to send mail with other mail box which is opened in my lotus notes instead of my mail box. I tried different options but no luck. I am using below code to send mail.
You can find the code in below URL:
https://gallery.technet.microsoft.com/scriptcenter/fe141119-9599-46a7-90ca-8dbc66d50297
option explicit
' --------------------------------------------------------------------------
' -- Create Lotus Notes email (and add attachment) using VB Script
' --
' -- Version 1.01
' --
' -- Created by : Michael Green
' -- migreen#westpac.com.au
' --
' -- Based on in-complete/partially working script from :
' -- http://en.allexperts.com/q/Using-Lotus-Notes-1427/Creating-LotusNotes-email-using-1.htm
' --
' -- Created : 06/10/2009
' -- Last Updated: 07/10/2009
' --------------------------------------------------------------------------
Dim oSession ' AS NotesSession
Dim strServer
Dim strUserName
Dim strMailDbName
Dim oCurrentMailDb ' as NOTESDATABASE
Dim oMailDoc ' as NOTESDOCUMENT
Dim ortItem ' as NOTESRICHTEXTITEM
Dim ortAttacment ' as NOTESRICHTEXTITEM
Dim oEmbedObject ' as ????
dim cstrAttachment
Dim blAttachment
cstrAttachment = "c:\Temp\Telstra.xls"
blAttachment = True
' Start a session to notes
wscript.echo "## Connecting to Lotus Notes session..."
Set oSession = CreateObject("Notes.NotesSession")
wscript.echo("NotesVersion : " & oSession.NotesVersion)
wscript.echo("NotesBuildVersion: " & oSession.NotesBuildVersion)
wscript.echo("UserName : " & oSession.UserName)
wscript.echo("EffectiveUserName: " & oSession.EffectiveUserName)
wscript.echo "## GetEnvironmentString..."
strServer = oSession.GetEnvironmentString("MailServer",True)
wscript.echo("Server :" & strServer)
' eg. CN=Michael V Green/OU=CORPAU/OU=WBCAU/O=WBG
strUserName = oSession.UserName
strMailDbName = Left(strUserName, 1) & Right(strUserName, (Len(strUserName) - InStr(1, strUserName, "")))&".nsf"
wscript.echo("MailDbName :" & strMailDbName)
wscript.echo "## Getting current Notes database..."
' open the mail database in Notes
set oCurrentMailDb = oSession.CurrentDatabase
wscript.echo("fileName:" & oCurrentMailDb.fileName)
wscript.echo("filePath:" & oCurrentMailDb.filePath)
wscript.echo("server:" & oCurrentMailDb.server)
wscript.echo("Title:" & oCurrentMailDb.Title)
If oCurrentMailDb.IsOpen = True Then
' Already open for mail
wscript.echo "## Lotus Notes mail database is already open !"
Else
wscript.echo "## Opening Lotus Notes mail database..."
oCurrentMailDb.OPENMAIL
End If
' Create a document in the back end
Set oMailDoc = oCurrentMailDb.CREATEDOCUMENT
' Set the form name to memo
OMailDoc.form = "Memo"
with oMailDoc
.SendTo = "migreen#westpac.com.au"
.BlindCopyTo = "mgreen#ozemail.com.au"
.CopyTo = "migreen#westpac.com.au"
.Subject = "This is a test of VB scripting driving Lotus Notes 7 "
end with
set ortItem = oMaildoc.CREATERICHTEXTITEM("Body")
with ortItem
.AppendText("Test of RTF Item append")
.AddNewLine(2)
.AppendText("Signature")
End With
' Create additional Rich Text item and attach it
If blAttachment Then
Set ortAttacment = oMailDoc.CREATERICHTEXTITEM("Attachment")
' Function EMBEDOBJECT(ByVal TYPE As Short, ByVal CLASS As String, ByVal SOURCE As String, Optional ByVal OBJECTNAME As Object = Nothing) As Object
' Member of lotus.NOTESRICHTEXTITEM
Set oEmbedObject = ortAttacment.EMBEDOBJECT(1454, "", cstrAttachment, "Attachment")
End If
wscript.echo "## Sending email..."
with oMailDoc
.PostedDate = Now()
.SAVEMESSAGEONSEND = "True"
.send(false)
end with
wscript.echo "## Sent !"
' close objects
set oMailDoc = nothing
set oCurrentMailDb = nothing
set oSession = nothing
Just replace the lines (that are complete nonsense, but I told you in the other post):
strMailDbName = Left(strUserName, 1) & Right(strUserName, (Len(strUserName) - InStr(1, strUserName, "")))&".nsf"
wscript.echo("MailDbName :" & strMailDbName)
wscript.echo "## Getting current Notes database..."
' open the mail database in Notes
set oCurrentMailDb = oSession.CurrentDatabase
wscript.echo("fileName:" & oCurrentMailDb.fileName)
wscript.echo("filePath:" & oCurrentMailDb.filePath)
wscript.echo("server:" & oCurrentMailDb.server)
wscript.echo("Title:" & oCurrentMailDb.Title)
If oCurrentMailDb.IsOpen = True Then
' Already open for mail
wscript.echo "## Lotus Notes mail database is already open !"
Else
wscript.echo "## Opening Lotus Notes mail database..."
oCurrentMailDb.OPENMAIL
End If
with
strServer = "ServerNameWhereMailboxIs"
strMailDbName = "mail\nameofotherdatabase.nsf"
set oCurrentMailDb = oSession.GetDatabase( strServer, strMailDbName )
That will do the trick.
As your question changed after my answer, I will -for the sake of anybody finding this question in the future- add some code for "sending an email in the name of another sender":
In Lotus Notes it is not possible to "send" a mail without leaving traces of the person who really sent it:
When you receive such a mail, that was sent by someone else you will see, that the mail comes from the other mailbox, but it will contain the information "Sent by" with the mailaddress of the "real" sender.
To at least make the "visual" sender look right, you need to add different fields that are needed in different cases: These fields are Principal, InetPrincipal, From and InetFrom.
However: On a Domino- Server that is configured right, this will not help: It will calculate these fields from the "real" sender and ignore what you gave him.
But there is a trick to make the router leave these fields alone: You have to add the NotesDomain to the adressen. If you add the following lines to your code, then the router will ignore these and keep the fields intact:
MailDoc.principal = "noreply#company.com#NotesDomain"
MailDoc.inetprincipal = "noreply#company.com#NotesDomain"
MailDoc.from = "noreply#company.com#NotesDomain"
MailDoc.inetfrom = "noreply#company.com#NotesDomain"
If you really need to "hide" the real sender completely from the recipient, then you cannot create the mail in the mail database, but create it directly in the "mail.box" of the server and just "Save" it instead of "Send" it. But this has other downsides and will not be discussed here.
I just want to leave one more answer about "send from/reply to" because this question here is what I found when I was searching for help:
I found out that only my own mailadress is shown to external recipients or people not using IBM notes. Even if I sent mails via a different mailfile (a Mail-In) only my own mailadress was shown and I also was the one the recipient could reply to. So I tried something, and it worked.
After some testing, this lines helped me out internal and external:
sender = """John Doe""" & "<support#domain.de>"
MailDoc.ReplyTo = sender
MailDoc.SMTPOriginator = sender
MailDoc.sender = sender
MailDoc.principal = sender
MailDoc.inetprincipal = sender
MailDoc.from = sender
MailDoc.inetfrom = sender
MailDoc.displayfrom = sender

VBScript Error: "Entry not found in index..." when opening documents Lotus Notes

Here is a working script for extract attachments from Lotus Notes letters:
Dim s
s = 1
Do
s = s + 1
Dim Session
Dim Maildb
Dim view
Dim vc
Dim doc
Dim Item
Dim coll
Dim x
Dim Sender
Dim sentTo
Dim viewTimer
Dim ws
Dim Source
Set Session = CreateObject("Lotus.NotesSession")
Call Session.Initialize("password")
Set Maildb = Session.GetDatabase("DOMAIN/Servers/Server-Name/RU", "GroupMail\mailbox.nsf")
Set view = Maildb.GetView("($inbox)")
If Not Maildb.IsOpen = True Then
Call Maildb.Open
End If
With view
x = 0
ReDim LmailID(x)
ReDim HasAttach(x)
Set doc = .GetFirstDocument
If doc Is Nothing Then
else
Call doc.PutInFolder("Processed")
Call doc.Removefromfolder("($inbox)")
Do
fileNames = Session.Evaluate("#AttachmentNames", doc)
For Each Filename In fileNames
Sender = doc.GETITEMVALUE("From")(0)
strSearchForSpecificName = "SpecificName"
If InStr(1, Sender, strSearchForSpecificName) > 0 then
sentTo = "SpecificName#mail.ru"
else
sentTo = Sender
End If
If Filename <> "" Then
Call doc.Save( False, False, True )
Set NotesEmbeddedObject = doc.GetAttachment(FileName)
NotesEmbeddedObject.ExtractFile ("d:\#files\" + Right("0" & Month(Now), 2) & "-" & Right("0" & Day(Now), 2) & "-" & Year(Now) & "-" & Hour(Time) & Minute(time) & Second(time) & "_" & Filename)
Set reply = doc.CreateReplyMessage( False )
Call reply.replaceItemValue("SendTo", sentTo)
Call reply.replaceItemValue("CopyTo", "copy#mail.ru")
Call reply.replaceItemValue("Subject", "Re: " & "файл " + Filename + " передан в обработку " + Right("0" & Month(Now), 2) & "-" & Right("0" & Day(Now), 2) & "-" & Year(Now) & Hour(Time) & ":" & Minute(time) & ":" & Second(time))
doc.SaveMessageOnSend = True
Call reply.Send( False )
End If
Next
x = x + 1
ReDim Preserve LmailID(x)
Set doc = .GetNextDocument(doc)
Loop Until doc Is Nothing
End If
End With
Wscript.Sleep (30 * 1000)
Set Session = Nothing
Set Maildb = Nothing
Set view = Nothing
Set vc = Nothing
Set doc = Nothing
Set Item = Nothing
Set coll = Nothing
Set x = Nothing
s = s - 1
Loop While s > 0
The problem is that sometimes I'm getting an error: Error: "Entry not found in index..." and program stopped at Set doc = .GetNextDocument(doc) line.
Is there there solution for resolve this error?
Your code is removing the first doc from the $Inbox, therefore it cannot be used as the anchor for getting the next document in $Inbox. The solution would normally be to make sure that you get the next document before you remove the current document. I.e., change
Call doc.PutInFolder("Processed")
Call doc.Removefromfolder("($inbox)")
to
Call doc.PutInFolder("Processed")
set nextDoc = .getNextDocument(doc)
Call doc.Removefromfolder("($inbox)")
and change
Set doc = .GetNextDocument(doc)
to
set doc = nextDoc
However, your code with the putInFolder and RemoveFromFolder calls is not actually inside the loop, therefore only the first doc that you process will be moved to the Processed folder and nextDoc will not be properly set after the first iteration of the loop. If you really only want to move the first document to the Processed folder, then the above solution still isn't right because you'll only be setting nextDoc once, outside the loop and you will have an infinite loop since you'll always be setting doc to the same nextDoc value. You'll need another instance of nextDoc = getNextDocument(doc) inside the loop. If you really want all documents to be moved to the Processed folder, then you just need to move the entire block of code dealing with the folders and assigning nextDoc into the inside of the loop.
The problem is simple: The document is removed from Inbox and therefor is not in the index anymore. This happens if one of two conditions are true:
The NotesView- Property "AutoUpdate" is set to true
Your timer- triggered "refreshView"- sub (that is not in your example code) does a view.Refresh.
Despite of the fact, that in your code there is a lot of "nonsense" (sorry to say), it is easy to fix this code:
Just use the fact, that the view- object can be updated as advantage and change to "getfirstdocument" all the time:
Change this line:
Set doc = .GetNextDocument(doc)
to these lines:
Call .Refresh()
Set doc = .GetFirstDocument
What does this do: The Refresh removes the currently processed document from the view. The "next" document will be the first in view. And that one you get until there is no more "first" document...
And: Richard is right. You need to move the two rows Call doc.PutInFolder("Processed")
Call doc.Removefromfolder("($inbox)") below the Do in order to move ALL documents to the folder and not only the first one.

Setting VBA to read personal inbox

trying to get some VBA code together to basically be able to run my rules from a button on my toolbar within outlook 2007. The following code runs the rules on my exchange server inbox, which is empty as everything moves to my "Personal Inbox". I just want to change the code below to read my personal inbox and not my exchange mailbox inbox. Have searched on the web and cant find my answer and hence my post -
Sub RunAllInboxRules()
Dim st As Outlook.Store
Dim myRules As Outlook.Rules
Dim rl As Outlook.Rule
Dim count As Integer
Dim ruleList As String
'On Error Resume Next
' get default store (where rules live)
Set st = Application.Session.DefaultStore
' get rules
Set myRules = st.GetRules
' iterate all the rules
For Each rl In myRules
' determine if it's an Inbox rule
If rl.RuleType = olRuleReceive Then
' if so, run it
rl.Execute ShowProgress:=True
count = count + 1
ruleList = ruleList & vbCrLf & rl.Name
End If
Next
' tell the user what you did
ruleList = "These rules were executed against the Inbox: " & vbCrLf & ruleList
MsgBox ruleList, vbInformation, "Macro: RunAllInboxRules"
Set rl = Nothing
Set st = Nothing
Set myRules = Nothing
End Sub
Try this. I have tested on my machine. This logs into the mailbox you are logged onto and runs the rules accordingly
Sub RunAllInboxRules()
Dim objOL As Outlook.Application
Dim st As Outlook.Store
Dim myRules As Outlook.Rules
Dim rl As Outlook.Rule
Dim count As Integer
Dim ruleList As String
Dim fldInbox As Object
Dim gnspNameSpace As Outlook.NameSpace
'On Error Resume Next
' get default store (where rules live)
'Logs into Outlook session
Set objOL = Outlook.Application
Set gnspNameSpace = objOL.GetNamespace("MAPI") 'Outlook Object
'Logs into the default Mailbox Inbox
'set the store to the mailbox
Set st = gnspNameSpace.GetDefaultFolder(olFolderInbox).Store
' get rules
Set myRules = st.GetRules
' iterate all the rules
For Each rl In myRules
' determine if it's an Inbox rule
If rl.RuleType = olRuleReceive Then
' if so, run it
rl.Execute ShowProgress:=True
count = count + 1
ruleList = ruleList & vbCrLf & rl.Name
End If
Next
' tell the user what you did
ruleList = "These rules were executed against the Inbox: " & vbCrLf & ruleList
MsgBox ruleList, vbInformation, "Macro: RunAllInboxRules"
Set rl = Nothing
Set st = Nothing
Set myRules = Nothing
End Sub

crystal reports 8 - set location dynamically in vb6

I have a VB6 front end, SQL Server 2005 as the back end and Crystal Reports 8.5 for reports.
I need to set the location at run time in my application as I have 2 databases. My problem is that when I change database, but the location remain the same. It will be great if anyone can help me out. Thanks in advance for your time, and here is my code.
Private Sub prin_Click()
With CrystalReport1
.Connect = MDI1.txtcn --> this is my connection info "driver={sql server};server=server;database=database;uid=user;pwd=password"
.DiscardSavedData = True
.Action = 1
.PrintReport
End With
Try some code like this:
Private Sub cmdSetLocations_Click()
Dim CrxApp As New CRAXDRT.Application
Dim CrxRep As CRAXDRT.Report
Dim CrxSubRep As CRAXDRT.Report
Dim strReport As String
Dim i As Integer, ii As Integer
strReport = "[Path to report file]"
Set CrxRep = CrxApp.OpenReport(strReport)
SetReportLocation CrxRep
For i = 1 To CrxRep.Sections.Count
For ii = 1 To CrxRep.Sections(i).ReportObjects.Count
If CrxRep.Sections(i).ReportObjects(ii).Kind = crSubreportObject Then
Set CrxSubRep = CrxRep.OpenSubreport(CrxRep.Sections(i).ReportObjects(ii).SubreportName)
SetReportLocation CrxSubRep
End If
Next ii
Next
'open your report in the report viewer
Set CrxApp = Nothing
Set CrxRep = Nothing
Set CrxSubRep = Nothing
End Sub
Private Sub SetReportLocation(ByRef RepObj As CRAXDRT.Report)
Dim CrxDDF As CRAXDRT.DatabaseTable
Dim CP As CRAXDRT.ConnectionProperties
For Each CrxDDF In RepObj.Database.Tables
Set CP = CrxDDF.ConnectionProperties
CP.DeleteAll
CP.Add "Connection String", "[Your connection string goes here]"
Next
Set CrxDDF = Nothing
Set CP = Nothing
End Sub
With CR
.ReportFileName = App.Path + "\Labsen2.rpt"
.SelectionFormula = "{PersonalCalendar.PersonalCalendarDate}>= Date(" & Year(DTPicker1) & "," & Month(DTPicker1) & "," & Day(DTPicker1) & ") and {PersonalCalendar.PersonalCalendarDate}<=date(" & Year(DTPicker2) & "," & Month(DTPicker2) & "," & Day(DTPicker2) & ") and {Department.DepartmentName}= '" & Combo1.Text & "'"
.Formulas(0) = "tglAwal = '" & DTPicker1.Value & "'"
.Formulas(1) = "tglAkhir = '" & DTPicker2.Value & "'"
.Password = Chr(10) & "ithITtECH"
.RetrieveDataFiles
.WindowState = crptMaximized
.Action = 1
End With
Try formatting the connection string like this:
DSN=server;UID=database;PWD=password;DSQ=user
The meanings of DSN, UID, DSQ are counter-intuitive, they are overloaded by Crystal.
Also check you have no subreports whose Connect properties would need to be similarly changed.
Why not pass the recordset to your report? In this way you will be able to get data from any supported (i mean VB6 can connect to) databases dynamically, you can even merge data from multiple databases, your report will require the data(recordset) only and report will be created with Data Field Definition.

VBPrnDlg object incorrectly disabling page selection

I'm changing some crufty old printing code to use the Visual Basic Print Dialog Control to pass printer information to a CrystalReport object. It works great except for one thing - the page selection box is consistently disabled no matter what flags I pass the object. Here is my code:
Public Enum PrintDialogFlags
NoFlag = 0
DisablePagesButton = 1
LoadIntoPrnObject = 2
AutoStartPrint = 4
End Enum
Public Function ShowPrintDialogCR(ByVal hwnd As Long, ByRef cr As CrystalReport, _
Optional PrintFlags As Long = 0) As Boolean
//this function assumes cr is a valid report object
On Error GoTo ShowPrintDialogCR_Error
Dim PD As New vbprndlglib.PrinterDlg
//load default settings
PD.PrinterName = Printer.DeviceName
PD.DriverName = Printer.DriverName
PD.Port = Printer.Port
PD.PaperBin = Printer.PaperBin
PD.CancelError = True
PD.flags = (vbprndlglib.cdlPDNoSelection Or vbprndlglib.cdlPDHidePrintToFile)
// commented the line below out to see if it was something with my logic
// Still disables page selection without this line
//If PrintFlags And DisablePagesButton Then PD.flags = PD.flags Or vbprndlglib.cdlPDNoPageNums
Printer.TrackDefault = False
PD.ShowPrinter (hwnd)
cr.PrinterPort = PD.Port
cr.PrinterDriver = PD.DriverName
cr.PrinterName = PD.PrinterName
cr.CopiesToPrinter = PD.Copies
If PD.flags And vbprndlglib.cdlPDPageNums Then
cr.PrinterStartPage = PD.FromPage
cr.PrinterStopPage = PD.ToPage
End If
If PrintFlags And PrintDialogFlags.LoadIntoPrnObject Then
//copy these settings to the printer object
Dim prn As Printer
For Each prn In Printers
If prn.DeviceName = PD.PrinterName Then
Set Printer = prn
Exit For
End If
Next prn
Printer.PaperBin = PD.PaperBin
Printer.PaperSize = PD.PaperSize
Printer.Duplex = PD.Duplex
Printer.Copies = PD.Copies
Printer.ColorMode = PD.ColorMode
Printer.Orientation = PD.Orientation
Printer.PrintQuality = PD.PrintQuality
End If
Set PD = Nothing
If PrintFlags And PrintDialogFlags.AutoStartPrint Then cr.Action = 1
ShowPrintDialogCR = True
Printer.TrackDefault = True
Exit Function
ShowPrintDialogCR_Error:
If Err.Number = 20545 Then //request cancelled by user
MsgBox "The print request was cancelled after being submitted to the print spooler." & vbNewLine & _
"If you cancelled a print to file dialog, this is a normal message. " & vbNewLine & _
"Otherwise, this message could mean your printer is not accepting print requests from us at this time." _
, vbOKOnly + vbExclamation, "Print Request Cancelled"
ErrorLogger Err, "ShowPrintDialogCR"
ElseIf Err.Number <> 32755 Then
//something else besides clicking cancel, show the error
MsgBox "Error " & Err.Number & " - " & Err.Description & vbNewLine & "Source: " & _
Err.Source & vbNewLine & vbNewLine & "Document not printed.", vbOKOnly + vbCritical, "Print Failure"
ErrorLogger Err, "ShowPrintDialogCR"
End If
Err.Clear
ShowPrintDialogCR = False
Printer.TrackDefault = False
End Function
I don't see what I'm doing wrong here. I've passed several combinations of unrelated flags just to see if the box would enable itself with no success. I've encountered VB6 quirks before and I'm really hoping this isn't one of them. Any help is much appreciated!
I found this in the KB article you linked to:
To enable the Select Pages portion of
the Print dialog box, Max must be set
to a number that is larger than Min.
So, at the very least, you need to set the Min and Max properties on the print dialog object to something reasonable before you set the flags:
PD.CancelError = True
'Set Min and Max to enable page selection'
PD.Min = 1
PD.Max = 32767 'Or any large number really'
PD.flags = (vbprndlglib.cdlPDNoSelection Or vbprndlglib.cdlPDHidePrintToFile)
In my own experimenting I also found out the following few things:
If you just set Min and Max, the page selection will default both the "To" and "From" fields to 1.
If you set Min to 1 and Max to -1, and also set FromPage to 1 and ToPage to -1, the "From" field will default 1 and the "To" field will be empty. It's interesting that this works since the documentation states that Max must be larger than Min, but it looks like -1 is treated more like an "empty" or "null" value.
If you set the vbPrnDlg.cdlPageNums flag, the Print Dialog will default to the Pages radio button when it's displayed. If you omit the vbPrnDlg.cdlPageNums flag, the dialog will default to the All radio button.

Resources