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.
Related
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!
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.
I have an Access app, developed in Access 2013 in multi-user env, uses Excel automation to export and format an Excel file.
The normal Office/Excel 2013 (15.0) references have been made and all works well on Office 2013 machines. Does not play nicely on 2010 machines.
Using a 2010 machine, I replaced the 15.0 references with 14.0 references, and the app is happy on 2010 and 2013 machines. Upon next edit/update on my 2013 machine the 15.0 references return.
Any suggestions to more conveniently develop/operate in this multi-version environment?
Thanks!
The overall solution to this issue is to use late binding. The downsides to late binding are
Dim xlApp As Object means that we don't get any IntelliSense for xlApp, and
related constants like xlEdgeTop are not defined without the associated Reference
These issues can be mitigated by using conditional compilation in the VBA project. For development, add the required Reference to the project and define a conditional compilation argument
which you can use in your code like this
Option Compare Database
Option Explicit
Public Sub WorkWithExcel()
#If LateBinding Then
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
#Else
Dim xlApp As Excel.Application
Set xlApp = New Excel.Application
#End If
Debug.Print xlEdgeTop
End Sub
To avoid clutter, I would be inclined to keep the constants in a separate Module like this
Option Compare Database
Option Explicit
#If LateBinding Then
Public Const xlEdgeTop = 8
#End If
When the code tweaking is complete, remove the Reference, set the LateBinding argument to "True" (LateBinding = -1) and compile the project. Add any constants you've missed (there always seems to be one or two) and when it compiles without the Reference you should be good to deploy.
For the next development session, set LateBinding back to "False" (LateBinding = 0) and add the Reference back in.
In csharp or vb.net we use the using statement for reasons that we know: One can open the database and close it automatically without writing it explicitly.
I would like to do the samething in VBA
how to do it?
Are all VB.NET statement/keywords/ available in VBA ?
how to tell if a given statement is(was) known in VBA ? Is it there a library(glosary) of all VBA statements/keyword/operators ?
c#
using(var db=new MyDbContext()){
//do work here
}
vb.net
Using s = New MyDbContext()
'--..do work here
End Using
Answering just your first question, as you've hinted, Using is just syntactic sugar for calling Dispose() on an object instance which implements the IDisposable interface.
It is equivalent to
Dim s as MyDbContext
Try
s = New MyDbContext()
// ...
Finally
s.Dispose()
End Try
Since VBA doesn't support the Using sugar, and in the absence of structured Try..Catch exception handling, you'll need to explicitly call Dispose() on all paths which control the lifespan of the object (MyDbContext in your case). In which case you may as well have just used .Close()
There is no VBA equivalent to the Using statement.
The VBA developer documentation provides samples and even downloadable offline versions of the VBA documentation.
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?