How to set a windows explorer window as the active window - vba

I'm trying to get a macro to select or activate a windows explorer window after it has completed or open the window if it is not found. Currently it does find the window handle (saved as "window") when it is open but it will not activate that window!
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function BringWindowToTop Lib "user32" _
(ByVal hWnd As Long) As Long
Dim directory As String
directory = "C:\...\practice contracts\"
Dim directorySplit() As String
directorySplit = Split(directory, "\")
'--the rest of the macro--
Dim window As Long
window = FindWindow("CabinetWClass", directorySplit(UBound(directorySplit) - 1))
If window <> 0 Then
BringWindowToTop window
Else
Shell "explorer.exe " & directory, vbNormalFocus
End If
I've also tried AppActivate directorySplit(UBound(directorySplit) - 1) instead of FindWindow but it also will find but not activate the window. I can tell that it finds the window and its handle because if I close the explorer window and try running AppActivate againt, it will raise an error instead.
Any help would be appreciated.

Can you please try this?
It worked for me in both conditions. Just tried it again.
If it errors out on appactivate because it cannot find the window, it goes to the window open section and opens the folder.
On Error GoTo WindowOpen
AppActivate directorySplit(UBound(directorySplit) - 1)
Exit Sub
WindowOpen:
Shell "explorer.exe " & directory, vbNormalFocus

This is another solution - simply try to close the window if it exists and then call the same window from the Shell:
If Window <> 0 Then Windows(Window).Close
Shell "explorer.exe " & directory, vbNormalFocus
It should work quite robustly and you can change the focus easily through VBA.

Related

IsWindow returns false for existing window handle

In a VB6 application I am checking if a certain VB.NET WinForms window exists:
Public Declare Function IsWindow Lib "user32" (ByVal hwnd As Long) As Long
If Not IsWindow(102937) Then
MessageBox("Window not found!")
End If
The messagebox is shown, but the window DOES exist.
I inspect it by
Debug.Print(Me.Handle.ToInt32)'it prints 102937
What goes wrong here?
Am I perhaps handling the return value of "IsWindow" incorrectly?
Thank you.
I found the solution:
I was indeed using the WinAPI function incorrectly.
I should have used
If IsWindow(102937) <> 1 Then

How to run function in vba using data macro?

i am new to data macro in ms access 2013 and need some help with it.
so lets assume that i have a simple database with only one table of Users.
when i change the "Age" Field in the table, i want to run an external exe file (the reason why dosent matter).
so i learn the subject during the last few days and end up with this:
1. i build a module in ms access called RunMiniFix (MiniFix is the name of the exe file i want to run). the module uses ShellExecute function and the whole module looks like that:
Option Compare Database
Const SW_SHOW = 1
Const SW_SHOWMAXIMIZED = 3
Public 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, _
Optional ByVal nShowCmd As Long) As Long
Public Function RunMiniFix()
Dim RetVal As Long
On Error Resume Next
RetVal = ShellExecute(0, "open", "C:\Program Files\MiniFix\MiniFix.exe", "<arguments>", _
"<run in folder>", SW_SHOWMAXIMIZED)
End Function
Now, when activating the module, everything works just fine and the exe file is running.
in ms access, i build a data macro based on an 'If Then' statement, asking
if [Users]![Age] > x and then calls the build-in RunCode event from the action catalog which calls the RunMiniFix function.
Now, when saving the data macro, the ms access pops up a message box saying Microsoft access dosen't have the ability to find the name "Users" i mentioned in the phrase and recommend me to look for the right control in the form. "the form"? yes, the form!
this database is not form based. i have no gui designed what so ever. i have no buttons or click event to handle.
what i am asking is how can i trigger the RunMiniFix module when the Age field is modify. please, this is very important!
thanks a head,
oron.
Please use SetLocalVar from the action list in data macro and set the expression to name of your function. Sample:
name: "test"
Expression: RunMiniFix()

ProcessStartInfo.CreateNoWindow doesn't work

I'm printing a pdf directly towards a printer, but I want to do this in the background.
At the moment everything is working, but you can see that adobe is starting up and opening a document, while I want that to stay hidden.
For this I tried to use:
Process1.StartInfo.CreateNoWindow = True
But it won't work, while I do everything the same as written in:
MSDN
It is mentioned that you should place
psi.UseShellExecute = False
In order to let CreateNoWindow work, but when I place this in my code I get an error message: The system cannot find the file specified, while without this line, it works.
Below you can find the entire code:
Dim Process1 As New System.Diagnostics.Process
Dim psi As New ProcessStartInfo("AcroRd32.exe", "/t " + temppdf + " " + General.pdfprinter + "")
'psi.UseShellExecute = False
psi.CreateNoWindow = True
Process1.StartInfo = psi
Process1.Start()
Process1.WaitForInputIdle()
Process1.Kill()
Any idea?
How about this?
Define the function ShowWindow:
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function ShowWindow(ByVal hwnd As IntPtr, ByVal nCmdShow As ShowWindowCommands) As Boolean
End Function
And then call it:
Process1.Start()
ShowWindow(Process1.MainWindowHandle, 0)

Access Application, Hidden Application Window With Form Taskbar Icon

I have an access application with one main form. When you open the application, an AutoExec macro hides the application via the Windows API apiShowWindow. Then, the AutoExec opens up the main form which is set to Popup. This all works beautifully; my database guts are hidden and the form opens up and just floats along.
However, when the access database gets hidden, you loose the taskbar icon. I have a custom icon set in the Options\Current Database\Application Icon setting. If I don't hide the database, this icon displays just fine in the task bar.
I found an API workaround that will show an icon in the taskbar for just the form. It goes a little something like this:
Public Declare Function GetWindowLong Lib "user32" _
Alias "GetWindowLongA" _
(ByVal hWnd As Long, _
ByVal nIndex As Long) As Long
Public Declare Function SetWindowLong Lib "user32" _
Alias "SetWindowLongA" _
(ByVal hWnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long
Public Declare Function SetWindowPos Lib "user32" _
(ByVal hWnd As Long, _
ByVal hWndInsertAfter As Long, _
ByVal X As Long, _
ByVal Y As Long, _
ByVal cx As Long, _
ByVal cy As Long, _
ByVal wFlags As Long) As Long
Public Sub AppTasklist(frmHwnd)
Dim WStyle As Long
Dim Result As Long
WStyle = GetWindowLong(frmHwnd, GWL_EXSTYLE)
WStyle = WStyle Or WS_EX_APPWINDOW
Result = SetWindowPos(frmHwnd, HWND_TOP, 0, 0, 0, 0, _
SWP_NOMOVE Or _
SWP_NOSIZE Or _
SWP_NOACTIVATE Or _
SWP_HIDEWINDOW)
Result = SetWindowLong(frmHwnd, GWL_EXSTYLE, WStyle)
Debug.Print Result
Result = SetWindowPos(frmHwnd, HWND_TOP, 0, 0, 0, 0, _
SWP_NOMOVE Or _
SWP_NOSIZE Or _
SWP_NOACTIVATE Or _
SWP_SHOWWINDOW)
End Sub
This approach does work; I get an icon in the taskbar dedicated to just the form. However, the icon in the taskbar is the standard Access icon.
In response to this problem, I added another API call using the SendMessageA:
Public Declare Function SendMessage32 Lib "user32" Alias _
"SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, _ ByVal wParam
As Long, ByVal lParam As Long) As Long
Executed thus:
Private Const WM_SETICON = &H80
Private Const ICON_SMALL = 0&
Private Const ICON_BIG = 1&
Dim icoPth As String: icoPth = CurrentProject.Path & "\MyAppIcon.ico"
Dim NewIco As Long: NewIco = ExtractIcon32(0, icoPth, 0)
Dim frmHwnd As Long: frmHwnd = Me.hwnd 'the form's handle
SendMessage32 frmHwnd, WM_SETICON, ICON_SMALL, NewIco
SendMessage32 frmHwnd, WM_SETICON, ICON_BIG, NewIco
SendMessage32 hWndAccessApp, WM_SETICON, ICON_SMALL, NewIco
SendMessage32 hWndAccessApp, WM_SETICON, ICON_BIG, NewIco
Keep in mind that I have tried the above four lines of 'SendMessages' in various orders inside of and outside of, top of and bottom of the AppTasklist Sub to no avail.
It does appear to work at the application level, but it never seems to work at the form level.
For those of you familiar with this particular predicament, let me list some of the other options outside of VBA that I have tried.
1.) Taskbar\Properties\Taskbar buttons. I've changed this menu option to 'Never Combine' and 'Combine When Taskbar Is Full'. So, basically, this does work; I now get my icon for just the folder and the little label. BUT(!), it only works if the users have these settings checked on their end. In my experience, almost no one uses any of the options except 'Always combine, hide labels'.
2.) Changing the Registry settings. You can change the following registry key to change the default icon an application uses: "HKEY_CLASSES_ROOT\Access.Application.14\DefaultIcon(Default)." However, most users (myself included) don't have access to the HKEY_CLASSES_ROOT part of the registry. Furthermore, I would have to write some code to find the proper key and then change it (which I could do) but, it's unclear if this change would be immediate--not to mention I'd have to change it back when exiting the application.
3.) Right-clicking the pinned application, then right clicking the application in the menu does give you a properties menu with a button called 'Change Icon...' in the 'Shortcut' tab. However, for a program like Access, this button is greyed out.
I am using Windows 7 and Access 2010.
Is it possible to force the Taskbar Icon in the above scenario to something other than the standard Access Icon?
I feel like there's ether a little something I'm missing, or an API function that could be used, or a better SendMessage constant, or that, maybe, it just can't be done.
Any help would be greatly appreciated.
Also, as a disclaimer (I guess): obviously the above code was pulled from other posts from this forum and others. Most of it was unattributed from whence I got it. I've made some minor tweeks to make it work in Access as opposed to that other piece of Microsoft Software that keeps getting in my search results so I will not name it here.
Thanks!
Okay. So I'm going to answer my own question. Apparently all I really needed was a break from the action and to type out my problem. A short time after I posted the question, I got back on the horse and tried some more search terms. I eventually came across a post which really didn't seem fruitfull at the outset because it wasn't clear to me if the poster and myself were dealing with the same scenario.
I found my answer here:
http://www.access-programmers.co.uk/forums/showthread.php?t=231422
First off, your application must open via a shortcut. Fortunately for me, I've been using a Desktop shortcut from the begining.
When I started building the application, I knew from the outset that I would be using a VBScript to do the installation of the application (as well as updating when a newer version get's released). In that script, I create a Desktop shortcut to the application which I store in the user's Documents directory. I also store the application icon in that directory which I attach to the application shortcut.
If you've never created a shortcut via vba/script, you'll essentially do something like this (written in vbScript):
Dim WinShell
Dim ShtCut
Set WinShell = CreateObject("WScript.Shell")
Set ShtCut = WinShell.CreateShortcut(strDesktopPath & "\MyCoolApp.lnk")
With ShtCut
.TargetPath = (See below)
.Arguments = (See below)
.IconLocation = ...
.Desciption = "This is the coolest app, yo!"
.WorkingDirectory = strAppPath
.WindowStyle = 1
.Save
End With
Now, the target of the shortcut started out being something like this:
"C:\Users\UserName\Public\Documents\MyCoolApp\MyCoolApp.accdb"
Obviously your users may have a different enterprise structure for the Documents location...
What the above reference post suggests doing is turning that shortcut into a psuedo command line script.
To do this:
First, your actual target is going to be the path to the user's version of access (Runtime or full), like such:
"C:\Program Files (x86)\Microsoft Office\Office14\MSACCESS.EXE"
IMPORTANT! You will have to wrap this target in double-quotes, i.e.:
.TargetPath = Chr(34) & strAccessPath & Chr(34)
Next (and you won't find this in the above post, I had to figure it out), you'll need to set the Argument to the directory of the application, like such:
"C:\Users\UserName\Public\Documents\MyCoolApp\MyCoolApp.accdb"
IMPORTANT! Again, you'll have to wrap the arguments in double-quotes, i.e.:
.Arguments = Chr(34) & strAppPath & Chr(34)
Also important, I hope your app IS cool.
Once you have this shortcut set up, essentially you're making it so your application will have it's own workgroup on the taskbar. I.e., if Access is open in general, your application will have it's own group on the taskbar. This group will have your cool, custom icon associated with it. And as a huge unexpected bonus, you'll be able to pin your shortcut to the taskbar outside of Access. SWEEEEEET!
Good luck!

Open Google Chrome from VBA/Excel

I'm trying to open a Chrome browser from VBA. I understand Chrome does not support ActiveX settings so I'm curious if theres any work-arounds?
Dim ie As Object
Set ie = CreateObject("ChromeTab.ChromeFrame")
ie.Navigate "google.ca"
ie.Visible = True
shell("C:\Users\USERNAME\AppData\Local\Google\Chrome\Application\Chrome.exe -url http:google.ca")
Worked here too:
Sub test544()
Dim chromePath As String
chromePath = """C:\Program Files\Google\Chrome\Application\chrome.exe"""
Shell (chromePath & " -url http:google.ca")
End Sub
I found an easier way to do it and it works perfectly even if you don't know the path where the chrome is located.
First of all, you have to paste this code in the top of the module.
Option Explicit
Private pWebAddress As String
Public 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
After that you have to create this two modules:
Sub LoadExplorer()
LoadFile "Chrome.exe" ' Here you are executing the chrome. exe
End Sub
Sub LoadFile(FileName As String)
ShellExecute 0, "Open", FileName, "http://test.123", "", 1 ' You can change the URL.
End Sub
With this you will be able (if you want) to set a variable for the url or just leave it like hardcode.
Ps: It works perfectly for others browsers just changing "Chrome.exe" to opera, bing, etc.
You can use the following vba code and input them into standard module in excel. A list of websites can be entered and should be entered like this on cell A1 in Excel - www.stackoverflow.com
ActiveSheet.Cells(1,2).Value merely takes the number of website links that you have on cell B1 in Excel and will loop the code again and again based on number of website links you have placed on the sheet. Therefore Chrome will open up a new tab for each website link.
I hope this helps with the dynamic website you have got.
Sub multiplechrome()
Dim WebUrl As String
Dim i As Integer
For i = 1 To ActiveSheet.Cells(1, 2).Value
WebUrl = "http://" & Cells(i, 1).Value & """"
Shell ("C:\Program Files (x86)\Google\Chrome\Application\chrome.exe -url " & WebUrl)
Next
End Sub
The answer given by #ray above works perfectly, but make sure you are using the right path to open up the file. If you right click on your icon and click properties, you should see where the actual path is, just copy past that and it should work.
You could use selenium basic to launch and interact with Chrome. After installation you will need to add a reference to Selenium Type library.
Option Explicit
Public Sub Demo()
Dim d As WebDriver
Set d = New ChromeDriver
Const URL = "https://www.google.com/"
With d
.Start "Chrome"
.get URL
.FindElementById("lst-ib").SendKeys "Selenium basic GitHub"
.FindElementsByTag("form")(1).FindElementByCss("input[value='Google Search']").Click
'.Quit
End With
End Sub