We have a fairly large Access front-end application that has been running on Access 2010. It makes extensive use of ADO recordsets for accessing data on our SQL servers, and frequently uses the UniqueTable form property.
We are looking to move the whole office to Office 2013 early next year, but during testing we have found that Access 2013 will not work with our code that uses UniqueTable. Any attempt to set UniqueTable results in the error message:
You entered an expression that has an invalid reference to the property UniqueTable
The following code works on Access 2010 but encounters above error on Access 2013 when attempting to set UniqueTable:
dim conn AS New ADODB.Connection
conn.ConnectionString = "DATA PROVIDER=SQLOLEDB;DATA SOURCE=server1;DATABASE=database1;Integrated Security=SSPI;"
conn.CursorLocation = adUseServer
conn.Provider = "MSDataShape"
conn.Open
Dim cmd As New ADODB.Command
cmd.ActiveConnection = conn
cmd.CommandType = adCmdText
cmd.CommandText = "SELECT TOP 10 * FROM Members WHERE MemberID IS NOT NULL"
cmd.Execute
Dim rs As New ADODB.Recordset
rs.CursorLocation = adUseClient
rs.Open cmd, , adOpenKeyset, adLockOptimistic
Set Recordset = rs
UniqueTable = "Members"
While searching for a solution I have found only a couple of other cases where this error has been mentioned, and no solutions so far.
I'm afraid that you may be out of luck on this one. I was able to recreate your issue: code that successfully set a form's UniqueTable property in Access 2010 failed in Access 2013 with the same runtime error message.
A Google search for microsoft access uniquetable yields a number hits, and the vast majority of them refer to the use of that form property in an ADP. ADP support was completely removed from Access 2013, so my guess is that UniqueTable support was removed along with it. (The IntelliSense feature within the Access 2013 VBA editor still offers Me.UniqueTable as a property of a Form object, but Access 2013 apparently does not allow us to set a value for it at runtime.)
You can set Recordset.Properties("Unique Table"), e.g.:
rs.Properties("Unique Table") = "members"
see ADO Dynamic Properties
You can still use Me.UniqueTable to make sure your select join into a ADO recordset is working while delete data from many-table. Also me.ResyncCommand is working from VBA code, not any more as a property in form design, but behind the form in the code like Form Load.
Related
I'm trying to take names of all windows user accounts. my code is working but it prints unnecessary user account also,
here is the code I'm using,
Dim query As New SelectQuery("Win32_UserAccount")
Dim searcher As New ManagementObjectSearcher(query)
For Each envVar As ManagementObject In searcher.[Get]()
Console.WriteLine(envVar("Name"))
Next
Output:
Administrator
DefaultAccount
Guest
Sam
WDAGUtilityAccount
Sam is the only user account I created on this PC. I can assume Administrator and Guest accounts come as default with windows. But DefaultAccount and WDAGUtilityAccount accounts are extremely unnecessary for printing in here. How can I prevent those unnecessary accounts printing from this code
As the Jimi's suggestion, I have updated my code by using Disabled property.
Win32_UserAccount class
Dim query As New SelectQuery("Win32_UserAccount")
Dim searcher As New ManagementObjectSearcher(query)
For Each envVar As ManagementObject In searcher.[Get]()
If Not envVar("Disabled").ToString.ToUpper.Equals("TRUE") Then
Console.WriteLine(envVar("Name"))
End If
Next
I have this connection string in library to connect to sql server.
Function db()
connectionnameDev = "Description=connect to hh dev;DRIVER=ODBC Driver 13 for SQL Server;SERVER=xxx;UID=xxx;PWD=#xxx%;Trusted_Connection=No;APP=UFTBase;WSID=L-XP9550-xxx;"
Set objConnection = CreateObject("ADODB.Connection")
Set objRecordSet = CreateObject("ADODB.Recordset")
objConnection.Open connectionnameDev
End Function
This library is shared across the team. Now, everyone has access to the credentials. Each person has own database credentials. When they run scripts, they should run with their own credentials. What would be the correct approach to protect the database credentials so each person can run scripts with their own credentials?
If this is part of a framework, here's one idea we used in one of the teams I worked at. Our framework loaded multiple function libraries from ALM, but there was one function library that was always locally referenced, called "Load_myCredentials.qfl".
Each team member can have their credentials saved as global parameters/variables in a qfl file in their local C: drive, and the framework can just load this as a function library. Then the password becomes available throughout the test, yet the password does not become visible in any results. All you have to do is change the first line of your function db(), and parameterize the password part.
I have an application which has been upgraded from Visual Studio 2010 (running on Windows Server 2003) to Visual Studio 2013 (now running on Windows Server 2008). One aspect of the app allows the user to upload an xlsx sheet to a folder, and a script validates its contents.
I have this method:
Private Function GetValuesFromExcel(ByVal strFileIn As String) As DataSet
Dim ds As DataSet = New DataSet
Dim strConn As String = ""
Try
If strFileIn.ToLower().EndsWith(".xlsx") Then
'This one is good for files that are saved with Excel
strConn = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source='" + strFileIn + "'; Extended Properties=Excel 12.0 Xml;"
Else
strConn = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source='" + strFileIn + "'; Extended Properties=Excel 8.0;"
End If
Dim conn = New OleDb.OleDbConnection(strConn)
conn.Open()
Dim dtExcelTables As DataTable = conn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, New Object() {Nothing, Nothing, Nothing, "TABLE"})
Dim strExcel As String = "select * from [" + dtExcelTables.Rows(0)("TABLE_NAME").ToString() + "]"
Dim myCommand = New OleDb.OleDbDataAdapter(strExcel, strConn)
myCommand.TableMappings.Add("Table", "table1")
'myCommand.Fill(ds, "table1")
myCommand.Fill(ds)
conn.Close()
Catch ex As Exception
DBUtils.WriteToLog("Error", "GetValuesFromExcel", ex.Message, Security.GetCurrentUser())
Throw ex
End Try
Return ds
End Function
On conn.Open(), it throws an error. Specifically, the most excellent error of, "Unspecified Error". Very helpful.
We are using Office 2007, and I have checked to make sure that the 32-bit Access Database Engine redistributable is indeed installed.
What the heck is the problem?
I'll noodle about this a little bit, pretty unlikely you are going to get a "push this button to solve your problem" answer.
The error you are getting is E_FAIL, a generic COM error code. Commonly used by Microsoft software when it does not have a decent guess at the underlying reason for a failure. And guessing at a more specific one is too risky, sending their customers into a rabbit hole. This is a liability of COM in general, it does not directly support exceptions, only error codes. So a major feature that's lost is the stack trace, a cue that can give a lot of information about the specific layer in which the error was detected.
The only real way to deal with them is by a process of elimination. Which is feasible here, the code fails early. The only thing that you can do wrong is supplying the wrong connection string, providing bad data or running the code in the wrong execution context. Ticking off the common mistakes:
Bad connection string syntax. Not your problem.
Invalid path for the file. Not your problem, produces a good message
File is not actually an Excel file. Not your problem, produces a good message
Trying to run this in a 64-bit process. Not your problem, good message.
The not so common mistakes that are not easy to eliminate:
Program runs as a service with an account that has accessibility problems. Eliminate that by testing it with a little console mode app.
The file is an .xlsx file but it is subtly corrupted. Eliminate that by testing with a set of other .xlsx files.
Which does leave the most likely reason:
The OleDb provider is not correctly installed. Classically also the common reason for Microsoft code giving up with a generic error like E_FAIL. Hard to diagnose of course, you might get somewhere by using SysInternals' Process Monitor and comparing a good trace with the bad trace. Good to discover a missing file or registry key. Do keep in mind that installing the 32-bit Access Database Engine redistributable after installing Office is not a good idea, it was meant to be used only on machines that don't have Office available. You'll have to spin the re-install wheel of fortune wheel at least once.
Perhaps the misery is also a good reason to give up on these providers. The EPPlus library is getting pretty good reviews, also scales quite well on a server.
I'm going to second Hans' idea of possibly giving up on these providers and looking into alternatives.
I recently went through a similar issue to that which you are facing. I developed a solution that worked well on my machine, but didn't on others due to them not having the requisite drivers installed.
My situation was a Winforms app that would be installed on clients machines and I would have no control over what external providers (ACE, JET etc) were installed. We also have no idea of what versions of Office they had installed. It was either we provide a convoluted solution that was capable of using whatever driver was installed...or look for alternatives.
We chose the latter, and went with Excel Data Reader. After about 30 mins, the solution now works without relying upon the configuration of the machine it is deployed to.
My code needed to simply read data from an Excel file (generated from an SSRS report) into an in memory DataTable for a bit of data comparison. The method we ended up with shows how simple it was to achieve;
/// <summary>
/// Read data from MS Excel saved as an export from their SSRS reports.
/// This method uses ExcelDataReader <link>https://github.com/ExcelDataReader/ExcelDataReader</link>
/// to avoid dependencies on OleDb Jet or ACE drivers. Given we can't control what is installed on
/// client machines, we can't assume they'll have the correct drivers installed, and therefore we'll
/// make use of ExcelDataReader.
/// </summary>
/// <param name="filename">Filename to the path of the Excel (xls or xlsx) file.</param>
/// <returns>DataTable containing the required data or null if no data is found.</returns>
private DataTable ReadDataFromUsingExcelReader(string filename)
{
DataTable returnval = null;
DataSet result = null;
using (FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read))
{
if (filename.EndsWith("xls", StringComparison.OrdinalIgnoreCase))
{
using (IExcelDataReader excelReader = ExcelReaderFactory.CreateBinaryReader(stream))
{
result = excelReader.AsDataSet();
}
}
else if (filename.EndsWith("xlsx", StringComparison.OrdinalIgnoreCase))
{
using (IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream))
{
result = excelReader.AsDataSet();
}
}
}
returnval = result != null && result.Tables[0] != null ? result.Tables[0].Copy() : null;
return returnval;
}
Okay, so I figured out the issue as it pertains to my situation... I stuck with the ACE.OLEDB drivers, because I knew I could make them work in this scenario. Also, I figured it was something stupid and small. It was.
The xlsx sheet gets written into a folder called 'admin->excel_uploads'. Turns out that I had identity impersonate set to true in my config file. The service account I was running on did not have full read/write privs. That solved why it wasn't working locally, because as soon as I turned off impersonation, it worked great. Then on deploy, I just needed to set up permissions to the service account I was running under.
I am opening Lotus files to get data from them. How do I instantiate the Lotus application without using GetObject? I have a reference to "Lotus 123". I am using Lotus SmartSuite 97.
This code works OK but it seeems I should be able to instantiate the Lotus application directly instead of using GetObject.
'get LotusWin
Dim LotusApp As Lotus123.Application
Dim wb As Lotus123.Document
Set wb = GetObject("C:\Temp\TestCopy.WK3", "Lotus123.Workbook")
Set LotusApp = wb.Application
LotusApp.Visible = True
wb.Activate
I tried to use Dim LotusApp As New Lotus123.Application but it give a compile error: Invalid use of New keyword.
I tried to use Dim LotusApp As New Lotus123 but it give a compile error: Expected user-defined type, not project.
I am using Excel VBA as my platform to run the code, but this is not an Excel question so please don't suggest adding an Excel tag.
Also I'm not interested in converting files to Excel.
How do I instantiate the Lotus application without using GetObject?
GetObject() returns a reference to an object provided by a COM component, in your case Lotus123.
As you are communicating with Lotus123 via COM, and Lotus123 apparently does not support the "As New" syntax (which wasn't properly supported even in VB6, and Lotus123 is way older) I see no alternative to using GetObject().
we have msi installer build with MSI Factory with a couple of custom action scripts (lua & vbs). one of the scripts try to get a custom property from package and write it to file after successfully installation. this custom property is added to downloaded package via MSI.ChangeMSIProperty in asp.NET handler when download was requested with parameters. problem is, that property change brokes the signature of msi file, so we try to add some data to the msi filename. now I need to change that vbscript to handle this. but I can't get the installers filename.
Dim data, tokens
Dim fso, f
Dim setupExeFilename, setupExeFilenameParts
data = Session.Property("CustomActionData")
tokens = Split(data,"|")
Set fso = CreateObject("Scripting.FileSystemObject")
Set f = fso.CreateTextFile(tokens(0) & "\\data.txt", True)
if tokens(1) = "_DEFAULT_" then
setupExeFilename = Session.Property("SETUPEXENAME")
setupExeFilenameParts = Split(data,".")
f.Write setupExeFilenameParts(UBound(setupExeFilenameParts) - 1)
else
f.Write tokens(1)
end if
f.Close
I found Session.Property("SETUPEXENAME") somewhere but doesn't work for me. I search for some property in Session, Session.Property, Session.ProductProperty, Installer but no luck yet. Installer object is present as I try, but no property returns what I need.
If not Installer is nothing then
msgbox "Installer ok"
msgbox Installer.version
end if
is it possible to get the installer filename?
The OriginalDatabase property has what you are looking for. However your reference to CustomActionData tells me your custom action is running in the deferred context. You won't have access to this property. Whatever custom action that is running in immediate and serializing your CustomActionData property will have to obtain this property and put it into CustomActionData.
You should be warned that VB/JScript custom actions are famous for their fragility. You mention SETUPEXENAME so I assume you are using InstallShield as this is an InstallShield property. I'd suggest using InstallScript, C/C++ or C# instead. If you choose InstallScript, I have a sample CustomActionData serialization/deserialization pattern over on InstallSite.org. If C#, it's built into the Microsoft.Deployment.WindowsInstaller library's Session class.