VB.NET batch pdf printer tool - vb.net

I'm looking for a tool, but I can't find it. So I thought, maybe I can make one. Seems like a good idea, a program that fits my needs at last! Just one problem.. I don't know how!
Intro
At my work we create production drawings in .dwg format. Once this is done they are exported as .pdf sent to the client for approval. If approved they are issued for production, so they need to be plotted.
So my current workflow is:
Set my default printer preferences (number of copies, paper size, ..)
Go to the folder that has the .pdf files
Select 15 files
Right click print.
The problem here is
The files are printed in the order the printer receives them and not the order in the folder. So I would need to sort them out ( this x number times the number of copies sometimes this goes up to 6 times. )
I can only do 15 at a time (large projects are +100 documents)
I have to reset my preferences each time the sizes change.
Our file numbering system has some "intelligence" into it. Its build like this:
A1-12345-001 rev1
A1 = page size
12345 = document number, the same within a project. Other project means other number. (mostly irrelevant as I only print a project at a time)
001 = sequence number, next drawing will be 003,004,005,007,... you get the drift.
rev1 = revision number. Normally only the highest revision should be located in the folder, but it could be used to check for documents with a lower revision.
Now, I would like to automate my happy printing task, as this makes my week very bad if a large projects needs to go into production or, there are revisions mid-production and we need to re-issue them for production.
So far the situation sketch
Program sketch
So I've started to make a sketch of what the program should do.
User should be able to add .pdf files into a list. file browser object for starters, can be drag and drop later (the drawings are in one folder so there is no real need for drag and drop).
The list should contain 4 columns. paper size, document number, sequence, revision. Could be a data-grid view.
The list should be sorted by the drawing sequence. This how I would like to pass the drawing so, no sorting is required anymore! You can look at the sequence as page numbers.
Select the desired printer to do the job. (usually the same but other departments also have a printer so that would be a nice option.)
Set the number of copies. When printed, it shouldn't be 5x -001 then 5x -002 .. it should print them still in order of the sequence number and the re-loop the process x times.
Print the documents.
Adding PDF files
I started out with creating a dialog.. easy enough I guess.(please keep in mind that I'm a very low level programmer and nothing seems easy to me..) I added an open file dialog to my windows-form set multiple select true. Also made a filter to have only .pdf files
added a button with this code:
Private Sub ADD_FILES_Click(sender As Object, e As EventArgs) Handles ADD_FILES.Click
' Show the open file dialog. If user clicks OK, add pdf_document to list(of T)
If FileDialog.ShowDialog() = DialogResult.OK Then
Dim file As String
For Each file In FileDialog.FileNames
Debug.Print(file)
Next
End If
End Sub
So this should give me all the info I need from the file. I will edit this later, I know how to access it now!
The document object
I guess it would be wise to use some o.o.p. for this. As each file is a document and have the same required properties to make this work.
So I made a Public class for the document called PDF_Document
Public Class PDF_Document
Public FullFilePath As String
Public Property Size As String
Public Property DocNumber As String
Public Property Sequence As String
Public Property Revision As String
Public Sub New(ByVal oFilePath As String)
' Set the FullFilePath
FullFilePath = oFilePath
' Get the filename only without path.
Dim oFileName As String
oFileName = Path.GetFileName(oFilePath)
' Get the document size from the file name
Size = oFileName.Substring(0, 2)
' Get the document number from the file name
DocNumber = oFileName.Substring(3, 5)
' Get the sequence from the file name
Sequence = oFileName.Substring(9, 3)
' Chop of the .pdf from the name to get access the revision
Revision = oFileName.Substring(oFileName.Length - 5, 1)
End Sub
End Class
Well this should result into the info I need from the document..
creating a list(of t)
Wow, it seems to be getting somewhere.. Now to hold the list I'll have this collection I think don't know whats best for this? Public oPrintList As New List(Of PDF_Document)
So I think I should populate my list like this?
Public oPrintList As New List(Of PDF_Document)
Private Sub ADD_FILES_Click(sender As Object, e As EventArgs) Handles ADD_FILES.Click
' Show the open file dialog. If user clicks OK, add pdf_document to list(of T)
If FileDialog.ShowDialog() = DialogResult.OK Then
Dim oFile As String
For Each oFile In FileDialog.FileNames
Dim oPDF As New PDF_Document(oFile)
oPrintList.Add(oPDF)
Next
End If
End Sub
Making things visual for the user
Hmm okay, were getting somewhere, I got a list of all the files I need! But I want to see them in a viewer. I'm gonna use a data-grid view maybe? It should show my properties and it looks good I think.
So I made a binding that binds my List(of T) and added this binding as data-source for the data-grid view. I also change the ADD_FILES_Click a little, the PDF_Document is now added into the binding and not in the List(of T).
Public Class Form1
Public oPrintList As New List(Of PDF_Document)
Public oBinding As BindingSource
Private Sub ADD_FILES_Click(sender As Object, e As EventArgs) Handles ADD_FILES.Click
' Show the open file dialog. If user clicks OK, add pdf_document to list(of T)
If FileDialog.ShowDialog() = DialogResult.OK Then
Dim oFile As String
For Each oFile In FileDialog.FileNames
Dim oPDF As New PDF_Document(oFile)
oBinding.Add(oPDF)
Next
End If
End Sub
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
oBinding = New BindingSource(oPrintList, Nothing)
DataGridView1.DataSource = oBinding
End Sub
End Class
Printing the list
Well I managed to do quite some things now. But.. the main essence still isn't reached! I now got a form with a bunch of buttons that don't work yet, a list of select documents in queue for printing and .. thats it :)
Now I'm trying to create a method that prints a .pdf file.. easier sad than done. I need some help with this.. I search the net, but I can find samples that don't work, or I don't understand. All users PC's are equiped with acrobat reader.
Also feel free to comment me on the other parts of the program. ( yes I know there is no sorting function yet etc. ) but getting a page from the printer is more important now.
Sorry for the long post!

If your users have Adobe Acrobat Reader installed, the following code should do the trick. I recommend Acrobat Reader 11 or lower version. With Acrobat DC the window from Acrobat does not close anymore, that is a "design" decision by Adobe.
Dim pr As New Process()
pr.StartInfo.FileName = "c:\myfile.pdf"
pr.StartInfo.UseShellExecute = True
pr.StartInfo.Verb = "print"
pr.Start()
pr.WaitForExit()
I work with DWG and PDF files for 20+ years. If you are interested in a solution that fully automates all steps you explained in your "wishlist" software and does a ton more feel free to contact me at pdfmagick at gmail dot com
Another way to print PDF files with the Print Drivers dialog is as follows:
Dim starter As ProcessStartInfo
starter = New ProcessStartInfo(<pathToAdobeAcrobatExecutable>, String.Format(" /s /N /P ""{0}""", Filename))
Dim Process As New Process()
Process.StartInfo = starter
Process.Start()
Process.WaitForExit()
Process = Nothing
starter = Nothing
More command line switches are explained here
Adobe Reader Command Line Reference
Regards

Related

Cannot save a freshly created bmp file, help needed

Hate to sound like a broken record, but I simply cannot get the program I wrote in Visual Basic to write a file when run standalone; but it works fine when run via the debugger.
Simplified, the code looks like this (and the bitmap image is being created and is being saved, i.e., the file does not already exist):
Using bmp As New Bitmap(imgHorSize, imgVerSize) ‘ the sizes are not too large
<build the bitmap>
Dim fName As String = “C:\Users\<name>\Desktop\temp\foobar.jpg"
bmp.Save(fName, ImageFormat.Jpeg)
End Using
When I run this outside the debugger, I get
System.UnauthorizedAccessException: Access to the path
'C:\Users<name>\Desktop\temp\foobar.jpg' is denied
I saw some notes that suggest there should be a \\ after C:. Other sources show using a / instead of a \. Not sure that either really matters (since the directory name is coming from the result of a FolderBrowserDialog). I have checked the folder permissions on temp and see that my account has full control. I added user Everyone, via the security tab, and gave it full control. Same problem. As an experiment, I changed the above code to
Using bmp As New Bitmap(imgHorSize, imgVerSize)
<build the bitmap>
Dim fName As String = “C:\Users\<name>\Desktop\temp\foobar.jpg"
Dim file As System.IO.StreamWriter
file = My.Computer.FileSystem.OpenTextFileWriter(fName, True)
file.WriteLine("Here is the first string.")
End Using
and I got the exact same error. I also tried creating a MemoryStream, but that also didn’t work.
So, the issue is probably not related to the bmp.Save process, but something more fundamental. I have been looking at various things and have tried a few of them, but nothing works. This should be super easy to do, so what am I doing wrong?
== follow up ==
To come up with something to share in its entirety, I just wrote the following, very simple program that basically does the same as the real program:
Imports System.Drawing
Imports System.Drawing.Imaging
Public Class Form1
Structure myImages
Dim strFName As String
Dim imgL As Image
End Structure
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim imgLI As myImages
imgLI.strFName = "C:\Users\<username>\Desktop\EinRiddle\ItemImages\An_Cat.jpg"
imgLI.imgL = New Bitmap(Image.FromFile(imgLI.strFName), 150, 150)
Dim bmp As New Bitmap(300, 400)
Using bmp
Dim gr As Graphics = Graphics.FromImage(bmp)
gr.Clear(Color.WhiteSmoke)
gr.DrawImage(imgLI.imgL, 20, 20)
bmp.Save("C:\Users\<username>\Desktop\testImg.jpg", ImageFormat.Jpeg)
gr.Dispose()
End Using
Application.Exit()
End
End Sub
End Class
I am getting the same error message...
Have you tried another directory? Often one cannot write a file to the desktop.
Have you tried another format (for example ImageFormat.Bmp)?
You use “ instead of " ... Is that the mistake? Ah, I guess this is not the real code and you wrote this from memory and and something made “
Sometimes it takes a while before the picture and graphics can be disposed because the image is saved lazily. Even if this is not welcomed, give it a try
bmp.Save("C:\Users\<username>\Desktop\testImg.jpg", ImageFormat.Jpeg)
Application.DoEvents()
gr.Dispose()
End Using
I found the answer: On this computer, my user files are on the D: drive. Thus, when I changed the path from C: to D:, it worked. Of course, why this is necessary, since there is symbolic link, I don't understand...

Autodesk Inventor place part at user defined position

I'm trying to create a method that will place a file into an assembly, and I want it to be like when you choose place file in Inventor.
The file is been chosen by it's path. And now it needs to be placed. I know a way how to place the file at coordinates, but I want the file to be on the cursor and the user be able to choose where to drop it.
How do you do achieve this? I tried a programming help search but I can only find thing about the event and dialog.
FileDialog.InsertMode() As Boolean
Normally I just place and ground, but that not good now..
Public Function Place_and_Ground_Part(ByVal oDef As AssemblyComponentDefinition,
ByVal path As String) As ComponentOccurrence
' Set a reference to the assembly component definintion.
' This assumes an assembly document is open.
' Set a reference to the transient geometry object.
Dim oTG As TransientGeometry
oTG = oInvApp.TransientGeometry
' Create a matrix. A new matrix is initialized with an identity matrix.
Dim oMatrix As Matrix
oMatrix = oTG.CreateMatrix
' Set the translation portion of the matrix so the part will be positioned
' at (3,2,1).
oMatrix.SetTranslation(oTG.CreateVector(0, 0, 0))
' Add the occurrence.
Dim oOcc As ComponentOccurrence
oOcc = oDef.Occurrences.Add(path, oMatrix)
' Make sure the master part is grounded
oOcc.Grounded = True
Return oOcc
End Function
It certainly isn't obvious how to accomplish what you want, but it is possible, if you know how. The code below demonstrates using the PostPrivateEvent method where you post the filename of the file you want to insert onto an internal queue within Inventor. Next, it gets and runs the Place Component just the same as if the user were to start the command. The command first checks to see if a filename is on the private queue and if it is it takes that filename and skips the dialog step. This results in the user being able to drag and position the occurrence.
Public Function Place_and_Ground_Part(ByVal invApp As Application,
ByVal path As String) As ComponentOccurrence
' Post the filename to the private event queue.
invApp.CommandManager.PostPrivateEvent(Inventor.PrivateEventTypeEnum.kFileNameEvent, filename)
' Get the control definition for the Place Component command.
Dim ctrlDef As Inventor.ControlDefinition
ctrlDef = invApp.CommandManager.ControlDefinitions.Item("AssemblyPlaceComponentCmd")
' Execute the command.
ctrlDef.Execute()
Return Nothing
End Function
You've probably noticed that the function is returning Nothing. This is a problem using this approach because you execute the command and then turn control over to Inventor. It is possible to use events to watch and see if a new occurrence is placed and then get it but it complicates the code quite a bit since it's no longer a simple function.

Notepad database in VB

I am completely new to VB.net and have only been learning in for a few weeks
I am doing a project where i need to make an EPOS systems using notepad as a data base. I am able to make the values of the buttons appear in the list box, however I have numerous buttons all with different values but only the first value in the text box is appearing each time a different button is pressed.
E.G
When Heineken button pressed "Heineken €5.00" is displayed
when Guiness button pressed "Heineken €5.00" is displayed
Any help is greatly appreciated!
Imports System.IO
Public Class Form1
Private Sub btnHeineken_Click(sender As Object, e As EventArgs) Handles btnHeineken.Click
Dim sr As IO.StreamReader = IO.File.OpenText("DATABASE.txt")
'File DATABASE.TXT is the the debug folder
Dim name As String
Dim stock, price As Double
name = sr.ReadLine
stock = CDbl(sr.ReadLine)
price = CDbl(sr.ReadLine)
lstBox.Items.Add(name & "" & FormatCurrency(price))
name = sr.ReadLine
End Sub
Private Sub BtnGuiness_Click(sender As Object, e As EventArgs) Handles BtnGuiness.Click
Dim sr As IO.StreamReader = IO.File.OpenText("DATABASE.txt")
'File DATABASE.TXT is the the debug folder
Dim name As String
Dim stock, price As Double
name = sr.ReadLine
stock = CDbl(sr.ReadLine)
price = CDbl(sr.ReadLine)
lstBox.Items.Add(name & "" & FormatCurrency(price))
name = sr.ReadLine
End Sub
DATBASE.txt
Heineken
5.00
20
Guiness
4.50
50
Bulmers
5.00
25
Both your methods have exactly the same code. Thus, they do exactly the same thing: They show the contents of the first entry in your text file.
If you want your methods to do different things, you need to put different code in them.
Unfortunately, putting arbitrary code in your methods won't make them do what you want. It looks like you already discovered that. So the next step is to take a more structured approach:
Decide what your button click should do. It looks like you already did that: You want to display "Guiness €4.50" when the "Guiness" button is clicked.
Next, think about how your program can do that. Apparently, that's where you are stuck. You have a text file with a list of entries, how do you get the one you want?
Translate the result of step 2 (the "algorithm") in code.
You tried to do step 3 before step 2. That won't work, and that's the reason why your code doesn't work.
I suggest that you think really hard about step 2 (How do I find data in a text file? How would I do it if I had the file printed out in front of me and were searching for the data personally?), come up with an algorithm and then return here and ask a new question if you need help translating it to code.

How can I Display Text Files?

I have a program that allows the user to complete test where all the user's scores are recorded in a seperate text file for each test. How would I display each text file so that for each test the scores can be displayed?
You can do this with a Linq query:
var scores = from file in System.IO.Directory.GetFiles(#"c:\path", "*.scores")
select GetScoreFromFile(System.IO.File.ReadAllLines(file));
with GetScoreFromFile:
private int GetScoreFromFile(string[] scoreLines)
{
// Some code to read the score from the file
}
To actually display the scores... You probably want to make something fancy (it sounds pretty game-like). If not, go with some sort of Grid control.
You can use an ini configuration file to do this. I have designed a VB class library which contains an ini File reader class which can be used to read and write to ini configuration files. Rather than save each score as a separate file, you can contain it in a single ini configuration file by separating them in sections.
You can download my class library here
Add a reference to the library in your project.
Here is an example of how to use it:
Dim ScoresReader As New Rodit.IniLib.IniParser
Public Sub ReadTestScores(ScoreFilePath As String)
ScoresReader = New Rodit.IniLib.IniParser 'Initializes new instance of class
ScoresReader.Load(ScoreFilePath) 'Loads scores file specified in subroutine args
For Each score As Rodit.IniLib.IniParser.IniSection In ScoresReader.Sections 'Each section in the ini file will represent a different user's score
'Here you can write whatever you want to do with the user's score
Next
End Sub
'Call example:
Protected Sub Form_Load(sender As Object, e As EventArgs) Handles Me.Load
ReadTestScores("C:\scores.ini")
End Sub
Ini file stucture:
[INIFILETEST] <-- Section
Name=Rodit
^ ^
| |
Key Value
By understanding this, it would be easy to read and write your scores using this method...
Hope this helped...
Rodit

Using Visual Basic to Select a Google Search Result in Internet Explorer

I have VB code that goes to Google, fills in the search bar, and hits the search button. Is there a way to have my program select a particular result after my search? ie. I search for "cheese", I would like for my program to select the 2nd to last result (in this case, it is wwww.chuckecheese.com)
I ended up using Sendkeys to emulate the tab and down arrow keys on the keyboard. You can then navigate to your desired search results using these 2 keys
Or you can bypass using an API and avoid ads or cost using speech recognition to improve your Dictation searches. Programming isn't programming if you aren't thinking outside the box and innovating your own solutions.
Coding comes with creativity and you won't know what that is if you don't try. This site is excellent for this very purpose and many have contributed to innovation in coding.
You will have to add a text file to your project and call it whatever you want, then change the path below in the code to your own path. The text file stays blank. The program will write your spoken search to file and then execute the search, constantly over-writing itself.
For some odd reason, this method greatly improves the fusion of speech recognition and dictation. You can speak an entire phrase and it will conduct the search. A good mic is a must and speaking clearly without background disturbances.
Imports System.Speech.Recognition
'Declarations:
Private ReadOnly Drone As New SpeechRecognitionEngine()
Private ReadOnly Qa As New DictationGrammar()
Private Sub Form1_Load(sender As Object,
e As EventArgs) Handles MyBase.Load
'Dictation Mode | Google Engine
Drone.LoadGrammarAsync(Qa)
Drone.RequestRecognizerUpdate()
Drone.SetInputToDefaultAudioDevice()
Drone.InitialSilenceTimeout = TimeSpan.FromSeconds(2.5)
Drone.BabbleTimeout = TimeSpan.FromSeconds(1.5)
Drone.EndSilenceTimeout = TimeSpan.FromSeconds(1.2)
Drone.EndSilenceTimeoutAmbiguous = TimeSpan.FromSeconds(1.5)
AddHandler Drone.SpeechRecognized, AddressOf Drone_SpeechRecognized
Drone.RecognizeAsync(RecognizeMode.Multiple)
End Sub
Private Sub Drone_SpeechRecognized(sender As Object, e As SpeechRecognizedEventArgs)
Dim google As String = e.Result.Text.ToString
Select Case (google)
Case google
If google <> "+" Then
'This section will take spoken word, write to file then execute search.
Dim sb As New StringBuilder
'Be sure to change the text file path below to your path if you are new to this program.
sb.AppendLine(google)
'Add your own path below here. you can also change google to youtube and conduct youtube searches
File.WriteAllText("C:\Users\justin.ross\source\repos\ScarlettCenturium\Scarlett Centurium\Scarlett Centurium\File.txt", sb.ToString())
google = "https://www.google.com/search?q=" & Uri.EscapeUriString(google)
Dim proc As New Process()
Dim startInfo As New ProcessStartInfo(google)
proc.StartInfo = startInfo
proc.Start()
'This sendkey will close out previous tab on new search
SendKeys.Send($"^{{w}}")
Return
End If
End Select
End Sub
well you can use google api for that
goto http://code.google.com/p/google-api-for-dotnet/
download GoogleSearchAPI_0.4_alpha.zip
extract it and add reference to the dll file in your project ( in folder .net 2)
and you can use it like this
first import the library
Imports Google.API.Search
then in a sub or function put your code as
Dim rf As String = "http://www.google.com"
Dim v As New Google.API.Search.GwebSearchClient(rf)
Dim result = v.Search(TextBox1.Text, 40)
' number (40) is the amount of fetched results ( change it if you want )
For Each item In result
If item.Url.Contains("chuckecheese") Then
' your code goes here
End If
Next