Object Library not registered - vba

I am using Access(2007) vba to process an Excel(ACCDB) workbook on a Sharepoint 2007 document library. In the process, I update two properties using the ExcelWB.ContentTypeProperties() proerty. It's been working fine literally for years. Today, it stopped working. It throws a "Object Library not registered" error. Research seems to suggest I've somehow gotten an old DLL for Excel registered, and the interface is using an old DLL that doesn't support the property.
My libraries are all found, no changes were made (by me...) in the last month to the machine. It's a client machine, so I can't speak for MS updates, etc. that were made. How can I fix this? It's literally got my client sitting on her hands, unable to work.
Dim xlApp As Excel.Application
Dim xlWB As Excel.WorkBook
Dim xlSH As Excel.Worksheet
Dim xlRA As Excel.Range
Dim bValidWorkbook As Boolean
Dim lngTrueHighestRow As Long
Dim strWorkbookName As String
WorkbookMessage , 3 'Clears the message queue
bValidWorkbook = True
strNewTimesheetStatus = "Rejected"
Set xlApp = New Excel.Application
xlApp.visible = False 'Don't let the workbook be shown
Set xlWB = xlApp.Workbooks.Open(URL) 'Open the workbook
lngCurrentVendorID = ParseVendor(strCurrentVendorName) 'Sets up the vendor recordset and the Labor rate Recordset. If it returns 0, it couldn't find the vendor
If lngCurrentVendorID = 0 Then
bValidWorkbook = False
WorkbookMessage "Workbook Rejected -- Vendor could not be validated"
GoTo ExitWorkbook
End If
'
' If the workbook is read-only, we can't proceed
'
If xlWB.ReadOnly Then
bValidWorkbook = False
WorkbookMessage "Workbook Rejected -- Workbook is read-only state"
GoTo ExitWorkbook
End If
Set xlSH = xlWB.Worksheets(1) 'Must be the first worksheet in the workbook
strWorkbookName = xlWB.NAME
Set xlRA = xlSH.UsedRange 'xlRA is the range of cells in the first workbook that are "USED"
strSheetArray = xlRA 'This sets an array of variants to the two dimensional range xlRA
xlRA.EntireRow.Hidden = False 'Unhides all rows to prevent misunderstandings.
...
...
...
...
If Not xlWB.ReadOnly Then
xlWB.ContentTypeProperties("TimesheetStatus") = strValidateWorkbook***
xlWB.ContentTypeProperties("OverrideStatus") = strNewOverrideStatus
xlWB.Save
End If

Related

Open workbook if not already open, if already, then get that reference

Ive a scenario to do some changes in a workbook in another workbook path. But the question is I need to check whether the workbook already open or not. If not I need to get that opened instance to a workbook variable.
Here is the code Im using for checking whether workbook open or not and then the code for opening
Function IsFileOpen(fileFullName As String)
Dim FileNumber As Integer
Dim errorNum As Integer
On Error Resume Next
FileNumber = FreeFile() ' Assign a free file number.
' Attempt to open the file and lock it.
Open fileFullName For Input Lock Read As #FileNumber
Close FileNumber ' Close the file.
errorNum = Err ' Assign the Error Number which occured
On Error GoTo 0 ' Turn error checking on.
' Now Check and see which error occurred and based
' on that you can decide whether file is already
' open
Select Case errorNum
' No error occurred so ErroNum is Zero (0)
' File is NOT already open by another user.
Case 0
IsFileOpen = False
' Error number for "Permission Denied." is 70
' File is already opened by another user.
Case 70
IsFileOpen = True
' For any other Error occurred
Case Else
Error errorNum
End Select
End Function
Public Function getConsolidatedDataFile() As Workbook
Dim p As String
p = ActiveWorkbook.Path
Dim cf As String
cf = printf("{0}\ConsolidatedData.xlsx", p)
Dim wb As Workbook
Dim fo As Boolean
fo = IsFileOpen(cf)
If fo = False Then wb = Workbooks.Open(filename:=cf)
''I need to get the code for this place of fo is true
getConsolidatedDataFile wb
End Function
So if file open I need to get that workbook in to that wb variable.
Ive got a solution
If fo = False Then
Set wb = Workbooks.Open(filename:=cf)
Else
Dim w As Workbook
For Each w In Workbooks
If w.FullName = cf Then
Set wb = w
End If
Next
End If
Here is in the loop its traversing through all workbook and if its there take that reference..
I hope this help
Dim dict As Dictionary
Function OpenFile(fileFullName As String) As Workbook
If (dict.Exists(fileFullName)) Then
OpenFile = dict.Item(fileFullName)
End If
dict.Add "fileFullName", Workbooks.Open(Filename:=fileFullName)
OpenFile = dict.Item(fileFullName)
End Function
Application.ActiveWorkbook = OpenFile(fileFullName)
To reference a workbook to the workbook collection it should be opened -
The Workbook object is a member of the Workbooks collection. The Workbooks collection contains all the Workbook objects currently open in Microsoft Excel.
MSDN Wrokbook Object
Thus, if your workbook is in the same Excel instance, then try like this:
Public Sub TestMe()
Dim wb As Workbook
Set wb = Workbooks("12.xlsx")
End Sub
If it is not in the same instance, then GetObject should work:
Public Sub TestMe()
Dim wb As Workbook
Set wb = GetObject("C:\path\12.xlsx")
Debug.Print wb.Worksheets(1).Name
End Sub
GetObject MSDN
This is how 3 workbooks in the same instance look like:
This is how 2 workbooks look like in 2 different instances:
Pros and Cons for using multiple instances (Source answers.microsoft.com):
Pros
If you have 32-bit Excel, each instance can use up to 3 GB memory. If you have a powerful computer, very heavy files, and 32-bit Excel, each instance of Excel can use 3 GB. So with e.g. 2 instances of Excel.exe, you could say that the total memory Excel could use triples. (Please note that this is not needed with 64-bit Excel as it is not limited by 3 GB memory per instance)
If you want to have a separate Undo chain, so that each Undo only undos in the currently active workbook, then separate instances will indeed achieve this.
Cons
If you want to have a common Undo chain shared by all open files, then using multiple instances will not achieve this.
If you want to be able to e.g. press Ctrl+F6 to jump between your open files quickly, then using multiple instances will not achieve this.
Paste Special will not work between instances. See this for more info.
Making workbook links between 2 files in separate running instances cannot be made by clicking, and will not update in real-time.
The code looks ok, simply use the Set keyword:
If fo = False Then set wb = Workbooks.Open(filename:=cf)
Here is a quick function that will open the workbook if it's not already open:
Function GetWorkBook(ByVal sFullName As String, Optional ReadOnly As Boolean) As Workbook
Dim sFile As String: sFile = Dir(sFullName)
On Error Resume Next
Set GetWorkBook = Workbooks(sFile)
If GetWorkBook Is Nothing Then Set GetWorkBook = Workbooks.Open(sFullName, ReadOnly:=ReadOnly)
On Error GoTo 0
End Function

Visio button to compare text in excel file; error 438

I am trying to make a visio diagram that you click a button and it searchs and excel file for the "location" once it find the location in the excel file it then copies over a URL and proceeds to open that URL with the default browser. I keep getting runtime error 438: Object doesn't support this property or method. Any ideas?
Option Compare Text
Private Sub Mail_Room_Click()
Dim XLApp As Excel.Application
Dim XLWB As Excel.Workbook
Set XLApp = New Excel.Application
Set XLWB = XLApp.Workbook.Open("C:\printers\schprint.xlsx")
Set XLWsht = XLWB.Sheets(1)
Dim URL As String
Dim Location As String
Location = "Mail Room"
URL = ""
For Each i In XLWsht.Range("D2:D11")
If StrComp(i.Cells.Value, Location) = 0 Then
URL = i.Cells.Offset(7, 0).Value
Exit For
End If
Next i
CreateObject("WScript.Shell").Run (URL)
End Sub
I think you're just missing as 's' in XLApp.WorkbookS.Open("C:\printers\schprint.xlsx")
That should fix the problem.

Write to Excel Object

I am trying to write a code that exports data to excel after user prompted actions.
Basically, I have been able to export to Excel successfully, but the 2nd instance I want to write to a new tab instead of a new Excel application.
oExcel = CreateObject("Excel.Application")
oExcel.Visible = True
oBook = oExcel.Workbooks.Add
oSheet = oBook.Worksheets(3)
oSheet.Delete()
oSheet = oBook.Worksheets(2)
oSheet.Delete()
oSheet = oBook.Worksheets(1)
oSheet.Name = "Run " & Counter
At this point, the user will press a button, making Excel no longer active.
So when I want to write more data to a new sheet, the Object commands do not
'work unless I repeat code exactly.
I tried:
Counter +=1
'For the first instance
If Counter = 1 Then
oExcel = CreateObject("Excel.Application")
oExcel.Visible = True
oBook = oExcel.Workbooks.Add
oSheet = oBook.Worksheets(3)
oSheet.Delete()
oSheet = oBook.Worksheets(2)
oSheet.Delete()
oSheet = oBook.Worksheets(1)
oSheet.Name = "Run " & Counter
Else
'For every instance after that the user wants to do another run
oExcel.ActivateObject(Excel.Application)
oBook = oExcel.Workbooks(1)
oSheet = oBook.Worksheets.Add
oSheet.Name = "Run " & Counter
End If
I have been looking for days and am getting very frustrated. I do not know how to reference back to the open excel in order to continue to writing data ... after the user has pressed a button on the VB form confirming they want to do another run.
To get a reference to an already-running instance of excel you can use GetObject.
Eg:
' Test to see if a copy of Excel is already running.
Private Sub testExcelRunning()
On Error Resume Next
' GetObject called without the first argument returns a
' reference to an instance of the application. If the
' application is not already running, an error occurs.
Dim excelObj As Object = GetObject(, "Excel.Application")
If Err.Number = 0 Then
MsgBox("Excel is running")
Else
MsgBox("Excel is not running")
End If
Err.Clear()
excelObj = Nothing
End Sub
http://msdn.microsoft.com/en-us/library/e9waz863(v=vs.90).aspx
If Excel is not already running you can start a new instance using CreateObject.
I used to write VBA, but I was taught to get out of the habit of using CreateObject. you could also use a boolean just as well, but i imagine thats just preference. You should create the excel object outside the loop, hold reference at class level once its assigned. you then use the loop to solely assign the next sheets and add values. Keeping the dimension at class level means you do not need to get rid of the object immediately, because there is possibility the user might still need to use the reference.
Public Class Form1
Dim firstRun As Boolean = True
Dim xlApp As New Excel.Application
Dim xlWb As Excel.Workbook
Dim xlSheet As Excel.Worksheet
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'set up us some excel
xlApp.Visible = True
xlApp.SheetsInNewWorkbook = 1
xlWb = xlApp.Workbooks.Add
'imaginary loop
For i = 0 To 5
Dim msgResponse = MessageBox.Show("Do you want to loop?", "Keep Looping?", MessageBoxButtons.YesNo)
If msgResponse = Windows.Forms.DialogResult.No Then Exit For
If firstRun Then
xlSheet = xlWb.Sheets(1)
firstRun = False
Else
xlWb.Activate()
xlSheet = xlWb.Sheets.Add(After:=xlWb.Sheets(xlWb.Sheets.Count))
End If
xlSheet.Name = "TEST" & i
xlSheet.Range("A1").Value = "Some Data"
Next i
End Sub
End Class
You will need to make sure that you clean up your references once you are certain the user is done with the sheet.

How to enable Grouping on a protected Excel 2007 sheet - without macros

I have an Excel 2007 XLSX workbook I am developing. It has multiple sheets and most of those use Excel's Grouping feature. I want to be able to protect the sheets, to protect some formulas and such from user intervention, but it seems there's no way to do that and still allow the user to expand or collapse the Grouped columns whenever they want.
It appears the standard answer on this is to insert a macro with commands like:
ActiveSheet.EnableGrouping
ActiveSheet.Proect UserInterfaceonly = true
But this workbook has no macros now and cannot have any ever. Is there a way to do this in Excel without a macro?
Thanks!
If there is nothing preventing you from running the code externally, then just put this code into another macro enabled workbook OR run it from a seperate C# winform/console application exe.
Note I had quick search of the Excel 2007 object model and didn't find the EnableGrouping method, but maybe i wasn't looking hard enough.
External VBA
Sub UpdateWorkbook()
Constant workbookpath As String = "C:\somepath\someworkbookname.xlsx"
Dim wkbk As Workbook
Set wkbk = Application.Workbooks.Open(workbookpath)
Dim wksht As Worksheet
Set wksht = wkbk.Worksheets.Item("sheetname")
wksht.EnableGrouping
wksht.Protect UserInterfaceonly = true
Set wksht = Nothing
Set wkbk = Nothing
End Sub
External C#
public void UpdateWorkbook()
{
const string workbookpath = #"C:\somepath\someworkbookname.xlsx";
Excel.Application xlApp = New Excel.Application();
// To use the next line you need the Excel Extension library otherwise use Type.Missing.
Excel.Workbook wkbk = Application.Workbooks.Open(workbookpath);
Excel.Worksheet wksht wksht = (Excel.Worksheet)wkbk.Worksheets.get_Item("sheetname");
//Check the way this method works..
wksht.EnableGrouping();
// UserInterfaceOnly is the 6th parameter, so 5 before and 11 after.
wksht.Protect(missing,missing,missing,missing,missing,True,missing,missing,missing, missing,missing,missing,missing,missing,missing,missing,missing);
Set wksht = null;
Set wkbk = null;
Set xlApp = null;
}

Reading excel files in vb.net leaves excel process hanging

The following code works fine but seems to leave instances of excel.exe running in the background. How do I go about closing out this sub properly?
Private Sub ReadExcel(ByVal childform As Fone_Builder_Delux.frmData, ByVal FileName As String)
' In progress
childform.sampleloaded = False
Dim xlApp As Excel.Application
Dim xlWorkBook As Excel.Workbook
Dim xlWorkSheet As Excel.Worksheet
xlApp = New Excel.ApplicationClass
xlWorkBook = xlApp.Workbooks.Open(FileName)
xlWorkSheet = xlWorkBook.Worksheets(1)
Dim columnrange = xlWorkSheet.Columns
Dim therange = xlWorkSheet.UsedRange
childform.datagridHeaders.Columns.Add("", "") ' Super imporant to add a blank column, could improve this
For cCnt = 1 To therange.Columns.Count
Dim Obj = CType(therange.Cells(1, cCnt), Excel.Range)
childform.datagridSample.Columns.Add(Obj.Value, Obj.Value)
childform.datagridHeaders.Columns.Add(Obj.Value, Obj.Value)
Next
For rCnt = 2 To therange.Rows.Count
Dim rowArray(therange.Columns.Count) As String
For cCnt = 1 To therange.Columns.Count
Dim Obj = CType(therange.Cells(rCnt, cCnt), Excel.Range)
Dim celltext As String
celltext = Obj.Value.ToString
rowArray((cCnt - 1)) = celltext
'MsgBox(Obj.Value)
Next
childform.datagridSample.Rows.Add(rowArray)
Next
AdjustHeaders(childform)
childform.sampleloaded = True
End Sub
Short answer: close each item appropriately, then call FinalReleaseComObject on them.
GC.Collect()
GC.WaitForPendingFinalizers()
If xlWorkSheet Is Nothing Then Marshal.FinalReleaseComObject(xlWorkSheet)
If xlWorkBook Is Nothing Then
xlWorkBook.Close(false, false)
Marshal.FinalReleaseComObject(xlWorkBook)
End If
xlApp.Quit()
Marshal.FinalReleaseComObject(xlApp)
Long answer: read this answer to another question (the entire post is helpful too).
I ran into this problem and what I found worked was making sure I called the Close() method on all Workbook and Workbooks objects, as well as the Quit() method on the Excel Application object. I also call System.Runtime.InteropServices.Marshal.ReleaseComObject on every Excel object was instantiated. I do all this in reverse order of age, so the newest object gets cleaned up first and the oldest, which is the Application object, gets taken care of last. I don't know if the order really matters, but it seems like it might.
I've seen examples where GC.Collect() was called at the very end, but I've never had to do that to get the excel.exe process to end.