Invalid Qualifier when using System.IO.path in VBA - ms-access

I'm extremely new to vba and feel like I have been falling down at the first hurdle all morning. I'm trying to get the path of my access file by doing the following
Sub getDirectoryPath()
Debug.Print (System.IO.path.GetFullPath())
End Sub
However I get an "Invalid Qualifier" error on System when I try to run it. I've tried adding the 'System' reference but then it says IO is not found. What am I doing wrong?

VBA environment has only access to COM (and COM visible) component.
So forget about importing usual .Net namespaces.
But some Wrappers exists : [https://technet.microsoft.com/en-us/magazine/2007.01.heyscriptingguy.aspx]
For instance this works :
DataList = CreateObject("System.Collections.ArrayList")
BTW, in order to parse file full name in VBA, you can use FileSystemObject.

Related

Working DLL code fails with Run-time error 13: Type mismatch when debugging

This question is a stumper, for experts only.
We are using Visual Studio 6 to develop a complex COM Add-In for Access. When compiled, the Add-In works fine. But, when we use Ctrl-F5 to put the VB6 IDE in debug mode, Access throws a
Run-time error 13: Type mismatch
error when it tries to assign the Access Application.COMAddIns("AddInName").Object reference to an early-bound VBA variable of a type exposed in the AddInName type library.
Further information:
The Access application uses objects created by calls to the Add-In
The Add-In DLL also serves as a type library that is included in Access VBA References
The type Access requests from the Add-In is defined in the AddInName type library
In Access VBA, the failing code looks like this:
Public Function GetAddInRef As AddInName.SomeClass
Dim objSomeClass As AddInName.SomeClass
' .Object is set to a SomeClass instance in IDTExtensibility2_OnConnection
Set objSomeClass = Application.COMAddIns("AddInName").Object ' => Error 13!
Set GetAddInRef = objSomeClass
End Function
If you change the type of objSomeClass to Object, the assignment works. If you set a break on the offending line, you can do things like this in the Immediate window:
? TypeName(objSomeClass)
AddInName.SomeClass
? TypeOf objSomeClass Is AddInName.SomeClass
False
So it is saying that the class name of objSomeClass is "AddInName.SomeClass", but it is not of type AddInName.SomeClass. Madness!
Further, if you put in code that exposes the CLSID for the Access-side reference and the Add-In originated object, they both return the same GUID! So why does VBA complain that the types are different?
Does anyone have any insight into what is happening here? I would be very grateful for any help.
I'm guessing (I am no expert) it's because AddInName.SomeClass is not an object, it is of type AddinName.SomeClass. Drop the .Object off of Application.COMAddIns("AddInName").Object and I think it will work just fine. If you need it as an object for somewhere else in your code, then change your AddInName.SomeClass types to Object and leave the .Object on Application.COMAddIns("AddInName").Object and it should work.
So a colleague of mine stumbled upon the answer: Set Access and VB6 permissions to administrator! I tried it, and VoilĂ , debugging works.
For each of the following executable files, Right-click, Properties, Configuration, then check Run this program as an administrator:
Office path:
MSACCESS.EXE (or EXCEL.EXE or WINWORD.EXE ...)
C:\Program Files (x86)\Microsoft Visual Studio\VB98\
VB6.EXE
LINK.EXE
Notes:
It probably helps to develop VB6 apps using an administrative login, too.
This makes sense, because VB6 had its start in the Windows 95 era, when users were pretty much the king of their OS instance.
Caveat: this may not be a perfect solution for very complex Access forms with lots of DLL interaction, but it is much better than nothing!

Extract c function with goto or break

On C project I currently work at there is much code that uses goto and break for error handling. Break and goto are usually found inside
if (error_occured) {
LOGGER_REPORT_ERROR();
goto cleanup;
}
I tried extracting code that includes chunks like this with Eclipse CDT refactoring but it did not work automatically.
This should be theoretically possible to do this automatically if additional error code variable is created in original function and extracted function returns error code somehow.
Is there an IDE or IDE plugin for automatic refactoring that supports such function extractions already?

User defined type not defined error in ms access

I am getting error message in ms access 2003. In access the 2 dll references are already added.
GeneralLink
CommonLink
I have to remove "CommonLink" reference from access project. I created one project "MyCommonLink" which is same as "CommonLink". When I remove "CommonLink" reference & adding new "MyCommonLink" reference while compiling it gives me "User - defined type not defined" error. Without any line of code highlighting.
Also I was checked that both project's code are same & dll files are registered.
Can anybody help me for how do I find for which object I am getting this error or which object was remain unreferenced?
could someone help me please? Thank you so much in advance.
Do a search in the code pages for "GeneralLink". There must be an object being declared somewhere that is fully qualified starting with GeneralLink (e.g. Dim x As GeneralLink.SomeObject). Or maybe there is a Public Enum in GeneralLink that is fully qualified somewhere (e.g. If x = GeneralLink.MyEnum.Item1 Then)

How can I save a global variable value after dynamically loading a reference?

I have a Access 2003 database that will dynamically load MDB databases as a library reference. The reason for this is this database is a menu front-end for 60+ application databases. Rather than deal with permanently referencing all these databases, the menu front-end will dynamically reference what is needed when the user makes a selection. I was working on moving this database to Access 2010 and creating a custom ribbon. I started using the technique from here to capture the ribbon object in a global variable when the ribbon loads. I then ran into the problem where I could verify the code was running and the global variable was correctly being assigned the ribbon reference but after the database would run through it's startup routine, that global variable would get reset to Nothing.
To verify what was going on, I created a simple database for testing. In this database, I had a module with a global variable:
Public obj as Object
I then had a function like this:
Public Function SetObj()
Set obj = Application
Debug.Print "IsNothing=" & (obj Is Nothing)
References.AddFromFile "Test.mdb"
Debug.Print "IsNothing=" & (obj Is Nothing)
End Function
Obviously, in my code, "Test.mdb" refers to an actual file. If I run this code, Debug.Print gives me "IsNothing=False" for both instances, but after the function finishes and if I wait a couple seconds, Debug.Print will give me "IsNothing=True". If I comment out References.AddFromFile, Debug.Print gives me "IsNothing=False" no matter how long I wait.
It makes sense to me that since Access has to re-compile the VBA code after loading the library that all global variables are reset. I've experimented with moving the global variable into a class, but since I then need a global variable for the class, the class variable then gets reset instead. I tried using a local variable in the function to save the value of the global variable, but it looks like Access waits a couple seconds after the code is finished running to do the re-compile, so that doesn't work either. Does anyone have any other ideas to accomplish this?
I don't really know if this will solve the problem for this kind of reference, but in general, I don't use public variables for this kind of thing, but instead use a STATIC variable inside your function. It would be something like this:
Public Function SetObj() As Object
Static obj As Object
If (obj Is Nothing) Then
Set obj = Application
End If
Set SetObj = obj
End Function
Then you'd just use SetObj as an object for using your application. In a production app, you'd need tear-down code, too, but I've omitted that here.
I doubt this helps, but your code struck me as rather inefficient and incomplete.
I figured out a solution to my problem, and thanks #David-W-Fenton, as your answer gave me the idea. I use your approach in a library database for caching frequently-accessed values that are stored in a table but don't change after the initial startup. Those values aren't lost every time the references change, and that's when the light bulb lit up.
The solution is to put the global variable in a library database. Access looks to be only resetting global variables in the database that the reference is being loaded into - which makes sense after thinking about it. So since the library database isn't the one being re-compiled, it doesn't get it's global (or private or static) variables reset.
What I ended up doing was creating a new module in an existing library database. It has a private variable and two methods - one to set the variable, one to retrieve the variable value. In my menu front-end database, when the ribbon loads and calls my callback function, rather than saving the ribbon object in the front-end database, I pass it to this module for saving. I now no longer lose that ribbon reference whenever new databases are added to the library references on the fly.

Use IFilter from VB

I am using VBA (in Access 2003) and I'd like to use the IFilter mechanism to extract the textual contents of files. I found some some nice C++ sample code which makes it look relatively easy, but at the moment I can't even get the DLL call to LoadIFilter to work:
Declare Function LoadIFilter Lib "query.dll" (ByVal pwcsPath As String, _
ByVal pUnkOuter As Object, ByRef ppIFilter As Object) As Integer
Public Sub DocEx()
Dim ifilter As Object
Dim hresult As Integer
hresult = LoadIFilter("C:\temp\test.txt" & Chr(0), Nothing, ifilter)
Debug.Print hresult
End Sub
hresult is always E_FAIL (= 16389).
Is it my syntax for the DLL that is incorrect, or something else?
EDITED TO ADD: In the end I didn't solve this problem. But since my only purpose is to hack up an internal script, it is sufficient for me to to just call the FiltDump.exe tool that comes bundled with the Microsoft Platform SDK and parse its output. (A bit clunky though, especially since FiltDump.exe insists on printing error messages to stdout instead of stderr!)
LoadIFilter() is meant to do a lot of work - it looks up the registry to find which IFilter to load, then loads it (most likely calls CoCreateInstance() for just found class id). Anything could go wrong - there could be no mapping in the registry from .txt extension to the class id or the COM server for that class id could fail to load.
Your best bet is to use Process Monitor to see if it finds what IFilter to load and if at least it tries to load it.