Purpose
Check for a numeric xls file on my desktop. If not found bring Thisworkbook to front.
Problem
If there are already opened workbooks, Thisworkbook remains in background. No error is raised.
Cause
Function Get_Highest_Numeric_Name although the function itself is working.
What I tried
Replacing ThisWorkbook.Activate with
AppActivate ((ThisWorkbook.Name) & " - Excel")
I got this error on AppActivate line
Invalid procedure call or argument
Strangely the error is not raised if I run that code from the code window.
Any way using AppActivate (ThisWorkbook.Nameā¦) is not reliable, because it requires this option ( File name extension ) is enabled on Windows system.
Private Sub Workbook_Open()
If Len(Get_Highest_Numeric_Name("D:\Users\Waleed\Desktop\", "*.xls")) = 24 Then 'for Question on Stackoverflow
MsgBox "File not found", vbCritical + vbMsgBoxSetForeground, "File not found"
ThisWorkbook.Activate
Exit Sub
End If
End Sub
Function Get_Highest_Numeric_Name(strFold As String, Optional strext As String = "*.*") As String
Dim arrD, lastName As String, lngNb As Double, El
'Return all files name in an array
arrD = Split(CreateObject("wscript.shell").Exec("cmd /c dir """ & strFold & strext & """ /b").StdOut.ReadAll, vbCrLf)
If UBound(arrD) = -1 Then MsgBox "Nothing could be found in the path you supplied...": Exit Function
arrD(UBound(arrD)) = "####": arrD = Filter(arrD, "####", False) 'Remove the last (empty) element
For Each El In arrD 'iterate between the array elements
If IsNumeric(Split(El, ".")(0)) Then
'Compare the lngNb variable (initially 0) with the numeric value:
If lngNb < CDbl(Split(El, ".")(0)) Then
'addapt lngNb like the bigger number
lngNb = CDbl(Split(El, ".")(0)): lastName = El
End If
End If
Next
Get_Highest_Numeric_Name = strFold & lastName 'Build the necessary path
End Function
I tried hopelessly adding to the code an additional function API into a separate module ,to produce new message box with timeout.
Anyhow, using this API fixed the issue (I do not know why this happened).
Note: If I comment the line of MsgBoxTimeout, the problem error raising again.
Private Sub Workbook_Open()
If Len(Get_Highest_Numeric_Name("D:\Users\Waleed\Desktop\", "*.xls")) = 24 Then
Call MsgBoxTimeout(0, "File not found", "File not found", vbInformation + vbMsgBoxSetForeground, 0, 2000)
Exit Sub
End If
End Sub
'This function exists on a separate module
Public Declare Function MsgBoxTimeout Lib "user32" Alias "MessageBoxTimeoutA" ( _
ByVal hwnd As Long, ByVal lpText As String, ByVal lpCaption As String, _
ByVal wType As VbMsgBoxStyle, ByVal wlange As Long, ByVal dwTimeout As Long) As Long
Related
I have a SAP GUI script running every day in VBA. In the script I am exporting some data from SAP to several different Excel files, and these are saved to a network drive. In the first macro, I export data. In the second I copy the data to the same workbook as the script is in.
Some days I get a runtime error
Subscript out of range
on Set ws2 = Workbooks("FEBA_EXPORT_" & today2 & ".XLSX").Worksheets("Sheet1").
It looks like the Excel file is not recognized as open. I manually close the file, and reopen it and then the script will run.
I tried to insert the below code in front of the Set ws2 line that is giving an error, and this code is always giving the massage that the file is open.
Dim Ret
Ret = IsWorkBookOpen(filepath & "FEBA_EXPORT_" & today2 & ".XLSX")
If Ret = True Then
MsgBox "File is open"
Else
MsgBox "File is Closed"
End If
This is the function:
Function IsWorkBookOpen(FileName As String)
Dim ff As Long, ErrNo As Long
On Error Resume Next
ff = FreeFile()
Open FileName For Input Lock Read As #ff
Close ff
ErrNo = Err
On Error GoTo 0
Select Case ErrNo
Case 0: IsWorkBookOpen = False
Case 70: IsWorkBookOpen = True
Case Else: Error ErrNo
End Select
End Function
This is the relevant part of the code:
Sub CopyExportedFEBA_ExtractFEBRE()
Dim SapGuiAuto As Object
Dim SAPApp As Object
Dim SAPCon As Object
Dim session As Object
Set SapGuiAuto = GetObject("SAPGUI")
Set SAPApp = SapGuiAuto.GetScriptingEngine
Set SAPCon = SAPApp.Children(0)
Set session = SAPCon.Children.ElementAt(0) ' <--- Assumes you are using the first session open. '
Dim ws0, ws1, ws2, ws6, ws7 As Worksheet
Set ws0 = Workbooks("FEB_BSPROC.xlsm").Worksheets("INPUT")
Set ws1 = Workbooks("FEB_BSPROC.xlsm").Worksheets("FEB_BSPROC")
Set ws6 = Workbooks("FEB_BSPROC.xlsm").Worksheets("FBL3N_1989")
Dim today2, filepath As String
today2 = ws0.Range("E2")
filepath = ws0.Range("A7")
' Check if if FEBA_EXPORT wb is open
' This is giving the message that the file is open
Dim Ret
Ret = IsWorkBookOpen(filepath & "FEBA_EXPORT_" & today2 & ".XLSX")
If Ret = True Then
MsgBox "File is open"
Else
MsgBox "File is Closed"
End If
' This is giving runtime error 9 Subscript out of range
' If manually close the Excel and the reopen, then it will always work after this
Set ws2 = Workbooks("FEBA_EXPORT_" & today2 & ".XLSX").Worksheets("Sheet1")
'This is never giving any errors
Set ws7 = Workbooks("1989_" & today2 & ".XLSX").Worksheets("Sheet1")
The filepath varaiable is the full filepath to the network drive. So this is not the issue. Also I have another Excel file that is opened in the same way, and that one is never giving any errors.
The today2 variable is also correct.
I thought that it would work if I could close the ws2 workbook with VBA and then reopen it. So I tried to close it without setting it to a variable, but then I got the same error.
With SAP GUI scripting when you export anything to an Excel file, the file will open automatically after it has been saved. I am wondering if this could be the issue? I only have problems with this one Excel file, and not with any of several others that are saved and opened in the same way.
As I said in my above comment, the workbook may be open in a new session, different from the one where the code runs. Please, use the next function to identify if it is a matter of different Excel session:
Function sameExSession(wbFullName As String, Optional boolClose As Boolean) As Boolean
Dim sessEx As Object, wb As Object
Set sessEx = GetObject(wbFullName).Application
If sessEx.hwnd = Application.hwnd Then
sameExSession = True
Else
sameExSession = False
If boolClose Then
sessEx.Workbooks(Right(wbFullName, Len(wbFullName) - InStrRev(wbFullName, "\"))).Close False
sessEx.Quit: Set sessEx = Nothing
End If
End If
End Function
It identify the session where the workbook is open, then compare its handle with the active session one and if not the same, close the workbook (if calling the function with second parameter as True), quit the session and returns False. If only checking, call the function with the second parameter being False (the workbook will not be closed, and session will still remain).
It can be used in the next way:
Sub testSameExSession()
Dim wbFullName As String, wbSAP As Workbook
wbFullName = filepath & "FEBA_EXPORT_" & today2 & ".XLSX"
If sameExSession(wbFullName, True) Then
Debug.Print "The same session"
Set wbSAP = Workbooks("FEBA_EXPORT_" & today2 & ".XLSX")
Else
Debug.Print "Different session..."
Set wbSAP = Workbooks.Open(wbFullName)
End If
Debug.Print wbSAP.Name
'use the set workbook to do what you need...
End Sub
When you have the described problem, please use the above way to test if it is a matter of different sessions.
If so, is easy to input this part in your existing code, I think. If the workbook will be open in a different session, no need to manually close it (and reopen), the above function does it...
In case someone is still facing this issue, I found a way to wait for the excel files downloaded from SAP and its app instance to open, then close them and let you work with the files without troubles. You can set a timeout too.
If files are downloaded and opened in an already open instance of excel, it will just close the files and not the whole instance.
You can use it as follow:
Sub Test()
Call Close_SAP_Excel("Test.xlsx", "Test2.xlsx")
End Sub
xCloseExcelFromSAP
#If VBA7 Then
Private Declare PtrSafe Function AccessibleObjectFromWindow Lib "oleacc" ( _
ByVal hwnd As LongPtr, ByVal dwId As Long, riid As Any, ppvObject As Object) As Long
Private Declare PtrSafe Function FindWindowExA Lib "user32" ( _
ByVal hwndParent As LongPtr, ByVal hwndChildAfter As LongPtr, _
ByVal lpszClass As String, ByVal lpszWindow As String) As LongPtr
#Else
Private Declare Function AccessibleObjectFromWindow Lib "oleacc" ( _
ByVal hwnd As Long, ByVal dwId As Long, riid As Any, ppvObject As Object) As Long
Private Declare Function FindWindowExA Lib "user32" ( _
ByVal hwndParent As Long, ByVal hwndChildAfter As Long, _
ByVal lpszClass As String, ByVal lpszWindow As String) As Long
#End If
Sub Close_SAP_Excel(ParamArray FileNames())
'Procedure to close files downloaded from SAP and at the same time close the Excel application instance that will be open with them.
Dim ExcelAppSAP As Variant
Dim ExcelFile As Variant
Dim FinishedLoop As Boolean, TimeoutReached As Boolean, FileClosed As Boolean
Dim ReTry As Long
Dim i As Long, x As Long
Set ExcelAppSAP = Nothing
ReTry = 100000 'Used as Timeout 100000 = ~10 seconds
i = 1
'The following loop is executed until excel file is closed.
'Inside of this, there is a For Loop for each Excel Instance and inside of that is another loop
'for each excel inside the instance. If name matches, it is closed.
Do While Not FinishedLoop
If i > ReTry Then
TimeoutReached = True
Exit Do
End If
For Each ExcelFile In GetExcelInstances() 'Function to Get Excel Open Instances
For Each xls In ExcelFile.Workbooks
For x = LBound(FileNames()) To UBound(FileNames())
If xls.Name = FileNames(x) Then
Set ExcelAppSAP = ExcelFile 'Set Instance opened by SAP to variable
'Here add actions if needed. Reference to workbook as xls e.g.: xls.Sheets(1).Range("A1").Copy
xls.Close SaveChanges:=False
FileClosed = True
End If
Next x
Next
Next
If FileClosed Then
FinishedLoop = True
End If
i = i + 1
Loop
ThisWorkbook.Activate
If Not TimeoutReached Then
If FileClosed Then
On Error Resume Next
If ExcelAppSAP.Workbooks.Count = 0 Then
ExcelAppSAP.Quit
End If
Else
MsgBox "Excel application instance from SAP was not closed correctly. Please close it manually or try again.", , "Error"
End If
Else
MsgBox "Max timeout reached", , "Error"
End If
End Sub
Public Function GetExcelInstances() As Collection
Dim guid&(0 To 3), acc As Object, hwnd, hwnd2, hwnd3
guid(0) = &H20400
guid(1) = &H0
guid(2) = &HC0
guid(3) = &H46000000
Set GetExcelInstances = New Collection
Do
hwnd = FindWindowExA(0, hwnd, "XLMAIN", vbNullString)
If hwnd = 0 Then Exit Do
hwnd2 = FindWindowExA(hwnd, 0, "XLDESK", vbNullString)
hwnd3 = FindWindowExA(hwnd2, 0, "EXCEL7", vbNullString)
If AccessibleObjectFromWindow(hwnd3, &HFFFFFFF0, guid(0), acc) = 0 Then
GetExcelInstances.Add acc.Application
End If
Loop
End Function
The code below Works with Excel 2016
When the user clicks a cell in column A (after the first few header rows are checked)
The value of the contents of the cell is stored in the string variable stockcode.
The Sub Spark() is where the problem lies, in particular Call Shell(stAppName, 0)
stAppName = "C:\Autoit\Spark_test_10_Excel.a3x " & stockcode
Debug.Print stAppName
Call Shell(stAppName, 0)
The application being called displays a chart.
In the debug window you can see the call string C:\Autoit\Spark_test_10_Excel.a3x BHP
If I copy and paste that output into the windows 10 search window the string opens the app and displays a chart perfectly. I also compiled the Autoit script to an EXE That performed exactly as described above. No difference.
Also not the Notepad test commented out. That also worked perfectly.
I guess this is problem is security related. I have tried numerous workarounds none worked so far.
Any suggestions will be gratefully received
Option Explicit
Public stAppName As String
Public stockcode As String
Private Type POINTAPI
x As Long
y As Long
End Type
Private Type MSG
hwnd As Long
Message As Long
wParam As Long
lParam As Long
time As Long
pt As POINTAPI
End Type
Private Declare Function PeekMessage Lib "user32" _
Alias "PeekMessageA" _
(ByRef lpMsg As MSG, ByVal hwnd As Long, _
ByVal wMsgFilterMin As Long, _
ByVal wMsgFilterMax As Long, _
ByVal wRemoveMsg As Long) As Long
Private Const PM_NOREMOVE = &H0
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim Message As MSG
'check for left-mouse button clicks.
PeekMessage Message, 0, 0, 0, PM_NOREMOVE
If Message.Message = 512 Then
Debug.Print "You clicked cell: " & Selection.Address, Selection.Value
End If
On Error GoTo FoundAnError 'the user probably clicked somewhare not in column A in the sheet
stockcode = Selection.Value
Call Spark
FoundAnError:
MsgBox ("there was a VBA code error it should have been addressed")
End Sub
Sub Spark()
Debug.Print "Spark: " & Selection.Address, Selection.Value
If ActiveCell.Column = 1 Then
If stockcode = "Ticker Symbol" Then
Debug.Print "Ticker", stockcode
Exit Sub
End If
If Selection.Value = "" Then
Debug.Print "No stock code ", stockcode
Exit Sub
End If
Debug.Print "stock code in call ", stockcode
'Shell "Notepad", vbNormalFocus 'Yes this works as a test
'On Error GoTo 0
stAppName = "C:\Autoit\Spark_test_10_Excel.a3x " & stockcode
Debug.Print stAppName
'EDIT
'Call Shell(stAppName, 0)This does not work!
Shell "cmd.exe /C " & stAppName, vbHide 'Works
'This Works Thanks FaneDuru
End If
End Sub
This is the output from the debug window running the above code
You clicked cell: $A$7 BHP
Spark: $A$7 BHP
stock code in call BHP
C:\Autoit\Spark_test_10_Excel.a3x BHP
I'm attempting to open a dot .eml file stored locally and access the attachments file name with a excel macro.
I've gathered some code that does the job but not really. Opening the .eml file works (Set Myinspect = OL.ActiveInspector), but on the next line (Set MyItem = Myinspect.CurrentItem) I get the error "Run-time error '91' - Object variable or With block variable not set".
However if I re-run the code from the beginning after the first attempt (with the email now open from the last run), I get the name of the attachment without errors, and here naturally the first instance of the email closes and a second instance is opened. If I remove the line "MyItem.Close 1" I will have two instances of the email after the second run.
I suspected this might be due to that the email did not have time to open and load before the code tried to retrieve the name of the attachment, hence I tried to put a MsgBox before setting "Myitem" and wait until the email had loaded but that did not do the trick..
Appreciate any help that can be provided on this. The end use of the code is to loop through a list of .eml files to search for a .eml file with a attachment with a pre-determined name and then return the name of the .eml file, so since it loops a faster solution then "wait 5 seconds" for example would be optimal.
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As
Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal
lpDirectory As String, ByVal nShowCmd As Long) As Long
Private Const SW_SHOWNORMAL As Long = 1
Private Const SW_SHOWMAXIMIZED As Long = 3
Private Const SW_SHOWMINIMIZED As Long = 2
Sub test11()
strMyFile = "C:\test1.eml"
Dim Myinspect As Outlook.Inspector
Dim MyItem As Outlook.MailItem
Dim OL As Object
If Dir(strMyFile) = "" Then
MsgBox "File " & strMyFile & " does not exist"
Else
ShellExecute 0, "Open", strMyFile, "", "C:\test1.eml", SW_SHOWNORMAL
End If
Set OL = CreateObject("Outlook.Application")
Set Myinspect = OL.ActiveInspector
Set MyItem = Myinspect.CurrentItem
MsgBox "Attachment = " & MyItem.Attachments(1)
MyItem.Close 1
End Sub
Please, try replacing of:
ShellExecute 0, "Open", strMyFile, "", "C:\test1.eml", SW_SHOWNORMAL
with
Const waitOnReturn as boolean = True
VBA.CreateObject("WScript.Shell").Run """" & strMyFile & """", 1, waitOnReturn
This version will wait for the application to open the file. At least, theoretically...:) And no need of any API.
Please, send some feedback after testing it.
You are getting that error because you need to give enough time for the reading pane to become visible. Is this what you are trying?
Option Explicit
Private Declare PtrSafe Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" ( _
ByVal hwnd As LongPtr, ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As LongPtr
Private Const SW_SHOWNORMAL As Long = 1
Private Const strMyFile As String = "C:\test1.eml"
Dim Retry As Long
Sub Sample()
Dim Myinspect As Outlook.Inspector
Dim MyItem As Outlook.MailItem
Dim OL As Object
If Dir(strMyFile) = "" Then
MsgBox "File " & strMyFile & " does not exist"
Exit Sub
Else
ShellExecute 0, "Open", strMyFile, "", strMyFile, SW_SHOWNORMAL
End If
Set OL = CreateObject("Outlook.Application")
Set Myinspect = OL.ActiveInspector
'~~> Wait till the reading pane is visible
Do While TypeName(Myinspect) = "Nothing"
'~~> Wait for 1 sec
Wait 1
Set Myinspect = OL.ActiveInspector
'~~> After 10 retries, stop retrying
If Retry > 10 Then Exit Do
Loop
If TypeName(Myinspect) = "Nothing" Then
MsgBox "Unable to get the Outlook Inspector"
Exit Sub
End If
Set MyItem = Myinspect.CurrentItem
MsgBox "Attachment = " & MyItem.Attachments(1)
MyItem.Close 1
End Sub
Private Sub Wait(ByVal nSec As Long)
nSec = nSec + Timer
While nSec > Timer: DoEvents: Wend
Retry = Retry + 1
End Sub
Note: Instead of Do While TypeName(Myinspect) = "Nothing", you can also use Do While Myinspect Is Nothing
'~~> Wait till the reading pane is visible
Do While Myinspect Is Nothing
'~~> Wait for 1 sec
Wait 1
Set Myinspect = OL.ActiveInspector
'~~> After 10 retries, stop retrying
If Retry > 10 Then Exit Do
Loop
If Myinspect Is Nothing Then
MsgBox "Unable to get the Outlook Inspector"
Exit Sub
End If
Opening and showing an EML file to an end-user when all you want is the attachment name may or may not be what the user expects.
I am not aware of any libraries that would let you open EML files directly from VBA, but if using Redemption (I am its author) is an option, you can create a temporary MSG file and import the EML file. You can then access the message without showing it to the user. Something along the lines
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = OutlookApplication.Session.MAPIOBJECT
set Msg = Session.CreateMessageFromMsgFile("c:\temp\test.msg")
Msg.Import "c:\temp\test.eml", 1031
Msg.Save
for each attach in Msg.Attachments
MsgBox attach.FileName
next
I am developing an Excel add-in with a CHM help file. The CHM has topics that I am trying to reach from Excel's "Insert Function" dialog. This is confirmed when I invoke HH.EXE as follows:
HH.EXE -mapid 1234 "mk:#MSITSTORE:<path-to-my-chm-file>"
I registered all of my UDFs with the Application.MacroOptions( ) function, passing the appropriate parameters (Macro, Category, HelpContextID and HelpFile).
When I click the "Help on this function" link, HH.EXE is invoked with the correct path and file name of my CHM. However, there is no -mapid parameter used for the invocation of HH.EXE. Consequently, when my CHM file is loaded, HH does not go to the desired topic.
Does anyone know or have a guess as to why Excel may be omitting this parameter?
Thank you!
As I understand you want something like shown in the snapshot. Context-sensitive help is complex.
I add sample code for buttons and code for calling the HTMLHelp (CHM) API.
Office 2007 is installed on my machine only.
This is done by a HTMLHelp API call (code snippet (1)):
'******************************************************************************
'----- Modul - definition for HTMLHelp
'----- (c) Ulrich Kulle, http://www.help-info.de/en/Visual_Basic_Applications/vba.htm
'----- 2002-08-26 Version 0.2.xxx
'******************************************************************************
'----- Portions of this code courtesy of David Liske.
Declare Function IsWindow Lib "user32.dll" (ByVal hwnd As Long) As Long
Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As Long
Private Declare Function HtmlHelp Lib "hhctrl.ocx" Alias "HtmlHelpA" _
(ByVal hwndCaller As Long, ByVal pszFile As String, _
ByVal uCommand As Long, ByVal dwData As Long) As Long
Declare Function HTMLHelpTopic Lib "hhctrl.ocx" Alias "HtmlHelpA" _
(ByVal hwndCaller As Long, ByVal pszFile As String, _
ByVal uCommand As Long, ByVal dwData As String) As Long
Private Declare Function HtmlHelpSearch Lib "hhctrl.ocx" Alias "HtmlHelpA" _
(ByVal hwndCaller As Long, ByVal pszFile As String, _
ByVal uCommand As Long, dwData As HH_FTS_QUERY) As Long
'--- to keep the handle of the HH windows when calling help by API --------
Public HHwinHwnd As Long
'--- some constants used by the API ---------------------------------------
Public Const HH_DISPLAY_TOPIC = &H0 ' select last opened tab, [display a specified topic]
Public Const HH_DISPLAY_TOC = &H1 ' select contents tab, [display a specified topic]
Public Const HH_DISPLAY_INDEX = &H2 ' select index tab and searches for a keyword
Public Const HH_DISPLAY_SEARCH = &H3 ' select search tab and perform a search
Public Const HH_HELP_CONTEXT = &HF ' display mapped numeric value in dwData
Public Const HH_CLOSE_ALL = &H12
Public Type HH_FTS_QUERY ' UDT for accessing the Search tab
cbStruct As Long ' Sizeof structure in bytes.
fUniCodeStrings As Long ' TRUE if all strings are unicode.
pszSearchQuery As String ' String containing the search query.
iProximity As Long ' Word proximity.
fStemmedSearch As Long ' TRUE for StemmedSearch only.
fTitleOnly As Long ' TRUE for Title search only.
fExecute As Long ' TRUE to initiate the search.
pszWindow As String ' Window to display in
End Type
Public Function HFile(ByVal i_HFile As Integer) As String
'----- Set the string variable to include the application path of helpfile
Select Case i_HFile
Case 1
HFile = ThisWorkbook.Path & "\CHM-example.chm"
Case 2
'----- Place other Help file paths in successive case statements
HFile = ThisWorkbook.Path & "\CHM-example.chm"
End Select
End Function
Public Sub ShowContents(ByVal intHelpFile As Integer)
HHwinHwnd = HtmlHelp(hwnd, HFile(intHelpFile), HH_DISPLAY_TOC, 0)
End Sub
Public Sub ShowIndex(ByVal intHelpFile As Integer)
HHwinHwnd = HtmlHelp(hwnd, HFile(intHelpFile), HH_DISPLAY_INDEX, 0)
End Sub
Public Sub ShowTopic(ByVal intHelpFile As Integer, strTopic As String)
HHwinHwnd = HTMLHelpTopic(hwnd, HFile(intHelpFile), HH_DISPLAY_TOPIC, strTopic)
End Sub
Public Sub ShowTopicID(ByVal intHelpFile As Integer, IdTopic As Long)
HHwinHwnd = HtmlHelp(hwnd, HFile(intHelpFile), HH_HELP_CONTEXT, IdTopic)
End Sub
Public Sub CloseHelp(ByVal hwnd As Long)
Const WM_CLOSE = &H10
If IsWindow(hwnd) Then
SendMessage hwnd, WM_CLOSE, 0, 0
End If
End Sub
'------------------------------------------------------------------------------
'----- display the search tab
'----- bug: start searching with a string dosn't work
'------------------------------------------------------------------------------
Public Sub ShowSearch(ByVal intHelpFile As Integer)
Dim searchIt As HH_FTS_QUERY
With searchIt
.cbStruct = Len(searchIt)
.fUniCodeStrings = 1&
.pszSearchQuery = "foobar"
.iProximity = 0&
.fStemmedSearch = 0&
.fTitleOnly = 1&
.fExecute = 1&
.pszWindow = ""
End With
Call HtmlHelpSearch(0&, HFile(intHelpFile), HH_DISPLAY_SEARCH, searchIt)
End Sub
And some sample code (2) added:
Sub AddUDFToCategory()
'------------------------------------------------------------------------------
' insert after Description line [optional]: Category:=2, _ => Date & Time
'------------------------------------------------------------------------------
' If the UDF's are in an Addin (.xla) it's better to qualify the function name
' like this:
' Macro:=ThisWorkbook.Name & "!" & "DayName"
'------------------------------------------------------------------------------
' see also Excel help for Application.MacroOptions
'------------------------------------------------------------------------------
application.MacroOptions _
Macro:="TestMacro", _
Description:="This function gives back the 'Hello world' message!", _
Category:=2, _
HelpFile:=ThisWorkbook.Path & "\CHM-example.chm", _
HelpContextID:=10000
application.MacroOptions _
Macro:="DayName", _
Description:="A Function That Gives the Name of the Day", _
Category:=2, _
HelpFile:=ThisWorkbook.Path & "\CHM-example.chm", _
HelpContextID:=20000
End Sub
Function TestMacro()
'----------------------------------------------------------------
' Display a message box with a help button linked to a help topic
'----------------------------------------------------------------
MsgBox "The 'Hello World' message for testing this function!.", _
Buttons:=vbOKOnly + vbMsgBoxHelpButton, _
HelpFile:=ThisWorkbook.Path & "\CHM-example.chm", _
Context:=20010
End Function
Function DayName(InputDate As Date)
'---------------------------------------------
'--- A Function That Gives the Name of the Day
'--- http://www.fontstuff.com/vba/vbatut01.htm
'---------------------------------------------
Dim DayNumber As Integer
DayNumber = Weekday(InputDate, vbSunday)
Select Case DayNumber
Case 1
DayName = "Sunday"
Case 2
DayName = "Monday"
Case 3
DayName = "Tuesday"
Case 4
DayName = "Wednesday"
Case 5
DayName = "Thursday"
Case 6
DayName = "Friday"
Case 7
DayName = "Saturday"
End Select
End Function
For a working example go to Online Help and Visual Basic for Applications
please. Search for VBA - Download and the download link Download Visual Basic for Applications example project (EXCEL).
download the ZIP file from the link above to a temp directory, right click the saved ZIP file first, click Properties and click Unblock
unzip to a temp directory.
as a test open CHM file first by double click
double click CHM_VBA_example.xls
first have a look to security warnings ( Excel) and set to Activate
follow the instructions from the Excel example worksheet.
For further information read Using the VBA Excel Example File too.
So I have been trying to add a level of security to a tool, and I came upon this post. The code works when on the network/domain, but I need to use this somehow for people who are remote and not on the network, nor vpn'ed into the network. Is this possible? I am learning as I go here, so this may not even be feasible in the first place. Just looking for every avenue possible.
Example Code:
Function WindowsLogin(ByVal strUserName As String, ByVal strpassword As String, ByVal strDomain As String) As Boolean
'Authenticates user and password entered with Active Directory.
On Error GoTo IncorrectPassword
Dim oADsObject, oADsNamespace As Object
Dim strADsPath As String
strADsPath = "WinNT://" & strDomain
Set oADsObject = GetObject(strADsPath)
Set oADsNamespace = GetObject("WinNT:")
Set oADsObject = oADsNamespace.OpenDSObject(strADsPath, strDomain & "\" & strUserName, strpassword, 0)
WindowsLogin = True 'ACCESS GRANTED
ExitSub:
Exit Function
IncorrectPassword:
WindowsLogin = False 'ACCESS DENIED
Resume ExitSub
End Function
EDIT: So #user2140261 told me about trying the LogonUser function from Advapi32.dll which looks like below:
Private Declare Function LogonUser Lib "advapi32.dll" Alias "LogonUserA" (ByVal lpszUsername As String, ByVal lpszDomain As String, ByVal lpszPassword As String, ByVal dwLogonType As UInteger, ByVal dwLogonProvider As UInteger, ByRef phToken As IntPtr) As Boolean
Sub LoginTest()
Dim logname As String
Dim logpass As String
Dim domainstring As String
logname = "username"
logpass = "password"
domainstring = "domain.com"
Call WindowsLogin(logname, logpass, domainstring)
End Sub
For some reason, this crashes Excel all together. Any reason why?
Not sure what the sub WindowsLogin is dong in your orininal code but try the below:
Private Declare Function LogonUser Lib "Advapi32" Alias "LogonUserA" _
(ByVal lpszUsername As String, ByVal lpszDomain As String, ByVal lpszPassword As String, _
ByVal dwLogonType As Long, ByVal dwLogonProvider As Long, phToken As Long) As Long
Public Sub LogUserOn()
Dim strUserName As String
Dim strPassword As String
Dim strDomain As String
Dim bResult As Boolean
strUserName = "UserName"
strPassword = "Password"
strDomain = "Domain"
bResult = LogonUser(strUserName, strDomain, strPassword, 2, 0, 0)
If bResult Then
MsgBox "Successfully Logged User In"
Else: MsgBox "And Error Occured While Trying To Log User In " & vbCrLf _
& "Error Code:" & Err.LastDllError
End If
End Sub
As the answer in the post you referenced said, if you just need to know who is using the app, and apply security based on that, then you can just get the logged-in user's name from the OS. The user can log into their laptop when disconnected using their cached credentials, and your app will be able to lock down whatever is needed based on the identity asserted by the OS.
Update
There are a couple of ways to get the User's identity from the OS. One is the environment variables %USERDOMAIN% and %USERNAME%. Another is the WScript.Network object:
Set WshNetwork = WScript.CreateObject("WScript.Network")
WScript.Echo "Domain = " & WshNetwork.UserDomain
WScript.Echo "User Name = " & WshNetwork.UserName
You can validate that the user is logged into the correct domain, and then provide access to the secured features.