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

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.

Related

Word VBA macro errors opening files when run on some computers but not others?

This has been a thorn in my side for months. It happens off and on for a small (but growing) number of users at my company, but not others running the same exact Word VBA Macro. The users get "5097:Word encountered an issue" or "4605: Command failed" runtime errors on lines of the code that open word or txt files. All are running the same build of windows and have the same permissions (according to the tech team.) The files are on a shared network drive.
Public Function readData(datafile As String) As String
'datafile = "\\network\unc\path\folder\folder\data.txt"
'I have confirmed this passes to the function correctly.
Dim db As Document
'Before it is suggested, I've tried early-binding, late-binding, and
'diming as Variant, Object, etc. to no effect
'Errors on this line
Set db = Documents.OpenNoRepairDialog(fileName:=datafile, ConfirmConversions:=False, _
ReadOnly:=True, Visible:=False)
'I have tried Documents.Open to no avail, in addition to toggling all of the parameters to
'or removing parameters see if I would get a different result.
'I have tried declaring the Word.Application and Application objects and prepending that
'to the function. Nadda. I also tried just the function, without setting as an object. No dice.
'---rest of code---'
End Function
I've used Debug.Print to check the file path was passed to the function correctly--it is. Also this issue does not have to do with the file being a txt file. If I comment out this function in the main sub, I get the same error on the next function that attempts to open a word doc.
Again, this exact macro runs flawlessly on some workstations.
Here's the real kicker:
The users are all able to navigate to the file paths the macro is trying to open in File Explorer without problem. When I run the "Documents.Open(datafile)" or "Dir(datafile)" functions in the immediate window they work perfectly, no issue. What gives?

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.

How can Excel VBA open file using default application

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).

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.

Capturing spreadsheet usage throughout a company

We have a lot of customized spreadsheet solutions that are being used and we want some programmatic way of keeping track of them. Obviously since they are spreadsheets, people can save them locally, rename them, etc so we need a solution that can account for that.
Some ideas are:
On spreadsheet open, handle the OnOpen event and write a message to a database for tracking
the issues with this are where do we store database details. If the database is down, we dont want the spreadsheet to crash, etc
has anyone come up with a good spreadsheet inventory management solution that handles all the issues above.
I don't understand the problem you're trying to solve here: you don't need spreadsheet usage logging as an end-result, something is causing pain and this is what you've devised to try to fix it.
If you need seriously reliable logging of all spreadsheet usage, then I don't think this is going to work. If you need mostly reliable logging, then just use a database and don't worry about the (rare) occasions that the database is down. On Error Resume Next should be enough to ensure the spreadsheet continues in that event.
That said, I'd be more inclined to go for a web-based solution: that way you don't have to get involved with ensuring everyone has the necessary database drivers, working connection strings and other horridness.
Some more awkward questions that are making me think that you may need another approach:
How are you going to deploy changes to your logging solution?
Do your users have control over their macro security level? Or the ability to write and edit macros? Could they therefore (innocently or otherwise) disable logging?
Can the users operate offline? What happens then?
Have the excel spreadsheet make a request out to a web server.
Add msinet.ocx to your toolbox and create a form with the Inet control. Add the ocx by right clicking somewhere in the toolbox area.
Then you can set the location of the Inet control somewhere you can handle that the spreadsheet was opened.
Although you may need logging in the short term, the long term solution should be to bring your spreadsheets under control. You should gather the "definitive" copy of the spreadsheets, and move them to a file share, where they will all be protected - users will be able to change the data in them, but will be unable to change the formulas.
If you need a more controlled collaboration solution, then you should look into using SharePoint, possibly the MOSS version which has Excel Services on it.
You might also need to explore how the spreadsheets are being used. Perhaps they are being used instead of someone writing a program, and in some cases, it may be time to do that.
Lastly, you don't want to track spreadsheet usage - you don't care if someone creates a spreadsheet to track their kid's soccer team scores. It's particular spreadsheets you're interested in. The logging may help you track that down to start with, but that's all it can help you with.
I like the suggestions being made so far and what you wrote. I personally like to keep things simple so here's my humble suggestion. It sounds like you have a lot of templates you may be managing and with excel things get messy quick and it's hard to know that formulas are not being tampered with. With that in mind I'd forget any database change management solution, instead:
Create a share drive folder that's set to read only and accessible by everyone in the company
You can create a sub folder structure that makes sense by team, department, location, whatever works
Store the latest copies of the excel templates in the folders
I'd also suggest locking the templates that have critical calculations in them
--> Try to leave it as open as you can so they can be customized where they need be but at your discretion
You may also consider setting up a version control repository that manages the changes to this folder structure. Look into version control with a simple interface like tortoiseSVN so you can track what changes were made and when. The standard share drive back ups are a life saver but I'd still supplement with a version control system (just makes things a little easier). Here's a couple of links to help you get started, you can try subversion locally and see what you think:
Instructions to setup Subversion on Windows
Tortoise Client to interact with Subversion
Also note, IF you chose to implement some kind of database connection for a spreadsheet to perform logging on a database server as has already been noted you can use "on error resume next". Here's what you can do:
After resume next attempt to open the connection to the DB
You can choose to handle the error then with an if statement such as:
if err.number = 3024 then
msgbox "Database file not found, check network connection and retry"
exit
end if
Here's a link to look up additional error codes for trapping in similar fashion:
Error Trapping in VBA
I do something very similar to this to check the current version of the Excel application. You could just as easily use this same code to make a web-request to a server that will log 'hits'. Here's my code:
In ThisWorkbook:
Option Explicit
Private Sub Workbook_Open()
Updater.CheckVersion
End Sub
Elsewhere (in a module called Updater)
Option Explicit
Const VersionURL = "http://yourServer/CurrentVersion.txt"
Const ChangesURL = "http://yourServer/Changelog.txt"
Const LatestVersionURL = "http://yourServer/YourTool.xlsm"
#If VBA7 Then
Private Declare PtrSafe 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
#Else
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
#End If
Public Sub CheckVersion()
On Error GoTo fail
Application.StatusBar = "Checking for newer version..."
Dim ThisVersion As String, LatestVersion As String, VersionChanges As String
ThisVersion = Range("CurrentVersion").Text
If ThisVersion = vbNullString Then GoTo fail
LatestVersion = FetchFile(VersionURL, , True)
VersionChanges = FetchFile(ChangesURL, , True)
If LatestVersion = vbNullString Then
Application.StatusBar = "Version Check Failed!"
Exit Sub
Else
If LatestVersion = ThisVersion Then
Application.StatusBar = "Version Check: You are running the latest version!"
Else
Application.StatusBar = "Version Check: This tool is out of date!"
If (MsgBox("You are not running the latest version of this tool. Your version is " & _
ThisVersion & ", and the latest version is " & LatestVersion & vbNewLine & _
vbNewLine & "Changes: " & VersionChanges & vbNewLine & _
vbNewLine & "Click OK to visit the latest version download link.", vbOKCancel, _
"Tool Out of Date Notification") = vbOK) Then
ShellExecute 0, vbNullString, LatestVersionURL, vbNullString, vbNullString, vbNormalFocus
End If
End If
End If
Exit Sub
fail:
On Error Resume Next
Application.StatusBar = "Version Check Failed (" & Err.Description & ")"
End Sub
As you can see, error handling is in place to make sure that if the URL is unavailable, the app doesn't crash, it just writes a message to the user in the status bar.
Note that if you don't want to set up a web service that does this, you could try to have the spreadsheet write to a database - you could still re-use a lot of this code, but not as much of it.
Your idea is good. Database availability is usually higher than the availability of the users' laptop. And there is a kind of primitive error (exception) handling in VBA, so they won't necessarily see freaking error messages.
Yes, you have a loss. Any uses of the sheet saved offline when the user is not on your network - will be missing from the database. But I don't think that there's a 100% foolproof solution for this.
Try to search for a Financial Times article like "Excel - a tool that is too ad hoc and open for errors". Even the title says it all.
write to the db, if the write fails, catch the error and send an e-mail to someone that can manually increment the count when the database is back up.
You could do a file-based approach with any of several file integrity monitoring solutions. Samhain is one free open source example. That would allow your employees to access their spreadsheets without interference, but would report when new spreadsheets are discovered or when their timestamps or hash values change. It would also detect changes made while the developer was off-line (on their laptops, for example) once they've reconnected to the network.