Changing the location of a referenced library - excel

I have a C# Library which I use in an Excel VBA project. I wish now wish to restructure my project and want to move the library to a different folder. However after removing the reference to the library and deleting all instances of the library from my computer, the References Available box for the project still shows the reference to the old library location even though it no longer exists on the computer and nothing I do seems to be able to remove that reference.
I don't know if this makes any difference, but the project is an Excel AddIn.
I had this problem back in 2019, and received a response to a question with the same title in April 2019. On that occasion the the issue was resolved by following the advise given. However this time the system stubbornly refuses to play ball.
The procedure that I was advised to follow in 2019 was:
Remove the reference
Save the File and close it
Delete the dll (in my case the .tbl) file from your computer. Do not save it anywhere.
ReOpen the file
Check if there is any reference still there. If not copy the dll to a new folder and then set a reference again. Save and close the file.
ReOpen to check if everything is OK
I was going to try code to remove the reference, but the following code did not find the reference
Sub delRef()
deleteReference ("FiskDLLlib")
End Sub
Sub deleteReference(s As String)
Dim oFs As Object, oReferences As Object, oReference As Object
Dim sFileName As String, sRefName As String, sRefFileName As String
Dim toBeDeletedRef As String
Set oReferences = Application.Workbooks("fiskAIWkBook.xlam").VBProject.References
For Each oReference In oReferences
sRefFileName = oReference.FullPath
sRefName = oReference.name
If sRefName = s Then
toBeDeletedRef = s
Exit For
End If
Next
If toBeDeletedRef <> "" Then
Debug.Print oReference.FullPath
Else
Debug.Print "No Reference found for " & s
End If
End Sub
Similarly the Watches panel didn't show the library.
I have subsequently discovered a registry key
\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\TypeLib{B22F6C9D-53E0-4D1B-9596-56AA1EA4BDBA}\1.0\0\win32
the value of which was set to the location of the reference I am trying to remove. I changed this to a reference to the new location in which I want to store my dll (.tlb) file. This at least looked like it would allow me to create a new reference in the References box but on clicking OK I got a message saying "Error in loading DLL"

I resolved my problem in the end by removing all references to the library in the Registry with a registry Cleanup tool (ReImage) before copying the library to its new directory and then reregistering it with regASM

Related

Name conflict error pops when creating reference at runtime, but not at design time

I'm having this staggering problem in creating a reference at runtime.
In short: I have an addin referenced in another addins, all created by myself and all working fine (except for some annoying popup which appears on loading Excel). As a workaround to this annoyance, I removed the existing reference to create it later, at runtime. But when I try creating the reference, it returns an "Name conflicts with existing module, project, or object library" error popup, and the reference is not created--which makes no sense, because if I create the reference at design time it works perfectly. There is no module or project with repeated name.
Now explaining a little further.
I have four kinda-complex Excel applications I'd had developed for my job. Each one is a VBA project, distributed as Excel Addins (.xlam).
Additionally, I have a fifth project with functions common to the other four. This fifth project is referenced in the other ones (via Tools -> References). So now, all I have to do is to call them as any API outside referenced function (commonProject.Function (arg1, arg2, arg3 etc)).
Unfortunately, I had some problems with a popup message (here) and the workaround seems to be referencing the fifth project in the other ones at runtime.
In order to do this, I uninstalled three of the other four Addins, remaining only one, and used the following code in its Workbook_Open event:
Private Sub Workbook_Open()
Dim strNamePath As String
Dim bolAddinIsRefered as Boolean
Dim oRef As Variant
strNamePath = "c:\etc\etc\etc\Filename.xlam"
For Each oRef In ThisWorkbook.VBProject.References
If oRef.FullPath = strNamePath Then bolAddinIsRefered = True
Next oRef
If bolAddinIsRefered = False Then ThisWorkbook.VBProject.References.AddFromFile strNamePath
End Sub
The problem is, when I used to create the reference at design time by hand, it worked mostly fine (except for the annoying popup I'm now trying to circumvent). But when I try creating the Reference at runtime, it returns an "Name conflicts with existing module, project, or object library" error popup, and the reference is not created.
I have verified the module and worksheet names and there is no duplicated one.
Does anyone have any idea how to prevent this error?
it seems after one and a half day struggling with a problem, when you ask the question on StackOverflow the solution just pops in your mind.
I'd already tried to change both projects names, even internal functions or subs resembling the same name. But I had not looked upon the FILE NAME!
As my solution is called Sisyphus, the filenames of all addins started with "Sisyphus"--"Sisyphus Common Functions.xlam", "Sisyphus DocMerge.xlam" etc.
The problem was VBA was comparing the first word in filename. I removed spaces and it worked well. Now my filenames are "SisyphusCommonFunctions.xlam", "SisyphusDocMerge.xlam" etc. and the referencing in runtime works all right.
Thank you for your time, I'll let this Question and Answer here, because it can be usefull to someone.

Do the DSOFile functions only apply to the non-binary Excel Document types?

Using Windows 10 (Build 1903 if that's relevant?) and 64bit Office 365 (probably relevant?) I've implemented a system that allows me to version control Excel VBA code.
I'm using the Workbook_BeforeSave method to check whether the current file is saved or not, and if it is saved, where it is saved to.
This works fine and will prompt the user as to whether they want to update the code contained within. I then thought that maybe I should in fact check if the code "needs" to be updated prior to prompting the user.
First off, I found the following question/solution: Using VBA to read the metadata or file properties of files in a SharePoint doc library
which I couldn't use without DSOFile.dll that I was able to install from here:
https://www.microsoft.com/en-us/download/details.aspx?id=8422
Here follows the code I have which doesn't work:
Private Function CheckTemplateIsNewerThanCurrentFile(ByVal templatePath As String) As Boolean
Dim templateName As String
Dim fso As New FileSystemObject
templateName = ActiveWorkbook.CustomDocumentProperties("TemplateName").Value
If fso.FileExists(templatePath & "\" & LocalTemplateName) Then
Dim objDSO As New DSOFile.OleDocumentProperties
objDSO.Open templatePath & "\" & LocalTemplateName, True, dsoOptionDefault
If Not objDSO.CustomProperties("LastCommitDate") = ActiveDocument.CustomDocumentProperties("LastCommitDate").Value Then
CheckTemplateIsNewerThanCurrentFile = False
Else
CheckTemplateIsNewerThanCurrentFile = True
TemplateLastCommitDate = objDSO.CustomProperties.Item("LastCommitDate")
End If
End If
End Function
And here (highlighted) is the error I receive trying to run the method above on an .xlsb file:
(FWIW: the reason for use of the .xlsb format is because we're working with 500K+ rows of data in the process we're carrying out. Yes, I know Excel is ABSOLUTELY NOT the tool for this but we're lumbered with it now)
I know I could have already tried changing the file format to .xlsm but because this file is version controlled that is a pain to do if the method is still likely to fail.
Thanks in advance,
Alex.

Injecting module into excel and run it

In VBScript I'm injecting a module into excel files and then I want to run them. The injection goes fine but when I run it says it can't find it. I've put the location in the trust center so it should trust it just fine. The module has a public sub named Run as well.
Dim XL
Set XL = CreateObject("Excel.Application")
Dim book
Set book = XL.Workbooks.Open(wkpath + "\" + wkname, 0, false)
book.VBProject.VBComponents.Import "C:\MyModule.bas"
XL.Application.Run("'" + wkname + "'!Run")
The paths and names all work out. Am I doing something wrong with this? What are my next debugging steps here.
[EDIT]
Actually it looks like some references aren't being selected now so it's getting an error about user-defined type not defined, but that's not the error that I get from VBScript. I had to do what is happening manually and then I saw that error.
So I was missing a reference but the error was pretty bogus. I figured this out by stopping my process once the excel file was open and adding in the module manually and trying to run the function. So I added the following in vbscript and it worked:
book.VBProject.References.AddFromFile "path to my xlam that has the type I use"

Overwrite file when copying into zip file using Microsoft Shell COM Library

I'm using Microsoft Shell Controls And Automation COM library from VBA. I have a zip file and I am copying a file into the zip file. The problem is that the file already exists and it throws a dialog box which says "There is already a file with the same name in this location do you want to a) Copy And Replace or b) Don't copy". I would like to programmatically say Copy And Replace (overwrite!).
I think the equivalent on the .NET framework has a documentation page at http://msdn.microsoft.com/en-us/library/windows/desktop/ms723207%28v=vs.85%29.aspx
but I have tried a variety of these.
Also, I will accept removing the original item so that the addition succeeds with no problem; sadly I could not find a delete item method.
I am using Windows 8, 64 bit edition. I'm in Excel (14) VBA (7) and the library I'm using is at C:\Windows\SysWOW64\shell32.dll
Here is head of IDL of the type library I'm talking about
// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: shell32.dll
[
uuid(50A7E9B0-70EF-11D1-B75A-00A0C90564FE),
version(1.0),
helpstring("Microsoft Shell Controls And Automation")
]
library Shell32
{
// TLib : // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
My preferred answer is the use the MoveHere method to move the old one out the way before adding. That way no dialog box is thrown. Thanks all.
Here's how you can delete a file from a zip using Shell:
Sub DeleteFromZip()
Dim fldr, zpath, itm, vrbs, vrb
zpath = "C:\_stuff\test\test.zip"
Set fldr = CreateObject("Shell.Application").Namespace(zpath)
For Each itm In fldr.items
If itm.Name = "IMG_0000322_2014.03.11.jpg" Then
itm.invokeverb "Delete"
Exit For
End If
Next itm
End Sub
This does raise a confirmation dialog though - see this link for how to avoid it:
FolderItem.InvokeVerb("Delete") without confirmation

Cannot add DLL reference with AddFromFile

I am trying to use a COM visible .NET DLL from Excel VBA. I have been successful when registering the DLL using regasm and then manually adding a reference to it via the Tools -> References menu item in the VBA Developer window.
However, I am now trying to register the DLL without using the regasm command so that the Excel file can be used on any computer without registering the DLL. So far this is what I've tried:
Dim JART_Instance As Object
Sub Initialize()
Dim RefPath As String, X As Byte
Const RefName = "JART xxx"
RefPath = Application.ActiveWorkbook.Path & "\JART\JART.dll"
With ActiveWorkbook.VBProject.References
For X = 1 To .Count
If .Item(X).Description Like RefName Then
.Remove .Item(X)
End If
Next
.AddFromFile (RefPath)
End With
End Sub
Sub PostInitialize()
Set JART_Instance = New JART.MainJobControl
End Sub
I have added a reference to "Microsoft Visual Basic for Applications Extensibility 5.3". When I run the above code I get "Run-time error '48': Error in loading DLL". I have loaded this DLL a couple times using regasm. Do I need to do something like change the GUID's used in the project and retry. I've seen code examples where this is supposed to work.
If I reference the tlb file instead of the .dll I do not get the DLL loading error. Instead I get an error whenever I try to use the JART_Instance variable saying that the reference has not been set. Even though PostInitialize gets called directly after Initialize and there is no evidence that any of the code threw an error or failed to run. If I try to put a "Stop" command in the PostInitialize function it tells me that it "Cannot enter break-mode at this time".
Any ideas, thanks.
Excel-DNA has a helper function that does this for Com Addins written on that platform.
It appears to:
load the addin
register it with CoRegisterClassObject
add it's progid to the registry
add it to the registry key HKCU\Software\Microsoft\Office\Excel\Addins
call Application.ComAddins.Update in Excel
remove all the previous registry entries
Unregister the object with CoRevokeClassObject
It would appear that once Excel has loaded the addon, it doesn't unload when the registry entries are removed and CoRevokeClassObject is called. It stays loaded until Excel closes and releases it.
So, it's doable but not easy.
Okay so I've resorted to doing a shell command to register the DLL with regasm. Here is my code:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim strWinCmd As String
Dim retVal As Double
strWinCmd = "cmd.exe %SystemRoot%\Microsoft.NET\Framework\v2.0.50727\regasm.exe /u /codebase /tlb .\JART\JART.dll"
retVal = Shell(strWinCmd, vbHide)
End Sub
Private Sub Workbook_Open()
Dim strWinCmd As String
Dim retVal As Double
strWinCmd = "cmd.exe /c %SystemRoot%\Microsoft.NET\Framework\v2.0.50727\regasm.exe /codebase /tlb """ & Application.ActiveWorkbook.Path & "\JART\JART.dll"""
Call Shell(strWinCmd, vbNormalFocus)
Call Button_Handlers.Sleep(1500)
Call Button_Handlers.Initialize
End Sub
For reference the Button_Handlers.Sleep just calls the system sleep method and Button_Handlers.Initialize does this:
Sub Initialize()
'This JART.MainJobControl is the main class in the JART DLL
Set JART_Instance = New JART.MainJobControl
'Use JART_Instance
End Sub
So basically I'm trying to register the DLL at start-up and un-register it on close. My problem is that when I open this file on a new PC I get an error in Button_Handlers.Initialize. It tells me that I'm trying to use an undefined class (JART.MainJobControl), as if the DLL wasn't referenced. If I try to reopen the file everything works fine???
The way I'm doing this is manually adding the reference to the DLL on a machine that already has it registered with regasm. I then save this excel file and transport it to a machine that hasn't had the DLL registered and try to open it and run it. I think that since the reference is already added to the excel file, alls the code has to do is register it with regasm. Does anyone know why this wouldn't work? Am I not sleeping long enough. I may post this as a separate question.

Resources