How to add handwritten signature using Excel's Ink Tools? - vba

I want to add a handwritten digital signature to some of my company's forms.
The goal is to, select a document, add a signature (through the use of a drawing pad, which can be done with Excel's Ink Tools) and store the file in the server as PDF. This would cut out the necessity of printing and then scanning the form back in to obtain a signature.
I'm using Excel for the main interface for file manipulation and search. I've not found any references/libraries for the use of Excel - Ink Tools through VBA.
How do I start Ink Tools Objects in VBA? Would I have to use a different software to get the signature?

Update:
After #Macro Man pointed me in the right direction I found some material that helped get the eSignature up and running.
I've found some material on MSDN Digital Ink Signatures - Concepts and Technologies and InkPicture Class that talk about the Ink collection on VB.net and C# through a PictureBox/Userform , this coupled with the InkEdit Control in another Stackoverflow response in which I realised that VBAs tool box had a InkPicture Control additional control that could be utilized to collect the handwritten eSignature through User form.
Please find below step by step:
In VBAs toolbox on additional control under Tools > Additional Controls there is the InkPicture Control which allows you to create a signature Userform.
Once Added InkPicture can be used as any other control on the toolbox.
Then its a case of initialising the UserForm for the Signature request. I'm using a drawing pad, but other hardware should work as well.
And storing or utilising the resultant image at need, in my case saving a temp version in the server to then resize and add to a Word document.
Edit:
After answering a similar question in here, on how to use Userform InkPicture to input image signature into a worksheet/specific cell, I thought I'd edit this answer for those interested.
The below code will allow you to, open the userform so the user can sign the ink field, save the image temperately, add the InkPicture to your worksheet and kill the temp image.
Set up your UserForm (mine is set up like this, with a couple extra options) the UserForm is named Signature_pad, the essential option you need is Private Sub Use_Click().
This is the code inside the Userform:
Private Sub Use_Click()
'dim object type and byte array to save from binary
Dim objInk As MSINKAUTLib.InkPicture
Dim bytArr() As Byte
Dim File1 As String
'get temp file path as $user\Temp\[file name]
FilePath = Environ$("temp") & "\" & "Signature.png"
' set objInk as image/strokes of InkPicture control form object
Set objInk = Me.SignPicture
'if object is not empty
If objInk.Ink.Strokes.Count > 0 Then
'get bytes from object save
bytArr = objInk.Ink.Save(2)
'create file for output
Open FilePath For Binary As #1
'output/write bytArr into #1/created (empty)file
Put #1, , bytArr
Close #1
End If
'set public File as file path to be used later on main sub
Signature.File = FilePath
Unload Me
End Sub
Private Sub Cancel_Click()
End
End Sub
Private Sub ClearPad_Click()
'delete strokes/lines of signature
Me.SignPicture.Ink.DeleteStrokes
'refresh form
Me.Repaint
End Sub
Below is the Main sub (Module called Signature) to call the userform and handle the signature, you can call this Sub with a button or form another Sub.
'public temp file path
Public File
Sub collect_signature()
'Dim and call userform
Dim myUserForm As Signature_pad
Set myUserForm = New Signature_pad
myUserForm.Show
Set myUserForm = Nothing
'insert image/signature from temp file into application active sheet
Set SignatureImage = Application.ActiveSheet.Shapes.AddPicture(File, False, True, 1, 1, 1, 1)
'scale image/signature
SignatureImage.ScaleHeight 1, True
SignatureImage.ScaleWidth 1, True
'image/signature position
SignatureImage.Top = Range("A1").Top
SignatureImage.Left = Range("A1").Left
'delete temp file
Kill File
End Sub
Be sure to rename either the Userform Name and Buttons Name Or the code to match the names of you buttons.

Is it the InkEdit Control you're after?
This is one of the standard libraries that you can find in Tools->References

Related

CommandBars("Text").Controls not deleted when exiting the document - VBA word add-in

I'm trying to create a add in for MS Word with VBA.
It has a "AutoExec" procedure that creates a new item in the CommandBar("Text") collection (right click menu) and a "AutoExit" that deletes this created item.
As an example, I tried the code below that create an item "How Many Pages?", which executes a macro displaying the number of pages in the active document.
This is the AutoExec Code:
Public Sub AutoExec()
Dim objcommandbutton As CommandBarButton
Call MsgBox("AutoExec")
Set objcommandbutton = Application.CommandBars("Text").Controls.Add _
(Type:=msoControlButton, Before:=1)
objcommandbutton.Caption = "How Many Pages?"
objcommandbutton.OnAction = "HowManyPages"
End Sub
This is the AutoExit Code:
Public Sub AutoExit()
Dim objcommandbutton As CommandBarControl
Call MsgBox("AutoExit")
For Each objcommandbutton In Application.CommandBars("Text").Controls
If objcommandbutton.Caption = "How Many Pages?" Then
objcommandbutton.Delete
End If
Next objcommandbutton
End Sub
This is the Main Macro Code:
Public Sub HowManyPages()
If Documents.Count > 0 Then
Call MsgBox(ActiveDocument.BuiltInDocumentProperties("Number of Pages"))
Else
Call MsgBox("No document is currently active.")
End If
End Sub
When exiting the document, the Button previously added in CommandBars("Text") collection is not deleted. I see this when I open a new blank Word document and the button remains in the right click menu.
I know that the routine is performed correctly because there is a MsgBox instruction to verify it.
This only happen with the AutoExit subroutine of a add-in, that is, loaded as a add-in: running the code in a macro with vba module works fine.
Any help?
When working with the CommandBars object model in Word it's necessary to always specify the Application.CustomizationContext.
Word can save keyboard layouts and CommandBar customizations in various places: the Normal.dotm template, the current template or the current document. The default when you create a CommandBar addition may not be the3 same as the default when trying to delete something.
Since this is an add-in, I assume you want the change for the entire Word environment (any open document). In that case, use the context NormalTemplate. Use this before any calls to CommandBar:
Application.CustomizationContext = NormalTemplate
Note: for saving a customization in the current document: = ActiveDocument; for saving in the template attached to the current document: = ActiveDocument.AttachedTemplate.
I solved my problem with a workaround:
I was trying to "add" a template (.dotm) as a add-in (in the "Templates and Add-ins" window) to use my VBA project in a new document. That's why I was using the AutoExec() and AutoExit() procedures.
But only now I figure out that just "attaching" the .dotm template to the active document (in the same "Templates and Add-ins" window, as show in the figure below) makes the functions Private Sub Document_Open() and Private Sub Document_Close() to run normally. Which solves my problem.
Even so, I think there is a certain "issue" with the AutoExit() procedure when trying to change the CommandBars itens. But that's ok for now.
enter image description here

How to Edit a Read-Only Word Document (VBA)

I am periodically getting Word documents from various clients and sometimes they send them to me in 'Read-Only' mode. While it isn't a big deal to go to 'View > Edit Document' manually, I cannot seem to find how to do this within my VBA code.
Either opening a document as editable or toggling it as editable once it is open would be sufficient for my needs.
Note that I cannot open the document with 'readOnly = false' as it looks like it is set to 'readOnly recommended' (based on my reading of the MS man page on Document.Open).
IN CONTEXT:
I was also hitting a problem with turning off 'read-mode' which the documents were opening as by default. I have posted this question and answer here.
The code below will change the ReadOnly attribute of a closed file, setting its ReadOnly attribute to either True or False depending on the argument supplied to the procedure.
Private Sub SetReadOnlyProperty(Fn As String, _
ByVal ReadOnly As Boolean)
' 21 Nov 2017
Dim Fso As Object
Dim Doc As Object
Set Fso = CreateObject("Scripting.FileSystemObject")
Set Doc = Fso.GetFile(Fn)
If (Doc.Attributes And vbReadOnly) <> Abs(Int(ReadOnly)) Then
Doc.Attributes = Doc.Attributes Xor vbReadOnly
End If
End Sub
This procedure requires access to the MS Scripting Runtime DLL. Enable this access by checking the box against Miscrosoft Scripting Runtime from Tools >References in the VBE window. Below is an example of how to call the function. Note that an error will result if the supplied file doesn't exist.
Private Sub TestReadOnly()
SetReadOnlyProperty "H:\Test Folder\Test File.docx", False
End Sub

Adding shapes/pages to visio on shape drop

Hello I am fairly new to VBA in visio, and I am trying to add functionality to a visio template so that a page will be added to the active document whenever a specific shape is dropped onto a page. I looked through MSDN and found an example using Application.ShapeAdded function but the active document I am working in doesn't seem to be responding to my modified code.
Private Sub Document_ShapeAdded(ByVal vsoShape As Visio.IVShape)
Dim vsoMaster As Visio.Master
'Get the Master property of the shape.
Set vsoMaster = vsoShape.Master
'If Visio shape added is named "SC" add a new page
If vsoMaster.Name = "SC" Then
NewPage
End If
End Sub
I drop the shape master "SC", which I confirmed is the name of the shape master, and nothing happens. The MSDN verbage describes Application.ShapeAdded as an event listener to the open application. Am I missing something or is there possibly a better way to do this I am not thinking of?
Here is the MSDN description: https://msdn.microsoft.com/en-us/library/office/ff766392.aspx
The Document_ShapeAdded event will only apply to the document in which the VBA code is located.
You'd have to declare an application object withevents and have it watch for that event.
Example (in an object or ThisDocument module):
Private WithEvents App as Visio.Application
Private Sub App_ShapeAdded(ByVal Shape As IVShape)
Call ActiveDocument.Pages.Add() ' etc..
End Sub
Alternatively, if it's something simple, you could just add a shapesheet CALLTHIS function on the master shape in question, which just fires a VBA routine to add a new page or whatever you have to do.

Word VBA: Sharing variables between documents

I feel like this should be obvious, I'm just not finding the answer anywhere.
I have a Word document with several Public variables declared and defined in a variety of procedures. One procedure opens another Word document, which has a form that loads on open. For the life of me I cannot get that form in the second document to use values from the original document's variables. Am I misunderstanding the nature of Public variables? Everything I've found seems to indicate that those values should be visible to the newly opened document.
So to open the second document, I'm using the code below (some of it is declared and set elsewhere, but I think this is the relevant stuff:
Public iMarker as boolean
Sub OpenDoc()
If check_ExA.Value = True Then 'a checkbox on a userform
docName = docsPath & "/" & "seconddocumentpath.docm"
iMarker = True
formAddDocs.Hide
Set addDoc = Documents.Open(docName)
End Sub
from there, the new document has a form that shows on Open, and in the initialization, I want it to be able to see if the iMarker variable is true, among some other strings, etc.
Private Sub UserForm_Initialize()
If iMarker = True Then
'do some other stuff
End If
End Sub
I tried changing that Initialize sub to public and that did nothing. It won't see that iMarker is true when the second document opens. Any suggestions?
To make a public variable of doc01 ("source doc") available to doc02 ("target doc") document, go like follows:
open the "source doc"
open the "target doc"
click Tools-> References
from Available References listbox of the References dialog box click the "Project" of the "source doc"
You can recognize it from the path appearing near the dialog box bottom
Otherwise
close Reference dialog box
go to "source doc" and rename its project (Tools->project properties, edit "project name" textbox and click "OK") with a meaningful name (say "MainProject")
go back to "target doc" project
open References dialog box and now from Available References listbox click the "MainProject" reference
Save and close target doc

Close modal form in Access and access module code

I've inherited a Access database that is used to import some data in SQL. The MDB opens with a form, in a modal mode: no Access menubar or buttons are visible. I can view the tables with content by using the Visual Studio 'Data Connection' tool, but I cannot see the module's code.
I've looked at this question here, but the answers there aren't really what I need. Is there a way to either force the form to close (and access the modules) or to extract the VBA code ?
[EDIT] I am using Access 2007, not sure what the original developer used.
Hold down the shift key when you open the database. This will prevent it from loading the automatic script it's running and allow you to gain access to the tables, queries, and VBA scripts.
This is a rather long addendum to, or comment on, Michael Todd's reply in response to edosoft's comment.
Rather than choosing to enable the content, check the start-up options (either (file->options->current database->display form) or (tools->start up->display form)) and remove the name of the form, having taken a note, and ensure that Allow Full Menus (same page) is ticked. You may also like to press Alt+F11 to display code, and check that for start-up code, finally, see if there is an AutoRun macro and rename it.
EDIT re Comments
You do not have to open an mdb to change the start-up form, for example, code such as this could be run from another mdb using the full name and path of the mdb you wish to change.
Sub SetStartForm(DBFile As String)
Dim prp As Object
Dim db As Database
Const PROPERTY_NOT_FOUND As Integer = 3270
Set db = OpenDatabase(DBFile)
db.Properties("StartupForm") = "(none)"
If Err.Number > 0 Then
If Err.Number = PROPERTY_NOT_FOUND Then
'' Create the new property, but this is not relevant in this case
End If
End If
db.Close
Set db = Nothing
Set prp = Nothing
End Sub
Button close with function:
Private sub cmdClose_Click()
CloseForm(YourFormName)
End sub
Public Sub CloseForm(ByVal strFormName As String)
Dim iCounter As Integer
For Each frm In Forms
With frm
If (.Name = strFormName) Then
iCounter = iCounter + 1
End If
End With
Next
If (iCounter > 0) Then
For i = 1 To iCounter
DoCmd.Close acForm, strFormName, acSaveNo
Next
End If
End Sub