How can Excel VBA open file using default application - vba

I want an Excel spreadsheet that has a file path and name in column A. When a macro is run, let's say the file specified in A1 should be opened on the user's machine. The file could be .doc, .xls, .txt, etc.... rather than my vba needing to know the full path the to application, how could I have the vba tell the machine "please open this file and use your application associated with the extension" ?
I have already found this to work with the full path:
dblShellReturned = Shell("C:\Windows\System32\notepad.exe myfile.txt, vbNormalFocus)
how could I get it to work with something like:
dblShellReturned = Shell("myfile.txt", vbNormalFocus) ' how do I get this to work
Thank you in advance!

This works for me in Excel & Word
Sub runit()
Dim Shex As Object
Set Shex = CreateObject("Shell.Application")
tgtfile = "C:\Nax\dud.txt"
Shex.Open (tgtfile)
End Sub
or ... as per Expenzor's comment below
CreateObject("Shell.Application").Open("C:\Nax\dud.txt")

VBA's Shell command wants an exe, so I've been launching the explorer.exe and passing in my file path as an argument. It also seems to work with *.lnk shortcuts and web urls.
Shell "explorer.exe C:\myfile.txt"

The code below is a template. However you might want to update the default (working) directory to the location of the file.
Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpszOp As String, _
ByVal lpszFile As String, ByVal lpszParams As String, _
ByVal LpszDir As String, ByVal FsShowCmd As Long) _
Function StartDoc(DocName As String) As Long
Dim Scr_hDC As Long
Scr_hDC = GetDesktopWindow()
StartDoc = ShellExecute(Scr_hDC, "Open", DocName, _
"", "C:\", SW_SHOWNORMAL)
End Function

I can't comment on existing answers (not enough points), so I'm answering to add information.
Working from Access 2010, I ran into silent failures with the following syntax:
Dim URL As String
URL = "http://foo.com/"
CreateObject("Shell.Application").Open URL
I could get it to work if I wrapped URL in parentheses, but that just seems wrong for subroutine (instead of function) call syntax. I tried swallowing the return value, but that failed with function call syntax, unless I doubled up the parentheses. I realized that the parentheses weren't just syntactic sugar - they had to be doing something, which lead me to believe they might be facilitating implicit casting.
I noticed that Open expects a Variant, not a String. So I tried CVar, which did work. With that in mind, the follwing is my preferred approach since it minimizes the "why are there extraneous parentheses here?" questions.
Dim URL As String
URL = "http://foo.com/"
CreateObject("Shell.Application").Open CVar(URL)
The lesson is that when making OLE Automation calls, be explicit about having Access VBA cast things appropriately!

Shell32.Shell COM object aka Shell.Application can be used that wraps the ShellExecute Win32 API function:
Add a reference to Microsoft Shell Controls And Automation type library to VBA project via Tools->References..., then
Dim a As New Shell32.Shell
Call a.ShellExecute("desktop.ini")
Alternatively, without any references:
Call CreateObject("Shell.Application").ShellExecute("desktop.ini")
Interestingly, here (WinXP), when using a typed variable (that provides autocomplete), ShellExecute is missing from the members list (but works nonetheless).

Related

Open files with .SLDDRW.cvd, .NFT.cvd and .xlsm in solidworks

I have a couple of questions about solidworks.
I want to open some files with .SLDDRW.cvd, .NFT.cvd and .xlsm. I 've used Opendoc6, it doesn't work. Can you please help me.
Any help is welcome
Thanks
According the API Open6 accpts this parameters:
Function OpenDoc6( _
ByVal FileName As System.String, _
ByVal Type As System.Integer, _
ByVal Options As System.Integer, _
ByVal Configuration As System.String, _
ByRef Errors As System.Integer, _
ByRef Warnings As System.Integer _
) As ModelDoc2
The Types options possible (swDocumentTypes_e) are:
swDocASSEMBLY 2
swDocDRAWING 3
swDocIMPORTED_ASSEMBLY 7; Multi-CAD
swDocIMPORTED_PART 6; Multi-CAD
swDocLAYOUT 5
swDocNONE 0
swDocPART 1
swDocSDM
If using swDocDrawing it doesn't work I think it is not possible with this Open6 function.
Have a look to this post from solidworks forum, https://forum.solidworks.com/thread/57616 in special David's comment:
A ".sldprt.cvd" file is a Virtual SolidWorks Part document There is no data in the file which will be why you cannot open it. It will
have been created inside Enterprise PDM as a placeholder until someone
had time to create the real file. If you need to add SolidWorks data
to this file then you can Right Click on it and select Replace. This
then allows you to find a SolidWorks Part to replace the virtual
document with. David
Maybe it can give you some ideas.

Circumvent Hyperlink Security Warning

I have a VBA script that cycles through a list of ppt links to sharepoint, opens them, saves them in a temp location, extracts information from specific text boxes and closes them. However when I try to open the links, I get the security warning-
"Opening http://.....pptm
Some files can contain viruses or otherwise be harmful to your computer. It is imporant to be certain that this file is from a trustworthy source.
Would you like to open this file?"
I know I can disable this by going into the registries; however my company does not allow me to do so. Can anyone recommend a way to either
Automatically close these warnings/disable them entirely
Extract the information from the .ppts in another way.
Taking a look at the MS support page for that issue it seems that all the solutions for it are inevitably registry based.
Tested and working for all versions of Office (making use of the registry):
Disable the hyperlink warning:
CreateObject("Wscript.Shell").RegWrite _
"HKCU\Software\Microsoft\Office\" & Application.Version & _
"\Common\Security\DisableHyperlinkWarning", 1, "REG_DWORD"
(Re-)Enable the hyperlink warning:
CreateObject("Wscript.Shell").RegWrite _
"HKCU\Software\Microsoft\Office\" & Application.Version & _
"\Common\Security\DisableHyperlinkWarning", 0, "REG_DWORD"
I haven't tried them, but here are a few options:
.
ShellExecute (API):
.
Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpszOp As String, _
ByVal lpszFile As String, ByVal lpszParams As String, _
ByVal LpszDir As String, ByVal FsShowCmd As Long) _
As Long
More details from Microsoft
.
Registry edit:
Click Start, and then click Run.
In the Open dialog box, type regedit, and then click OK.
In Registry Editor, locate and then click one of the following registry subkeys:
HKEY_CURRENT_USER\Software\Microsoft\Office\11.0\Common
HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\11.0\Common
Notes:
You only have to modify one of these registry subkeys, not both of them.
If the HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\11.0\Common registry subkey does not exist, you may have to manually create it.
After you click the registry subkey, point to New on the Edit menu, and then click Key.
Type Security, and then press ENTER to name the key.
On the Edit menu, point to New, and then click DWORD Value.
Type DisableHyperlinkWarning, and then press ENTER to name the entry.
In the right pane, right-click DisableHyperlinkWarning, and then click Modify.
In the Edit DWORD Value dialog box, click Decimal, and then type 1 under Value data.
Note
A value of 0 enables the hyperlink warning message, and a value of 1 disables the warning message.
Click OK.
Quit Registry Editor.
More details from Microsoft1 and Microsoft2
.
VBA code to modify the registry:
Option Explicit
Function killHyperlinkWarning()
Dim oShell As Object
Dim strReg As String
strReg = "Software\Microsoft\Office\11.0\Common\Security\Dis ableHyperlinkWarning"
Set oShell = CreateObject("Wscript.Shell")
oShell.RegWrite "HKCU\" & strReg, 1, "REG_DWORD"
End Function
found here

How to run a Classic ASP file (located on a server) from VBA code?

Last few days I was working on a Outlook 2013 function which reads an email and saves all data of the email. This is being done in the VBA code of Outlook and all works fine. The stored VBA data is then transferred to a XML file on the server which also works.
What I want to do next is read the transferred XML Data in the ASP file (which is also located on the server) and INSERT the data into an MS SQL server and then removing the XML file.
This all works fine as well since I tested it by manually calling the asp file on the web.
Though the thing I cant seem to find out is how to activate/launch the ASP file from within the VBA code automatically instead of calling it myself manually.
So when the Macro is being clicked in Outlook it gets the data, puts it in an XML file and then it should launch the ASP file.
There is an other way to do it, namely by using a Task Scheduler on my server which launches the ASP file every X minutes (and looks for the XML file). This possibility is something I rather avoid though because if a outlook user presses the Outlook macro multiple times in a short time the XML files will overwrite each otter (and thus having the change of not getting ALL the right data).
I didn't add my code since I think it is not really needed here (since the code I have is working), though if code is needed just ask;)
UPDATE
I found a piece of code which opens the asp file on the web (and thus launching it). The problem how ever is that it opens the webpage, while it only should run it. So I should add something that the page is also closed right away (so the user doesn't see it getting opened), now clue if this can be achieved though..
The code for opening it is as follows:
Private Declare Function ShellExecute _
Lib "shell32.dll" Alias "ShellExecuteA" ( _
ByVal hWnd As Long, _
ByVal Operation As String, _
ByVal Filename As String, _
Optional ByVal Parameters As String, _
Optional ByVal Directory As String, _
Optional ByVal WindowStyle As Long = vbMinimizedFocus _
) As Long
Public Sub OpenUrl()
Dim lSuccess As Long
lSuccess = ShellExecute(0, "Open", "http://mywebsite.nl/MyCode.asp")
End Sub
which is also located on the server
Do you automate Outlook on the server?
It looks like you need to develop a web service for submitting your data (extracted from Outlook) to the server and run the server sider infrastructure.

VBA Excel variables value after closing the excel file

I have an user form which selects a directory path. That path is stored in a variable. The problem is that every time I start the macro, I have to rechoose the path for the directory. How should be the path variable declared in order to keep it's value once the macro is closed, or the excel file is closed ?
Persisting data between calls to a macro is simpler; use a variable at module scope in the .bas module containing the macro.
Persisting data on saving is more difficult. You could write to the registry but that's tricky and you'll need to use various Windows API functions.
The simplest thing to do would be to write the data to somewhere on the workbook.
The registry is simple in VBA. It's is very limited and uses ini file concepts.
There's a few of them such as (from Object Browser [F2] in VBA editor)
Function GetAllSettings(AppName As String, Section As String)
Member of VBA.Interaction
Sub SaveSetting(AppName As String, Section As String, Key As String, Setting As String)
Member of VBA.Interaction
Sub DeleteSetting(AppName As String, [Section], [Key])
Member of VBA.Interaction
Function GetSetting(AppName As String, Section As String, Key As String, [Default]) As String
Member of VBA.Interaction
Also the newer Windows Scripting Host Shell object also makes registry access easy.
object.RegDelete(strName)
object.RegRead(strName)
object.RegWrite(strName, anyValue [,strType])
Also WMI can access registry. Unlike both above methods it can ennumerate, so you can see what is there without have to know in advance.
Dim proglist()
Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
ret = oReg.EnumKey(&H80000002, "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", proglist)
If err.num =0 then
For each prog in proglist
msgbox prog
Next
Else
Msgbox err.num & " " & err.description & " " & err.source
err.clear
End If
It can also check security and monitor changes to keys.
I would use a Name, which can be saved with the workbook.
ThisWorkbook.Names.Add Name:="SavedPath", RefersTo:= someString
Another simple alternative is to put that value in a cell, eventually in a hidden sheet, or a hidden row/column of any suitable sheet.
A third solution is to add it to the file properties.
Registry tricks are complex, don't work if you change machine or if user has not enough rights.
I have solved the problem storing the data on a cell and then on excel file initialization giving the data to corresponding variables. Thank you very much for those who thought to a solution !

Is it possible to specify a location in a user's home directory for a shared library in VBA (in Office for Mac)?

I'm currently using the VBA code similar to the following to specify a location of a shared library for use in communicating (passing a string) from an Office application to a desktop application. The VBA code/macros will need to exist in an add-in (.ppa).
Private Declare Sub sharedLibPassString CDecl Lib "/Users/myUserName/Library/Application Support/myCompanyName/MySharedLib.dylib" Alias "PassString" (ByVal aString As String)
In code from a VBA Macro, I then can do the following.
Call sharedLibPassString(myString)
I've got the communication working, but I'd like to replace the /Users/myUserName/ part with the current user's home directory. Normally on a Mac, you'd specify ~/Library/Application Support/..., but the ~/ syntax doesn't work, producing a "File not found" runtime error.
I discovered that using the following Environment Variable method gets me the ~/ location that I need:
Environ("HOME")
However, I don't see a way to make this part of the CDecl Lib statement, since, as far as I can tell, Environ is evaluated at runtime.
Is there any way to specify a location of a shared library in the user's home directory (~/) in VBA?
Here are a few notes about my environment/approach:
I'm using a Mac, though I believe if there is a solution it would be similar on a PC.
I don't believe it shouldn't matter, but the Office application I'm using is PowerPoint (2011).
The reason I'm trying to access an area inside of the Application Support directory, instead of the default location for shared libraries is because I'd like the Desktop application to place the shared library in a location without an installer, and without requiring a user's or administrator's privileges. If there is a better solution or location to accomplish the same task, this would be very helpful as well.
Sorry for giving a long response, I just wanted to make sure I explained this fairly well.
From this page (Anatomy of a Declare Statement) we read that
The Lib keyword specifies which DLL contains the function. Note that
the name of the DLL is contained in a string within the Declare
statement.
(emphasis added)
From experimentation, the VBE scolds me if I try to give anything but a string constant.
The only work around that I'm aware of requires rewriting the string constant at runtime.
Here is an example of how this could be done: Let's say your delaration statement is in Module1 in your current project, and that you deliberately wrote the declaration in this format at the top of your module:
Private Declare Sub sharedLibPassString CDecl Lib _
"/Users/myUserName/Library/Application Support/myCompanyName/MySharedLib.dylib" _
Alias "PassString" (ByVal aString As String)
You can access that module via code through this (requires permissions to VBA in trust Center listed under Developer Macro Settings):
Dim myModule
set myModule = ActivePresentation.VBProject.VBComponents("Module1").CodeModule
Once you've gained the CodeModule, you can replace the 2nd line directly:
myModule.ReplaceLine 2, Environ("HOME") & " _"
Mission accomplished!
If you do this, you will need to update the path prior to attempting to call your declared sub. There must be a break in execution that allows VBA to recognize the change. Also, you will not be able to modify the code while in break mode.
Now if I were doing this, I'd want to make sure I replace the right line, to not break code. You can check the contents of the 2nd line by calling this myModule.Lines(2,1) which will return the string value of the line.
However, here is a more robust solution that will find the correct line and then replace it (assumes myModule has already been defined as listed above):
Dim SL As Long, EL As Long, SC As Long, EC As Long
Dim Found As Boolean
SL = 1 ' Start on line 1
SC = 1 ' Start on Column 1
EL = 99999 ' Search until the 99999th line
EC = 999 ' Search until the 999th column
With myModule
'If found, the correct line will be be placed in the variable SL
'Broke search string into two pieces so that I won't accidentally find it.
Found = .Find("/Users/myUserName/Library/Application Support/myCompanyName/" & _
"MySharedLib.dylib", SL, SC, EL, EC, True, False, False)
If Found = True Then
'Replace the line with the line you want, second paramater should be a string of the value.
.ReplaceLine SL, Environ("HOME") & " _"
End If
End With
I don't have a Mac, so this is an incomplete answer and I don't know if it will help, but it's a couple of ideas.
I know on Windows, VB doesn't load an external library until you first try to call a function declared with it, and if you specify only the filename in the declare statement, it will use the system path to look for it. Once I did the same thing you are doing, loading a library from a dynamic path, by specifying only a filename, then making a system API call to set the current working directory to the directory of the library before loading it. Changing the PATH environment variable would probably also work.
Second idea: you could hard-code the path to a filename in the /tmp directory; then automatically copy the desired library to that location before loading it. Watch out for the file being in use by another process, but that's only an error if it is a different version of the file to the one that you want.