Excel Automation Workbooks.Open fails: "Unable to get the Open Property ..." - asp.net

I'm working with a web application that performs some Excel automation (I know - not a preferred solution).
I am using Excel 2007 as my development platform but the target server uses Excel 2003. After experiencing a lot of headaches with the Excel 12 interop trying to be loaded on the target server even though I expressly selected Excel 11 during development, I have resorted to using late binding rather than early binding.
This has allowed me to get as far so as to instantiate Excel (and I can see the Excel process start in task manager on the target server).
However I am unable to invoke the Open method of the late-bound Workbooks object. It throws this error at me:
"Unable to get the Open property of the Workbooks class"
I have been experimenting with a few different things and have tried the following:
Try the same Workbooks.Open call using late-binding VBScript (e.g. a vbs file).
Try the same Workbooks.Open call using late-binding VBA code (e.g. in Excel).
Try the same Workbooks.Open call using late-binding .NET code in a Windows Forms application.
In all three cases, the Excel automation succeeds. It's only when I deploy the ASP.NET application that this error crops up. In a very simplified form, the code resembles:
Dim xlApp As Object 'Excel.Application
Dim xlBook As Object ' Excel.Workbook
xlApp = CreateObject("Excel.Application") 'New Excel.Application
xlBook = xlApp.Workbooks.Open("somefile.xls", , True, , , , , , , , , , , , False)
Does anyone have any ideas as to what might be happening? I checked the user that the Excel process starts as, and it is the same user that I successfully ran the Windows Forms .NET application as successfully. I had already opened Excel as this user to clear all the initial setup stuff.

I'm getting this same problem and I found some sites saying the following: Try going to file - options - add-ins - select diabled add-ins in the manage dropdown - click go - and enable anything in there.
It didn't work for me but it might for you.

Better a late answer then never...
When developing a VBscript make sure you handle the error that prevent closing your Excel Book correctly.
I got the same error as you, but I found out that when a error occurs within my logic, the interpreter doesn't close the Excel Book making it unavailable to further process.
Dim XLWkbk 'Excel workbook
Set xlApp = CreateObject("excel.application")
On Error Resume Next
Set XLWkbk = xlApp.Workbooks.Open("somefile.xlsm")
If Err.Number <> 0 Then ' Catch your error
WScript.Echo "Error while opening: " & Err.Number & " " & Err.Description
XLWkbk.Close False ' Close your workbook.
xlApp.Quit ' Quit the excel program.
WScript.Quit
Err.Clear
End If
WScript.Echo "Opened"
Be sure to handle the error with all function that operates on a file (SaveAs, Close, etc...)

Omitting the last argument fixed it for me.
xlBook = xlApp.Workbooks.Open("somefile.xls", , True, , , , , , , , , , , , )

Related

Is web automation with Openoffice BASIC even possible?

I'm trying to do some simple webscraping in OpenOffice (I usually work in Excel but I'm trying to port something over for a coworker that doesn't have Excel). However, when I try to run something very similar to this, it keeps giving me this BASIC runtime error 1.
Here's the relevant code, I'm not sure what I'm supposed to do to make this work.
Sub Macro1
Dim explorer As Object
Set explorer = CreateObject("InternetExplorer.Application")
explorer.Visible = True
explorer.navigate("www.yahoo.com")
Const READYSTATE_COMPLETE As Long = 4
Do While explorer.Busy Or explorer.readyState <> READYSTATE_COMPLETE
Loop
dim page as object
set page = explorer.Document
dim mailButton as object
set mailButton = page.GetElementByID("ybar-navigation-item-mail") 'this is the line the error occurs on
mailButton.Click
End Sub
Do you know that you can save script in vbs file (you have to delete types in variables declarations) and run it directly by double click without using office application? I recommend you to use this way.

MsgBox doesn't work after deployment

I've deployed my ASP.NET application today. It's a web application (I am using forms, etc.). I was happy with all my functionalities. For example, I had part of the of the code that says
if c.results = " " then MsgBox("Error! No record was returned)
Then I clear all my text boxes.
That MsgBox was working when I was running my application locally, but now that I've deployed it I get a server run error! I read some similar posts that said MsgBox is not supported with web applications, but all their answers were with JavaScript. I am not familiar with it, but I don't understand how to put my JavaScript in my Visual Basic class instead of where I am calling the MsgBox- is there a way fixing the above issue with VB.NET code?
Here is the code:
Dim results = customer.getCustomerDetails(txtCustomerNumber.Text, txtDOB.Text)
If (results.customerNumber = "") Then
Response.Write("<script>alert('Customer record not found')</script>")
txtCustomerNumber.Text = ""
txtDOB.Text = ""
Else
( Do the other stuff)
End if
MsgBox is server side so it can't show up to the client which is only seeing the client side of the ASP.NET webform, hence use the following if you want to access a JavaScript alert from code behind or simply alert in JavaScript:
Page.ClientScript.RegisterStartupScript(Page.GetType(), "alert", "<script
language=JavaScript>alert('your wanted message');</script>")
You can generate client code from your server side VB as such:
If c.results = " " Then
Response.Write("<script>alert('Error! No record was returned')</script>")
End If

How to get PID (Process ID) of Word instance or Hwnd property?

I'm looking for a better way of coding for proper closing of WINWORD.EXE or word process in my application by getting its PID (Process ID) just like getting the PID in Excel.
This is my sample of getting the PID of an Excel using Hwnd property and GetProcessID class.
Imports System.Diagnostics
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Integer, ByRef lpdwProcessId As IntPtr) As IntPtr
Public Sub CreateNewFromTemplate_Excel()
' Create Excel Application, Workbook, and WorkSheets
Dim xlExcel As Excel.Application = New Excel.Application
'Getting the process ID of excel application
Dim processId As IntPtr = Nothing
GetWindowThreadProcessId(xlExcel.Hwnd, processId)
Dim excelProcess As Process = Process.GetProcessById(processId.ToInt32())
Dim blError As Boolean = False
Try
[Perform Excel generation here.]
' Make sure all objects are disposed
xlBook.Close()
xlExcel.Quit()
Catch ex As Exception
blError = True
If Not excelProcess.HasExited Then excelProcess.Kill() ' End the specific Excel Process ID if not yet closed.
Throw
Finally
If Not blError Then
If Not excelProcess.HasExited Then excelProcess.Kill() ' End the specific Excel Process ID if not yet closed.
End If
End Try
End Sub
This is my code for closing the Word Process/WINWORD.EXE but unfortunately, it's not working on the server side so I'm looking for a way and code to get the Word Process ID to properly close it.
Marshal.ReleaseComObject(rng)
Dim strFileName As String = comm.GenerateFilename(strUser_Id, strVPN) & ".docx"
' Save the document.
Dim filename As Object = Path.GetFullPath(strNewFilePath & strFileName)
newDoc.SaveAs(FileName:=filename)
' Close.
Dim save_changes As Object = False
newDoc.Close(save_changes)
WordApp.Quit(save_changes)
Marshal.ReleaseComObject(newDoc)
Marshal.ReleaseComObject(WordApp)
rng = Nothing
newDoc = Nothing
WordApp = Nothing
' Let GC know about it
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
' save the file to database
SaveFormat(filename, strUser_Id, strFamilyId.Trim, strVPN.Trim, DateTime.Now.ToString(), "application/vnd.ms-word", br_id, "doc")
If File.Exists(filename) Then
File.Delete(filename)
End If
Can anyone suggest what's the best way or the best practice for coding on how to get the PID or Hwnd property of Word instance. Thanks :)
What you are trying to do is probably not going to work as reliably as expected. I would strongly suggest that you switch to OpenXML or some other library if you need to process documents and spreadsheets from Server side.
I tend to use EPPlus which works very well and is almost the same code as VBA/Interop. http://epplus.codeplex.com/
I would read the following warnings and articles from Microsoft before proceeding:
All current versions of Microsoft Office were designed, tested, and configured to run as end-user products on a client workstation. They assume an interactive desktop and user profile. They do not provide the level of reentrancy or security that is necessary to meet the needs of server-side components that are designed to run unattended.
Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.
https://support.microsoft.com/en-us/help/257757/considerations-for-server-side-automation-of-office

FileUpload control in asp/VB.net cannot access the file because it is being used by another process

Error message:
The process cannot access the file 'C:\SampleProjectName\mytestcsv.csv' because it is being used by another process.
I am trying to read numerous files (CSV, XML, HTML) in asp/VB.net using the fileupload (file upload) control.
I'm saving the file using Server.MapPath so I can process the file in another procedure. It's very odd, but sometimes I can browse and upload the same file over and over with no issues, but sometimes it immediately fails.
I've found that I can ultimately kill the WebDev.WebServer40.exe it releases whatever lock is present. This is annoying, but fine for my debugging... but unacceptable for endusers.
My fileupload code:
If fuImport.HasFile Then
If (System.IO.File.Exists(Server.MapPath("myhtml.html"))) Then
System.IO.File.Delete(Server.MapPath("myhtml.html"))
End If
Dim dtFromHTML As New Data.DataTable
Dim dtFromSQL As New Data.DataTable
Try
fuImport.SaveAs(Server.MapPath("mytestcsv.csv"))
'Process data here
ProcessCSVData(Server.MapPath("mytestcsv.csv"))
Catch ex As Exception
Response.Write("error: " & ex.Message)
Finally
fuImport.PostedFile.InputStream.Flush()
fuImport.PostedFile.InputStream.Close()
fuImport.FileContent.Dispose()
End Try
'Other things happen here
Else
Response.Write("no file...")
End If
Any ideas would be appreciated.
Use FileShare.Read to read a file even if it is opened exclusively by an another process.
You may not be releasing the file in your code for access. You should use the keyword "using".
Read this post:
The process cannot access the file because it is being used by another process - using static class
and this:
http://msdn.microsoft.com/en-us/library/htd05whh.aspx
I am not a VB.NET coder but try something along the lines of:
Using {fuImport.SaveAs(Server.MapPath("mytestcsv.csv")) }
ProcessCSVData(Server.MapPath("mytestcsv.csv"))
End Using
The next procedure that uses file...
Try closing input stream before accessing the file:
UPDATED To use temp filename
Dim sTempName = Path.GetRandomFileName
fuImport.SaveAs(Server.MapPath(sTempName))
'close before accessing saved file
fuImport.PostedFile.InputStream.Close()
'Process data here
ProcessCSVData(Server.MapPath(sTempName)

Insert using ADO with classic ASP

' Setting variables
Dim con, sql_insert, data_source
data_source = "project_db"
sql_insert = "insert into cart ( UserID,Count,ProductName,ProductDescription,ProductPrice) values ('"&user_id&"','"&count&"','"&product_name&"','"&product_description&"','"&product_price&"')"
' Creating the Connection Object and opening the database
Set con = Server.CreateObject("ADODB.Connection")
con.Open data_source
' Executing the sql insertion code
con.Execute sql_insert
' Done. Now Close the connection
con.Close
Set con = Nothing
AS you can see , it is a simple code . and it worked in my local host for 5 or 6 times. but now it didn't work. What's the problem ? I think , it's about my database or memory. i setup 2 different iis in 2 different computer and they behave same... please help..
Thanks
Does it give you any error message? Make sure all the values you are inserting actually have values and are not blank or null. You can check this by response.write all the values and then response.end to see if they contain any values.
I bet it's a data-dependent error. You should be using ADO parameters. Those will ensure that extraneous SQL-unfriendly characters in your input do not adversely affect your database operation. You should also use them to guard against SQL injection issues.
Some docs are available at http://msdn.microsoft.com/en-us/library/ms675869(VS.85).aspx, and you can google for "ADO parameters" and find many relevant examples.
I believe that 'data_source' should be focused on (and agreed with Tom Gullen as regards to error messages. Always use Option Explicit at the top of your pages).
con.Open either expects some DSN parameters or a database connection string to be passed within 'data_source'.
Examples, respectively :
data_source = DSN_Database, DSN_User, DSN_Password
(these 'DSN_' parameters are found/set in your DSN configuration)
OR :
data_source = "Driver={SQL Server};Server=server.domain.com;Database=project_db;uid=MyUser;pwd=MyPass;""

Resources