EPSDK.Recordset not looping until EOF (end of file) - com

I am currently half way through a project where I am migrating data from an ancient Adobe Workflow server using Visual Basic and COM.
I have hit a bit of a brick wall really as I am trying to perform a simple while loop that counts the number of records in a recordset, and I keep getting this error...
"An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in microsoft.visualbasic.dll
Additional information: Unspecified error"
There is little to no documentation to help me online so I am hoping there is some sort of VB wizard/veteran that can point me in the right direction.
I have set the record as a global variable like so...
Dim record As New EPSDK.Recordset
I have then tried...
Dim recCount As Integer = 0
Do Until record.EOF
recCount += 1
Loop
This...
Dim recCount As Integer = 0
Do While Not record.EOF
recCount += 1
Loop
This...
Dim recCount As Integer = 0
Do
recCount += 1
Loop Until record.EOF
And lots of other variations, but still cannot seem to source the problem. There are no code errors, nothing comes up in the console, and I just keep getting that message back.
Can anyone spot what I am doing wrong? Thanks

Ok, I've looked up the documentation for EPSDK. For those who are unaware (as I was), it's an object collection from Adobe for manipulating COM data. It's basically the most popular functionality in ADO.
MoveFirst, as its name suggests, moves to the first record in a recordset. There doesn't appear to be any such method supported by the EPSDK Recordset object. Since you can use the Move method to do the same thing, it isn't needed. In either case, you don't need to use it to move to the end of the file.
What you're doing wrong is expecting that you can increment a variable called recCount that you made up and the recordset cursor will magically move along. Doesn't happen. As you say, the doc is insubstantial, but you probably need to use MoveNext. Here's a cheat sheet you can use to look up what's supported.
Also, you need to specify a connection, open it, point the recordset to the open connection, and open the recordset. I would suggest that you familiarize yourself with ADO (NOT ADO.Net! Not the same thing), upon which this is clearly based. There's much more documentation, and it should apply fairly well. Read up on Connections and Recordsets in particular.
Now, your loops do pretty much the same thing. While Not is the equivalent of Until. However, if you put the while/until condition after the Do statement, you won't enter the loop unless the condition is met. If you put it after the Loop statement, you will always run the loop at least once. In this case, you should put "Do Until myRecordset.EOF", because then if the recordset is empty, you won't go into the loop.

Related

Error HRESULT E_FAIL when iterating through for loop only

I'm seeing the good old "System.Runtime.InteropServices.COMException HResult=0x80004005 Message=Error HRESULT E_FAIL has been returned from a call to a COM component" error when attempting to find an item via a for loop as shown below:
For i = 1 to itemList.Count
oObject = itemList.Item(i)
Next
But not if I hardcode the index, this finds item 1 without issue:
oObject = itemList.Item(1)
Obviously I don't want to do that and need to search through all the objects in my "itemList" to find the one I'm looking for.
I'm being intentionally vague because the software I'm working in is Dassault 3D Experience but am writing macros for it through Visual Studio 2017. I'm not sure where to even start debugging this sort of issue so any suggestions would be appreciated. Thanks.
Edit: adding full code of what I'm trying to do here (find an object, display its name, also select it on screen to double check. I will later add a check to make sure the object found in each loop is really what I'm looking for). All variables have been declared before this section.
selactive = CATIA.ActiveEditor.Selection
selactive.Clear()
product1Service = CATIA.ActiveEditor.GetService("PLMProductService")
oRootOcc = product1Service.RootOccurrence
cVPMOccurrences = oRootOcc.Occurrences
For i = 1 to cVPMOccurrences.Count
oVPMOccurrence = cVPMOccurrences.Item(i)
selactive.Add(oVPMOccurrence)
MsgBox(oVPMOccurrence.Name)
Next
The line that fails is oVPMOccurrence = cVPMOccurrences.Item(i)
Can you do something like this with a For Each loop?
For each oVPMOccurrence as oRootOcc.Occurrence in cVPMOccurrences.Items
selactive.Add(oVPMOccurrence)
MsgBox(oVPMOccurrence.Name)
Next
Using a For Each means you don't have to worry at all about the index
Not sure what the type of oVPMOccurrence is as you haven't specified
Most indexes in .net are zero base. I don't know what itemList is but I suspect the index of the first item is 0.
For i = 0 to itemList.Count - 1
oObject = itemList.Item(i)
Next
Not sure why you want to overwrite the value of oObject on every iteration.

Using movenext and moveprevious

I want to get the next value of the field next to the current row.
I used ADODB movenext and moveprevious together, but there is an error that the current context does not permitted.
How to fix that?
This is the code
objresultset.MoveNext()
yMark = objresultset.Fields(k1).Value
If xMark = yMark Then
m += 1
End If
objresultset.MovePrevious()
I'm not sure. Perhaps you provide too little information.
I assume that ADO recordset features might also dependent upon the underlying database system and/or your database connection properties. So perhaps your specific database/recordset instance does not support MovePrevious in your case.
But if it has worked before, or if it works in a small test application, perhaps you are trying to move beyond the last record in your recordset. In that case you might check the BOF/EOF property values before you try to use MovePrevious/MoveNext.

Running a loop while debugging VBA

The Problem
I am trying to debug some code, and somewhere in the middle I stopped at a breakpoint. Now I want to change some variables and run a certain loop several times.
How far did I get?
I know how to change the variables, but somehow I get stuck when trying to run the loop in the immediate window. Here is an example:
Dim i As Integer
Dim j As Integer
For i = 0 To 6
j=i ' Do something
Next i
I tried several variations of the code, but each time I get the following error:
Compile error: Next without for
Other relevant information
I tried searching but mostly found information about problems with loops, whilst I am quite sure the loop itself is fine. (Especially as I reached it before arriving at the breakpoint).
The only place I saw someone addres this situation, he reduced the loop to a single line, however to do this every time would be very impractical in my case.
I realize that I could call a function containing the loop, and then the function call would probably work, but again this feels quite impractical. So I guess it boils down to the following question.
The question
What is a practical way to run a loop whilst debugging VBA code in Excel?
There is actually a way for using loops or other multi-line statements in the Immediate Window - using a colon : to separate statements instead of a new line.
Full solution is described here.
Note that in the Immediate Window you also don't have to declare the variables using a Dim statement.
To summarize, your snippet would look something like this:
For i = 0 To 6: j=i: debug.Print i+j: Next i
I think I understand your question. You want to run a multi-line code block (i.e. the loop) in the Immediate Window. This throws errors because the Immediate Window is only intended for single lines of code.
I don't have any suggestions other than those you already mentioned. I'd recommend putting your test loop into a separate function and calling that from the Immediate Window:
Sub Test()
Dim i As Integer
Dim j As Integer
For i = 0 To 6
j=i ' Do something
Next i
End
Another option is to set several breakpoints. You can also run one line of code at a time with F8.
What is likely the preferred method (i.e., what most people actually do) is use the full power of the IDE, which includes the Immediate, Locals and Watch panes. You can change the value of most variables at runtime by direct assignment in the Immediate Pane (i=6 will do exactly what you think it should do). The IDE also allows you to set breakpoints, add watch conditions, step through code line-by-line using the F8, step through function or procedure calls using Shift+F8, stepping over (and back) through code using the mouse/cursor, and with a few exceptions, you can even add new variables during runtime.

Need to call com function from VB.NET

If anyone wants to take a crack at this I'd really appreciate it. I'm writing a VB.NET app that will control a commercial backup product. One of the things I need to do is loop through all existing jobs and look at the source drive. I am able to do this in VBScript very simply like this:
Dim SP, BackupJob, volumes
Set SP = CreateObject("ShadowStor.ShadowProtect")
For Each Job In SP.Jobs
Set BackupJob = SP.Jobs.GetBackupJob(Job.Description)
BackupJob.GetVolumes volumes
For Each Volume in volumes
WScript.Echo volume
Next
Next
Set SP = Nothing
However nothing I try in VB.NET works. I'm pretty sure it has to do with the fact that the com functions are returning variant data types and arrays (specifically GetVolumes). I have tried using string arrays, object arrays, and even wrapping the return value in a VariantWrapper and I always get errors such as "not implemented" or "the parameter is incorrect." If anyone is bored and wants to write some code I'll gladly give it a shot and report back.
UPDATE:
This is odd. Look at this code:
Dim SP As Object = CreateObject("ShadowStor.ShadowProtect")
Dim gotJob As Object
Dim volumes() As Object
Try
For Each Job As Object In SP.Jobs
gotJob = SP.Jobs.GetBackupJob(Job.Description.ToString())
gotJob.GetVolumes(volumes)
For Each volume As Object In volumes
MsgBox(volume.ToString())
Next
Next
Catch ex As Exception
MsgBox(ex.Message)
End Try
This will display the volume from ONE job, then it crashes if there is more than one jobwith the error "invalid callee."
Locate ShadowStor.ShadowProtect in your registry in HKCR. It will have a CLSID which is a GUID. Search for that GUID, also in HKCR. You should find it in the CLSID section. Under that key you should find the actual dll path under InprocServer32.
Now if that component has an embedded TypeLib you should be able to add a reference to it in Visual Studio. (If you have OLE View installed you can inspect the type lib easily as well).
And if you cannot add a reference to the dll, there might be a seperate .tlb file, and you can find that by searching on the GUID present in the TypeLib value.
For anyone interested, the solution was to Dim volumes() As Object inside the loop and then set volumes = Nothing at the end of the loop so that it was re-created each time. If anyone can explain why this is so I would love to understand it.

How do I use Google.GData.Client.AtomLinkCollection.FindService method to get the list of worksheets in a Google Spreadsheet?

I'm trying to write code that talks to Google Spreadsheets. We do a bunch of processing on our end and then pass data out to our client into this spreadsheet and I want to automate it. This seems like it should be easy.
On this page, Google says "Given a SpreadsheetEntry you've already retrieved, you can print a list of all worksheets in this spreadsheet as follows:"
AtomLink link = entry.Links.FindService(GDataSpreadsheetsNameTable.WorksheetRel, null);
WorksheetQuery query = new WorksheetQuery(link.HRef.ToString());
WorksheetFeed feed = service.Query(query);
foreach (WorksheetEntry worksheet in feed.Entries)
{
Console.WriteLine(worksheet.Title.Text);
}
Following along at home, I start with:
Dim link As AtomLink = Entry.Links.FindService(GDataSpreadsheetsNameTable.WorksheetRel, "")
Dim wsq As New WorksheetQuery(link.HRef.ToString)
and when execution gets to that second line, I find that "Object reference not set to instance of an object." The FindService method is returning nothing. And when I look at GDataSpreadsheetsNameTable.WorksheetRel, it's a constant value of "http://schemas.google.com/spreadsheets/2006#worksheetsfeed"
I'm not really at the point where I even grok what it wants to be doing. E.g., what's a feed? Is a worksheet really what I think it is based on Excel nomenclature? That kind of stuff. But I see a couple of things that might be causing my issue:
The C# method call "...FindService(GDataSpreadsheetsNameTable.WorksheetRel, null);" I'm not sure about that null. It demands a string, so I used "" in my VB, but I'm not sure that's right.
That schemas.google.com URI doesn't seem to be live. At least, if I punch it into a browser, I get server not found. But again, I don't exactly know what it's trying to do.
So, any thoughts? Anyone have VB code that reads Google Spreadsheets and time to instruct a newbie? I'm surprised to find that there's essentially no useful sample code floating around the net.
Thanks for reading!
So, of course, right after I posted this I found some inspiration over here. Manually iterating across the collections works just fine, even if it's not the preferred way to do this. I'm still keen to hear info from others related to this, so feel encouraged to help out even though I'm maybe over this one hurdle.
For Each Entry In mySprShFeed.Entries
If Entry.Title.Text = "spreadsheetNameSought" Then
For Each link As AtomLink In Entry.Links
If link.Rel = GDataSpreadsheetsNameTable.WorksheetRel Then
Dim wsf As WorksheetFeed = service.Query(New WorksheetQuery(link.HRef.ToString))
For Each worksheet In wsf.Entries
Console.WriteLine(worksheet.Title.Text)
Next
End If
Next
End If
Next