Link to home
Create AccountLog in
Avatar of Blue Fin
Blue FinFlag for United States of America

asked on

Getting Runtime Error 91: Object variable or With block variable not set in Access

Hi,
I am getting "Runtime Error 91: Object variable or With block variable not set. In my opinion the issue is due to the Object: CreateObjectNet is set to nothing. I have attached a .pdf file which has the code shown.

Help and guidance will be appreciated. 


CreateObjectNet Set to Nothing.pdf
Avatar of Martin Liss
Martin Liss
Flag of United States of America image

I don't even know how to spell .Net but what is MyCreateObject? Shouldn't it just be CreateObject?
Avatar of Blue Fin

ASKER

Thanks Martin for your reply.

No it not a workbook the code is part of vba Access 2019 (part of Office 365 Suite).

And to your earlier question MyCreateObject is optional keyword that can be used during declaration to implicitly enable object creation. Here I am trying to assign a object reference. 


The error message says, that there is no defined Object.
The reason is, that - Martin Liss already said this - that you create an external object, and the command to do this is CreateObject.

https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/createobject-function

A DLL in VBA is usually called by its classname, how it is registered in the registry as CLSID. 
@Bambi,@Martin
The fact that the same code works perfectly on two different machines perplexed me...I have attached a .pdf document with code snippets from both machines so that the difference can be observed. Code.pdf
Does the problem machine(s) run 64bit and the good machine(s) 32bit or vice versa?
Martin,
Machine A on which the code is failing have Access 2016 - 32 Bit

Machine B on which the code is working have Access 2010 - 32 Bit.

I have also attached a screenshot for the two.Access Ver Info.pdf
Based on that I'm tempted to say that something was lost between Access 2010 and Access 2016, but that's probably not the case and so the only thing I can suggest is that if the problem is limited to just one machine then try things on that machine like rebooting or reinstalling Access.
Martin,
I have another Machine with Access 2016 MSO (32 bit) and NOT Microsoft Access 365 MSO (32 Bit) as on Machine A the code is also working fine on that machine since the Microsoft Access version number is the same i.e. 16.

Just thinking out loud should I repair the Office installation? 


If you back it up first it can't hurt.
Just did a re-install but still the same issue...one thing I want to mention is that this code is referencing a .dll file.

I have read that sometime difference in .NET framwork installed on a machine also matters and I checked that the versions are same on both machine.
Okay, sorry but I can't think of anything else.
@Martin..., stay here :-)
@Blue Fin
MyCreateObject is optional keyword that can be used during declaration ...
1.) OK, can you show me please the reference? In Object Browser or what ever you can find?
I would say that this is either just a function or it comes from any other reference.
But it is definitely not part of any Office VBA. At least all my Office versions doesn't show any valid reference.

User generated image


2.) You use conditional compilation and reference the WIN64 to point to nloader64.dll or nloader.dll and you reflect to CurrentProject.Path. That means, the nloader.dll (32 Bit Office) or nloader64.dll (64 Bit Office) has to reside in the same folder than the database.

As we can not see what is behind "MyCreateObject", we can not really tell you what is happening in this procedure, but you may step with F8 through your code and see, what is going on, especially where CurrentProject.Path points to and if the DLLs reside there. 

stay here :-)
Okay.

If you Google MyCreateObject you'll get a bunch of hits so it is a real thing. One of the hits is this one which may not apply in your case but the last post says that that person's problem was fixed by reinstalling the  .NET Framework.
@bambi
Please see attached .pdf MyCreateObject.pdf
You are right is a member (function)

On your point # 2, yes both the .dll (32 Bit and 64 Bit) are in the same folder (that is a requirement). I did step into the code please see .pdf Code1.pdf

As you can see in the Code1.pdf file CurrentProject.Path points to location where the referenced .DLLs are stored.

@Martin,
Your recommendation is to re-install .NET Framework...
Your recommendation is to re-install .NET Framework...
Yes, and as long as you make a backup first it can't hurt to try it.
@Martin
This is very strange issue, I just tested the code on a new machine which also has Office 365 i.e. same version as in the Machine (laptop) with issues and the codes runs fine...!!!

OK I will re-install the .NET Framework to the latest version available and post back.
OK, we narrow down the issue...
Please post pictures and codeblocks, and not just PDF, it makes the thread unreadable.
You can just copy and paste it into here.

So if I interpret your pictures in the right way, you have a module called NetLoader, where you declare the 4 methods including MyCreateObject and LoadLib...., they point to nloader.dll (following your Object Broser)

Inside your code, you use the LoadLib to check if either nloader.dll or nloader64.dll is loaded?
Doesn't make sense to me to check a static declare against a version dependend DLL...
Either you have declared the correct DLL or it will fail anyway. You just hit the error with the hammer and set the object to nothing.

But nevertheless interesting what LoadLib delivers back as well as the values of loaderDLL and bsIsLoaded

An then you call the MyCreateObject inside that static declared DLL to load a class Pmerge.Pmerge inside the Pmerge.dll library.

So far for clarification.

So lets assume the nloader.dll is loaded and declared with the correct version, you use a 32 Bit Office and your code reaches the part of the MyCreateObject....

My next question would be, where these DLLs coming from, like Martin I found a few rare links but nothing really usefull.
A DLL can be, but need not to be connected with NET Framework, and because I can not sort them into any direction, I can not tell you if reinstalling NET Framework may help or not. Even it is not clear which version of NET Framework, maybe 3.x or 4.x. They arenot compatible to each other, so if you need one of them, you have tofind out which one your need. If the DLL reflects to NET 3.x, what is noit installed by default on newer systems, it will fail, even 4.x is installed.
 
You may search the registry, if you can find Pmerge.Pmerge or only Pmerge, if there are differences between working and non working clients. If you call a Class inside a library, it should be registered with a CLSID, nevertheless it is possible to hook blind into a DLL without any registration.
The other option is also possible, that the DLL is registered, but with a different path.

At the end, you have to follow the instructions of the source of this DLLs as nobody else can tell you, what the libraries are doing and how they work and what they need. 



@bembi
I appreciate your response.
I am working on that machine remotely so as soon as I get access to it I will definitely post the code blocks as you mentioned.

I think it is better to give a little back ground of the DLLs and why they are being used in Access database:

I needed a way to merge more then one pdf file in a folder without using a "third party software" so on another forum a very helpful gentleman provided his tested (and tweaked) .NET Library for processing PDF files taken from PDFSharp and NetLoader module.

The instructions/information to implement these .DLLs was as follows:

1. Download and save them in the same folder where your Front End (FE) Database file is stored.
2. Import the NetLoader into your FE DB
3. Import Module1 (also provided) which I need to call within my vba code when a user click a button to combine the pdf file into one file. Need to make few changes such as updating with the paths of the PDF files located in my system

So the program flow is follows:

1. User Click a button to combine the pdf file into one:
2. It takes the program to execute code in Module1 below:

Sub TestMerge2()


    Dim MyPdf     As Object
    Set MyPdf = CreateObjectNET("Pmerge.dll", "Pmerge.Pmerge")

   MyPdf.Add CurrentProject.Path & "\a.pdf"
   MyPdf.Add CurrentProject.Path & "\b.pdf"
   
      ' set output file to merge above list to
   MyPdf.OutPutDoc = CurrentProject.Path & "\ab.pdf"
   
   'MyPdf.CreatePageNumbers = True


   MyPdf.Merge    ' merge the files
    
      
End Sub

Open in new window


3. The following line of code takes the program control to NetLoader Module
Set MyPdf = CreateObjectNET("Pmerge.dll", "Pmerge.Pmerge")

Open in new window

4. The NetLoader Module code is below:
Private Declare PtrSafe Function LoadLibrary Lib "kernel32" _
Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr

   #If Win64 Then
       Private Declare PtrSafe Function MyCreateObject Lib "nloader64.dll" (ByVal strDll As String, ByVal strClass As String) As Object
   #Else
       Private Declare PtrSafe Function MyCreateObject Lib "nloader.dll" (ByVal strDll As String, ByVal strClass As String) As Object
   #End If

'Private Function LoadLib(strDll As String) As Boolean
   
   Dim s             As String
   Dim blRet         As Boolean
   Dim hLibDynaPDF   As LongPtr

   On Error Resume Next
   
   LoadLib = False

   hLibDynaPDF = LoadLibrary(CurrentProject.Path & "\" & strDll)
   If hLibDynaPDF = 0 Then
      ' Our error string
      s = "Sorry...cannot find the " & strDll & " file" & vbCrLf & _
      "Please ensure that the " & strDll & " file is placed in the same folder as " & CurrentProject.Path
      MsgBox s, vbOKOnly, "MISSING " & strDll & " FILE"
      LoadLib = False
      Exit Function
   End If
   
   ' RETURN SUCCESS
   LoadLib = True


End Function

Public Function CreateObjectNET(strDll As String, strClass As String) As Object


   Static bIsLoaded        As Boolean     ' local static - for one time load
   
   Dim loaderDLL           As String      ' use x64 or x32 .net loader
   
   #If Win64 Then
      loaderDLL = "nloader64.dll"
   #Else
      loaderDLL = "nloader.dll"
   #End If
   
   If bIsLoaded = False Then
     
      If LoadLib(loaderDLL) = False Then
         Set CreateObjectNET = Nothing
         Exit Function
      Else
         bIsLoaded = True
      End If
   End If
   
   Set CreateObjectNET = MyCreateObject(CurrentProject.Path & "\" & strDll, strClass)
   
End Function

Open in new window

5. The following line of code takes back the program control to Module1
 Set CreateObjectNET = MyCreateObject(CurrentProject.Path & "\" & strDll, strClass)

Open in new window

 Module1 codes starts to execute from:
   MyPdf.Add CurrentProject.Path & "\a.pdf"
   MyPdf.Add CurrentProject.Path & "\b.pdf"
   
      ' set output file to merge above list to
   MyPdf.OutPutDoc = CurrentProject.Path & "\ab.pdf"
   
   'MyPdf.CreatePageNumbers = True

   MyPdf.Merge    ' merge the files
        
End Sub

Open in new window

I am getting Runtime Error 91 at the bolded line in Module1 code above.

6. Netloader loads the required .dll files which uses PDFSharp class libraries.

7. The PDFSharp .NET Library for processing PDFs provide a Pmerge Class which can be used to merge PDF files in a specific folders. The .DLL were already tweaked and ready to use. The ONLY modification required was as I mentioned above to recompile the NetLoader module on your machine and place the .DLLs in the same folder of your FE database.

The .dlls provided was compiled in 4.0 with a note that they will work seamlessly with PCs with .NET Framework Versions 4.0 and upward installed. That was indeed the case until I tested this code on a Machine A where the code failed and was giving me Runtime Error 91.

Again thanks for looking into the issue. 


OK, now I understand a bit more...
What I can see here is...(nevertheless is seems to work on some clients...)

Private Declare PtrSafe Function LoadLibrary Lib "kernel32" _
Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr

   #If Win64 Then
       Private Declare PtrSafe Function MyCreateObject Lib "nloader64.dll" (ByVal strDll As String, ByVal strClass As String) As Object
   #Else
       Private Declare PtrSafe Function MyCreateObject Lib "nloader.dll" (ByVal strDll As String, ByVal strClass As String) As Object
   #End If
 
...
Dim hLibDynaPDF   As LongPtr


Open in new window

LongPtr on Win32 is a long value while on 64 Bit a LongLong. It is not an own datatype than rather a Pointer, which can be converted by vba. LoadLibrary delivers a handle, but they are long values in 32 Bit environments.
PtrSafe is / has to only used in 64 Bit environments.

So the correct (or more save) declaration would be

#If Win64 Then
       Private Declare PtrSafe Function MyCreateObject Lib "nloader64.dll" (ByVal strDll As String, ByVal strClass As String) As Object
       Private Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr
Dim hLibDynaPDF   As LongPtr

#Else
       Private Declare Function MyCreateObject Lib "nloader.dll" (ByVal strDll As String, ByVal strClass As String) As Object
       Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Dim hLibDynaPDF   As Long

#End If

Open in new window

See
https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/ptrsafe-keyword

The point is, that you can use wrong declarations with the windows API as long as the values are not overwriting memory. If you overwrite a declared value in memory, the result will be an memory exception, the application will crash.
 
The second point is, that a wrong declaration my force windows to use address space what is not addressable by 32 Bit applications. In that case you doesn't get a valid value back.

To avoid both options, you have to take care about the correct declarations, otherwise you do not have any control, what windows is doing, it may work or even not.

If the libraries are compiled for Net 4.x Framework, it may be an option to reinstall / repair the Net Framework, but seldom seen issues with the 4.x version.

I am getting Runtime Error 91 at the bolded line in Module1 code above.
I would assume, also the PDF files are existing in the Project Path, right?
 
Thanks Bembi for such a detailed response, I tested the updated declaration code given by you but I am getting a Compile error: Ambiguous name detected LoadLibrary on the following line of code:

Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long

Open in new window


Note: I have tested the code on good machine.  

Since I still have to get access to the machine remotely to debug further.

As I mentioned it to @Martin Liss earlier that I tested this code on a new machine with Office 365 (Access 32 Bit) and same .Net Framework as the machine with error and the code runs without any issue...this is what making me confuse...apart from obvious my lack of knowledge on the inner workings of windows APIs...

ASKER CERTIFIED SOLUTION
Avatar of Bembi
Bembi
Flag of Germany image

Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
See answer
Thanks @Bembi, appreciated your feedback...I will follow your suggestions and post back my findings.