How to invoke Add a Digital Signature dialog in Excel VBA - windows

I want to write a simple Excel macro, that invokes Add Digital Signature dialog for the user. I do not want to add the signature itself, just to show the Add Digital Signature dialog so that user doesn't have to look for it him or herself. I was googling for solution and understand that this can not be done in native Excel VBA. One has to call Windows Shell directly. How do I do that?

You don't state your Excel version but assuming you have a version with the ribbon UI. There are a couple of options - you can use the fluent UI control identifier and this code:
Option Explicit
Sub FindControlByFluentUIId()
Dim objCtrl As CommandBarControl
Dim lngId As Long
On Error GoTo ErrHandler
' magic number of Add Digital Signature
lngId = 13035
' find that control in the command bars collection
' this line throws an error for some workbooks !?
Set obj = Application.CommandBars.FindControl(Office.MsoControlType.msoControlButton, lngId)
' execute
If Not obj Is Nothing Then
obj.Execute
Else
MsgBox "Not found"
End If
End Sub
ErrHandler:
If Err.Number <> 0 Then
Debug.Print Err.Description
End If
End Sub
The full list of codes is here: https://www.microsoft.com/en-us/download/details.aspx?id=36798
If you didn't know the ID for some reason you can manually search each control collection of each command bar for a control with Caption this is like the one you are looking for. You are better off doing a wildcard search with the Like operator because you may not know the exact case of the control caption and position of the &s that facilitate keyboard short-cuts.
You can try something like this:
Option Explicit
Sub TestFindControl()
Dim strCaptionWild As String
Dim objCtrl As CommandBarControl
' use wildcards to help find the control
strCaptionWild = "*add*a*digital*signature*"
' call the function to find by caption
Set objCtrl = FindControl(strCaptionWild)
' execute on match
If Not objCtrl Is Nothing Then
Debug.Print "Command bar index: " & objCtrl.Parent.Index
Debug.Print "Control index: " & objCtrl.Index
Debug.Print "Real caption: " & objCtrl.Caption
objCtrl.Execute
Else
MsgBox "Not found for caption: " & strCaptionWild
End If
End Sub
Function FindControl(ByVal strCaption As String) As CommandBarControl
Dim objCb As CommandBar
Dim objCtrl As CommandBarControl
Dim blnFound As Boolean
On Error GoTo ErrHandler
' not found the control
blnFound = False
' iterate command bars and their controls
For Each objCb In Application.CommandBars
For Each objCtrl In objCb.Controls
' use like operator check control caption vs input caption
' LIKE enables use of wildcard matching
If LCase$(objCtrl.Caption) Like LCase$(strCaption) Then
' found it
blnFound = True
Exit For
End If
Next objCtrl
If blnFound Then Exit For
Next objCb
Set FindControl = objCtrl
Exit Function
ErrHandler:
Debug.Print Err.Description
Set FindControl = Nothing
End Function

Related

Quit error Internet Explorer Window

Issue : I am currently encountering some issues closing a "premature" internet window which has no content yet.
Basically if this "premature" window is open, my macro doesn't manage to select the window I'm interested in, but as soon as I close this "premature" window manually, I can run my code properly.
Its source comes from a minor error which somehow opens it but except diplaying that window doesn't affect the rest of the code.
Tests done :
Dim Widow As Object, page_foireuse As SHDocVw.InternetExplorer
Dim objShell As Object
Set objShell = CreateObject("Shell.Application")
MsgBox objShell.Windows.Count
' MsgBox objShell.Windows(0).document.Title
' MsgBox objShell.Windows(1).document.Title
' MsgBox objShell.Windows(2).document.Title
' MsgBox objShell.Windows(3).document.Title
' MsgBox objShell.Windows(4).document.Title
' MsgBox objShell.Windows(5).document.Title
' MsgBox objShell.Windows(6).document.Title
'For Each Widow In objShell.Windows
' If Widow.document.Title Is Nothing Then ' this doesn't work
' Set page_foireuse = Widow
' End If
'Next
'
'If objShell.Windows(5).document.Title Is Nothing Then
'End If
Set page_foireuse = objShell.Windows(5)
page_foireuse.Quit
MsgBox objShell.Windows.Count
Results so far :
When I count the number of windows in the shell, this "premature" window is also counted
When I return the location or title of each of the counted windows, I get an error when trying to return the location or title of the "premature" window
The two loops I tried to run at this end didn't work
So my question is : How can I close this "premature" window via the macro ?
The page on the image in your question looks strange, no location, no title. Try the following code, but set breakpoint on the line Set doc = ie.document and check if doc is not Nothing etc. HTH
' Add reference to Microsoft Internet Controls (SHDocVw)
' Add reference to Microsoft HTML Object Library
' Add reference to Microsoft Shell Controls And Automation
Dim ie As SHDocVw.WebBrowser
Dim doc As HTMLDocument
Dim shellApp As Shell32.Shell
Dim windows As SHDocVw.ShellWindows
Dim window
Set shellApp = New Shell
Set windows = shellApp.windows
For Each window In windows
If Not UCase(window.FullName) Like "*IEXPLORE.EXE" Then GoTo continue
Set ie = window
Set doc = ie.document
If doc.Title = "" Then
ie.Quit
Exit For
End If
continue:
Next window

MS Access 2016 File Browse Button Issues

I am using the script listed below (I honestly stole this probably from this very site) for a browse button on a form. The task is simply to start up MS File Dialog box so that a file (in this case an image file) can be selected. Once you select the record and click ok it then pastes the file name and location into a field.
Viewing the table the file name and location is pasted just as it should be. The problem comes in with a report I built. I have an image set to display with the control source linked back to that file address field. It will not display the image though.
However, if I manually type the same address character for character or even “copy”, delete, and then “paste” the same exact entry into the field the image then displays just fine on the report.
I have checked to make sure there are no spaces or characters anywhere there shouldn’t be. I am at a loss here.
Any help would be greatly appreciated and I will gladly give you my first born. Ok maybe not the first I like him but you can have the second one, she’s hell.
Private Sub Command67_Click()
On Error GoTo SubError
'Add "Microsoft Office 14.0 Object Library" in references
Const msoFileDialogFilePicker As Long = 3
'Dim FD As Office.FileDialog
Dim FDialog As Object
Dim varfile As Variant
Set FDialog = Application.FileDialog(msoFileDialogFilePicker)
EmployeePicture = ""
' Set up the File Dialog
Set FDialog = Application.FileDialog(msoFileDialogFilePicker)
With FDialog
.Title = "Choose the spreadsheet you would like to import"
.AllowMultiSelect = False
.InitialFileName = "C:\Users\" 'Folder picker needs trailing slash
.Filters.Clear
.Filters.Add "All", "*.*"
If .Show = True Then
If .SelectedItems.Count = 0 Then
'User clicked open but didn't select a file
GoTo SubExit
End If
'An option for MultiSelect = False
'varFile = .SelectedItems(1)
'EmployeePicture = varFile
'Needed when MultiSelect = True
For Each varfile In .SelectedItems
EmployeePicture = EmployeePicture & varfile & vbCrLf
Next
Else
'user cancelled dialog without choosing!
'Do you need to react?
End If
End With
SubExit:
On Error Resume Next
Set FDialog = Nothing
Exit Sub
SubError:
MsgBox "Error Number: " & Err.Number & " = " & Err.Description, vbCritical + vbOKOnly, _
"An error occurred"
GoTo SubExit
End Sub

Access VBA to Close a Chrome window opened via Shell

I am attempting to close a shell Chrome window via a VBA function. My function runs a URL query that returns a .csv file. The thing is I would like to close the window so that it is not always showing (This process runs every 3 minutes). I haven't been able to find a solution that I can get to work as of yet. I tried adding SendKeys "%{F4}" after as one site suggested. This merely minimizes the window, not close it. I also attempted to try adding DoCmd.Close Shell, "Untitled" after, yet this also did not work. I have spent several hours attempting to do, what I imagine is a simple task, and felt another set of eyes could point me in the right direction. Below is my code that opens Chrome. Any assistance is greatly appreciated.
Public Function RunYahooAPI()
Dim chromePath As String
chromePath = """C:\Program Files\Google\Chrome\Application\chrome.exe"""
Shell (chromePath & " -url http://download.finance.yahoo.com/d/quotes.csv?s=CVX%2CXOM%2CHP%2CSLB%2CPBA%2CATR%2CECL%2CNVZMY%2CMON&f=nsl1op&e=.csv")
End Function
this VBA code will launch (as in your question) chrome, save the Process handle in the variable pHandle, loop all processes with this Handle and then stop the process (after checking user and domain of the process owner) .
Sub LaunchandStopProcess()
'
' As in your Question
'
Dim chromePath As String
Dim pHandle As Variant
chromePath = "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
'
' Note: Shell pass the Process Handle to the PID variable
'
PHandle = Shell(chromePath & " -url http://download.finance.yahoo.com/d/quotes.csv?s=CVX%2CXOM%2CHP%2CSLB%2CPBA%2CATR%2CECL%2CNVZMY%2CMON&f=nsl1op&e=.csv")
Dim objWMIcimv2 As Object
Dim objProcess As Object
Dim objList As Object
Dim ProcToTerminate As String
Dim intError As Integer
Set objWMIcimv2 = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\.\root\cimv2")
Set objList = objWMIcimv2.ExecQuery("select * from win32_process where Handle='" & CStr(pHandle) & "'")
'
' ObjList contains the list of all process matching the Handle (normally your chrome App, if running)
'
If objList.Count = 0 Then
' No matching Process
' Set all objects to nothing
Set objWMIcimv2 = Nothing
Set objList = Nothing
Set objProcess = Nothing
Exit Sub
Else
'
' Parse all matching Processes
'
For Each objProcess In objList
' additionally check with actual user
colProperties = objProcess.getowner(strNameofUser, strUserdomain)
If strUserdomain + "\" + strNameofUser = Environ$("userdomain") + "\" + Environ$("username") Then
intError = objProcess.Terminate
If intError <> 0 Then
'
' Trap Error or do nothing if code run unattended
'
Else
' Confirm that process is killed or nothing if code run unattended
End If
End If
Next
Set objWMIcimv2 = Nothing
Set objList = Nothing
Set objProcess = Nothing
End If
End Sub

Does anyone remember what the statement/command "WaitOn" meant in VB3?

In the Form_Load event of this ultralegacy app I need to transliterate over to a web app is this command/statement "WaitOn" that occurs right after the On Error GoTo...
Does anyone remember what WaitOn means?
Here's the code snippet:
Dim sCmd As String
Dim iFileHandle As Integer
Dim sFileName As String
Dim i As Integer
Dim sKeyWord As String
Dim sWindowPosition As String
Dim iWindowState As Integer
Dim sSystemId As String
Dim sMetrics() As String
On Error GoTo MainFormLoadErr
WaitOn
ReDim gsFundsUsed(0 To 0)
ReDim gsObjectsUsed(0 To 0)
Set gsActiveSpread = Nothing
.
.
.
MainFormLoadExit:
WaitOff
Close
Exit Sub
MainFormLoadErr:
MsgBox Error$(Err) & " in MainForm Load"
Resume MainFormLoadExit
There is a corresponding WaitOff down there I just found. I don't think WaitOn is part of a line label.
As #C-Pound Guru suggested, WaitOn and WaitOff were methods in one of the (many) modules of the program. Not clear from the the names of the subroutines was the fact that their task was to set the mouse pointer to the Wait Cursor, and then return to the default, later.
Sub WaitOn ()
On Error Resume Next
Screen.MousePointer = 11
End Sub
Sub WaitOff ()
On Error Resume Next
Screen.MousePointer = 0
End Sub
I've never come across a 'WaitOn' or 'WaitOff' command in VB. You might want to double-check the code to see if there's a WaitOn method written (and a WaitOff method as well). It's not a label as VB labels end with a colon (:).
What happens if you right-click and Go To Definition? And does the code currently run?
Check the references - maybe it's something from a non-standard dll.

Use clipboard from VBScript

I am looking for a method to place some text onto the clipboard with VBScript. The VBScript in question will be deployed as part of our login script. I would like to avoid using anything that isn't available on a clean Windows XP system.
Edit:
In answer to the questions about what this is for.
We wanted to encourage users inside our organization to use the file server to transfer documents instead of constantly sending attachments by email. One of the biggest barriers to this is that it isn't always obvious to people what the correct network path is to a file/folder. We developed a quick script, and attached it to the Windows context menu so that a user can right click on any file/folder, and get a URL that they can email to someone within our organization.
I want the URL displayed in the dialog box to also be placed onto the clipboard.
GetNetworkPath
Another solution I have found that isn't perfect in my opinion, but doesn't have the annoying security warnings is to use clip.exe from a w2k3 server.
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run "cmd.exe /c echo hello world | clip", 0, TRUE
Example with a multiline string as per question below :
Link1
Dim string
String = "text here" &chr(13)& "more text here"
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run "cmd.exe /c echo " & String & " | clip", 0, TRUE
Using Microsoft's clip.exe is the closest to having a clean Windows XP system solution. However you don't have to call CMD.EXE to host it in order to use it. You can call it directly and write to its input stream in your script code. Once you close the input stream clip.exe will write the contents straight to the clipboard.
Set WshShell = CreateObject("WScript.Shell")
Set oExec = WshShell.Exec("clip")
Set oIn = oExec.stdIn
oIn.WriteLine "Something One"
oIn.WriteLine "Something Two"
oIn.WriteLine "Something Three"
oIn.Close
If you need to wait for clip to be finished before your script can continue processing then add
' loop until we're finished working.
Do While oExec.Status = 0
WScript.Sleep 100
Loop
And don't forget to release your objects
Set oIn = Nothing
Set oExec = Nothing
The closest solution I have found so far is a method to use IE to get and set stuff on the clipboard. The problem with this solution is the user gets security warnings. I am tempted to move 'about:blank' to the local computer security zone so I don't get the warnings, but I am not sure what the security implications of that would be.
Set objIE = CreateObject("InternetExplorer.Application")
objIE.Navigate("about:blank")
objIE.document.parentwindow.clipboardData.SetData "text", "Hello This Is A Test"
objIE.Quit
http://www.microsoft.com/technet/scriptcenter/resources/qanda/dec04/hey1215.mspx
No security warnings, full let and get access:
'create a clipboard thing
Dim ClipBoard
Set Clipboard = New cClipBoard
ClipBoard.Clear
ClipBoard.Data = "Test"
Class cClipBoard
Private objHTML
Private Sub Class_Initialize
Set objHTML = CreateObject("htmlfile")
End Sub
Public Sub Clear()
objHTML.ParentWindow.ClipboardData.ClearData()
End Sub
Public Property Let Data(Value)
objHTML.ParentWindow.ClipboardData.SetData "Text" , Value
End Property
Public Property Get Data()
Data = objHTML.ParentWindow.ClipboardData.GetData("Text")
End Property
Private Sub Class_Terminate
Set objHTML = Nothing
End Sub
End Class
Example Usage.
' Create scripting object
Dim WShell, lRunUninstall
Set WShell = CreateObject("WScript.Shell")
WShell.sendkeys "^c"
WScript.Sleep 250
bWindowFound = WShell.AppActivate("Microsoft Excel")
WShell.sendkeys ClipBoard.Data
To avoid the security warnings associated with Internet Explorer and clipboard access, I would recommend you use the Word application object and its methods to put your data onto the clipboard. Of course you can only use this on a machine that has MS Word installed, but these days that's most of them. (*In spite of the fact that you asked for stuff on a 'clean' system :) *)
' Set what you want to put in the clipboard '
strMessage = "Imagine that, it works!"
' Declare an object for the word application '
Set objWord = CreateObject("Word.Application")
' Using the object '
With objWord
.Visible = False ' Don't show word '
.Documents.Add ' Create a document '
.Selection.TypeText strMessage ' Put text into it '
.Selection.WholeStory ' Select everything in the doc '
.Selection.Copy ' Copy contents to clipboard '
.Quit False ' Close Word, don't save '
End With
You can find detail on the MS Word application object and its methods here: http://msdn.microsoft.com/en-us/library/aa221371(office.11).aspx
Microsoft doesn't give a way for VBScript to directly access the clipboard. If you do a search for 'clipboard'on this site you'll see:
Although Visual Basic for Applications supports the Screen, Printer, App, Debug, Err, and Clipboard objects, VBScript supports only the Err object. Therefore, VBScript does not allow you to access such useful objects as the mouse pointer or the clipboard. You can, however, use the Err object to provide runtime error handling for your applications.
So using notepad indirectly is probably about the best you'll be able to do with just VBScript.
Here's another version of using the "clip" command, which avoids adding a carriage return, line feed to the end of the string:
strA= "some character string"
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "cmd /C echo . | set /p x=" & strA & "| c:\clip.exe", 2
s = "String: """ & strA & """ is on the clipboard."
Wscript.Echo s
I've only tested this in XP. clip.exe was downloaded from Link and placed in C:\.
I've found a way to copy multi line information to clipboard by vbscript/cmd.
Sequence:
with VBS generate the final "formatted string" that you need copy to clipboard
generate a (txt) file with the "formatted string"
use type command from cmd to paste information to clip by pipe
Example script:
Function CopyToClipboard( sInputString )
Dim oShell: Set oShell = CreateObject("WScript.Shell")
Dim sTempFolder: sTempFolder = oShell.ExpandEnvironmentStrings("%TEMP%")
Dim sFullFilePath: sFullFilePath = sTempFolder & "\" & "temp_file.txt"
Const iForWriting = 2, bCreateFile = True
Dim oFSO: Set oFSO = CreateObject("Scripting.FileSystemObject")
With oFSO.OpenTextFile(sFullFilePath, iForWriting, bCreateFile)
.Write sInputString
.Close
End With
Const iHideWindow = 0, bWaitOnReturnTrue = True
Dim sCommand: sCommand = "CMD /C TYPE " & sFullFilePath & "|CLIP"
oShell.Run sCommand, iHideWindow, bWaitOnReturnTrue
Set oShell = Nothing
Set oFSO = Nothing
End Function
Sub Main
Call CopyToClipboard( "Text1" & vbNewLine & "Text2" )
End Sub
Call Main
The easiest way is to use built-in mshta.exe functionality:
sText = "Text Content"
CreateObject("WScript.Shell").Run "mshta.exe ""javascript:clipboardData.setData('text','" & Replace(Replace(sText, "\", "\\"), "'", "\'") & "');close();""", 0, True
To put to clipboard a string containing double quote char ", use the below code:
sText = "Text Content and double quote "" char"
CreateObject("WScript.Shell").Run "mshta.exe ""javascript:clipboardData.setData('text','" & Replace(Replace(Replace(sText, "\", "\\"), """", """"""), "'", "\'") & "'.replace('""""',String.fromCharCode(34)));close();""", 0, True
Take a look at this post. It describes a hacky approach to read from the clipboard, but I imagine it could be adapted to also write to the clipboard as well, such as changing the Ctrl+V to Ctrl+A then Ctrl+C.
I devised another way to use IE and yet avoid security warnings...
By the way.. this function is in JavaScript.. but u can easily convert it to VBScript..
function CopyText(sTxt) {
var oIe = WScript.CreateObject('InternetExplorer.Application');
oIe.silent = true;
oIe.Navigate('about:blank');
while(oIe.ReadyState!=4) WScript.Sleep(20);
while(oIe.document.readyState!='complete') WSript.Sleep(20);
oIe.document.body.innerHTML = "<textarea id=txtArea wrap=off></textarea>";
var oTb = oIe.document.getElementById('txtArea');
oTb.value = sTxt;
oTb.select();
oTb = null;
oIe.ExecWB(12,0);
oIe.Quit();
oIe = null;
}
Here is Srikanth's method translated into vbs
function SetClipBoard(sTxt)
Set oIe = WScript.CreateObject("InternetExplorer.Application")
oIe.silent = true
oIe.Navigate("about:blank")
do while oIe.ReadyState <> 4
WScript.Sleep 20
loop
do while oIe.document.readyState <> "complete"
WScript.Sleep 20
loop
oIe.document.body.innerHTML = "<textarea id=txtArea wrap=off></textarea>"
set oTb = oIe.document.getElementById("txtArea")
oTb.value = sTxt
oTb.select
set oTb = nothing
oIe.ExecWB 12,0
oIe.Quit
Set oIe = nothing
End function
function GetClipBoard()
set oIe = WScript.CreateObject("InternetExplorer.Application")
oIe.silent = true
oIe.Navigate("about:blank")
do while oIe.ReadyState <> 4
WScript.Sleep 20
loop
do while oIe.document.readyState <> "complete"
WScript.Sleep 20
loop
oIe.document.body.innerHTML = "<textarea id=txtArea wrap=off></textarea>"
set oTb = oIe.document.getElementById("txtArea")
oTb.focus
oIe.ExecWB 13,0
GetClipBoard = oTb.value
oTb.select
set oTb = nothing
oIe.Quit
Set oIe = nothing
End function
In your Class ClipBoard, neither the Clear sub nor the Let Data sub work. I mean they have no effect on Windows Clipboard. Actually, and ironically so, the only sub that works is the one you have not included in your example, that is Get Data! (I have tested this code quite a few times.)
However, it's not your fault. I have tried to copy data to clipboard with ClipboardData.SetData and it's impossible. At least not by creating an "htmlfile" object. Maybe it works by creating an instance of "InternetExplorer.Application" as I have seen in a few cases, but I have not tried it. I hate creating application instances for such simple tasks!
Alkis
If it's just text can't you simply create a text file and read in the contents when you need it?
Another alternative and clearly a kludge, would be to use the SendKeys() method.
No security warnings and no carriage return at the end of line
' value to put in Clipboard
mavaleur = "YEAH"
' current Dir
path = WScript.ScriptFullName
GetPath = Left(path, InStrRev(path, "\"))
' Put the value in a file
Set objFSO=CreateObject("Scripting.FileSystemObject")
outFile=GetPath & "fichier.valeur"
Set objFile = objFSO.CreateTextFile(outFile,True)
objFile.Write mavaleur
objFile.Close
' Put the file in the Clipboard
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run "cmd.exe /c clip < " & outFile, 0, TRUE
' Erase the file
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.DeleteFile outFile

Resources