FeatureCursor instance passed to Search method of ISelectionSet throws NullReferenceException - vb.net

I am trying to create a custom tool in VB.Net for arcmap. But im having a problem with FeatureCursor passed to ISelectionSet's Search() method.
Here's a portion of my code:
Dim pSelSet As ISelectionSet = provFSel.SelectionSet
Dim provCursor As IFeatureCursor
pSelSet.Search(spatialFilter, True, provCursor)
Dim provFeature As IFeature = provCursor.NextFeature
A blue squiggle appears under provCursor inside Search() that says "Variable 'provCursor' is passed by reference before it has been assigned a value. A null reference exception could result at runtime."
Ive tried
Dim provCursor As IFeatureCursor = New FeatureCursor
but a squiggle under New FeatureCursor says "'ESRI.ArcGIS.Geodatabase.FeatureCursorClass.Friend Sub New()' is not accessible in this context because it is 'Friend'.".
I also tried
Dim provCursor As IFeatureCursor = Nothing
but with no success.
In all my debugging attempts, Arcmap crashed with this error: A first chance exception of type 'System.NullReferenceException' occurred in Microsoft.VisualBasic.dll
Can somebody help me figure out whats wrong with my code? Ill really appreciate any help.
-spearman
Im not actually sure if error occurs in the above codes or in the prior codes. Im therefore posting the whole subprocedure content:
Dim pPoint As IPoint = pMxDoc.CurrentLocation
Dim provFSel As IFeatureSelection = provinceLayer
Dim pGeom As IGeometry = pPoint.Shape
Dim spatialFilter As ISpatialFilter = New SpatialFilter
With spatialFilter
.Geometry = pGeom
.SpatialRel = esriSpatialRelEnum.esriSpatialRelWithin
End With
Dim pSelSet As ISelectionSet = provFSel.SelectionSet
Dim provCursor As IFeatureCursor
pSelSet.Search(spatialFilter, True, provCursor)
Dim provFeature As IFeature = provCursor.NextFeature

Try:
pSelSet.Search(spatialFilter, True, out provCursor)

Related

OpenXML: Losing Custom Document Property After Editing Word Document

Using DocumentFormat.OpenXML, I am trying to add a custom property to a Word document and then later read the property. The following code "appears" to do just that:
Dim os As OpenSettings = New OpenSettings() With {
.AutoSave = False
}
Dim propVal As String = "Test Value"
Using doc As WordprocessingDocument = WordprocessingDocument.Open(filename, True, os)
Dim cPart As CustomFilePropertiesPart = doc.CustomFilePropertiesPart
If cPart Is Nothing Then
cPart = doc.AddCustomFilePropertiesPart
cPart.Properties = New DocumentFormat.OpenXml.CustomProperties.Properties()
End If
Dim cPart As CustomFilePropertiesPart = doc.CustomFilePropertiesPart
Dim cProps As Properties = cPart.Properties
For Each prop As CustomDocumentProperty In cProps
If prop.Name = "TranscriptID" Then
prop.Remove()
Exit For
End If
Next
Dim newProp As CustomDocumentProperty = New CustomDocumentProperty() With {
.Name = "TranscriptID"
}
newProp.VTBString = New VTBString(propVal)
newProp.FormatId = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"
cProps.AppendChild(newProp)
Dim pid As Integer = 2
For Each item As CustomDocumentProperty In cProps
item.PropertyId = pid
pid += 1
Next
cProps.Save()
End Using
This code is modeled after code found here:
https://learn.microsoft.com/en-us/office/open-xml/how-to-set-a-custom-property-in-a-word-processing-document
It appears to work in this scenario:
Execute code from above.
Execute code from above again.
At #2 I expect to find the CustomFilePropertiesPart and the property value and my expectation is met.
The problem appears in this scenario:
Execute code from above.
Open document using Microsoft Word, save and close.
Execute code from above again.
What happens in this scenario is that the CustomFilePropertiesPart is missing, whereas it should be found. It is as if Microsoft Word does not successfully read this object, so when the document is save, the object is lost. This suggests to me that there is something that there is something wrong with my code. If you can see what it is, or if you have a comparable working example that I could compare it with, I would appreciate hearing from you. I feel like I correctly followed the Microsoft example, but obviously I did not and I am having trouble seeing where I departed. Thanks.
OK, I found this wonderful tool called the Office Productivity Tool. It has a code generation feature, so I was able to compare what I was doing with what Word does. Basically the problem was with setting the property value. This snippet does the trick:
Dim cProps As Properties = cPart.Properties
Dim val As DocumentFormat.OpenXml.VariantTypes.VTLPWSTR = New DocumentFormat.OpenXml.VariantTypes.VTLPWSTR
val.Text = tr.ID.ToString
Dim newProp As CustomDocumentProperty = New CustomDocumentProperty() With {
.Name = "TranscriptID",
.FormatId = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"
}
newProp.Append(val)
cProps.AppendChild(newProp)

Excel VSTO - Hide multiple columns lambda function issue - VB.NET

I've been trying to figure out what is wrong with my code below, but no success so far.
My simple task is to hide multiple Excel columns using VSTO / VB.NET.
This works:
Dim app As Excel.Application = Globals.ThisAddIn.Application
Dim act_sheet As Excel.Worksheet = app.ActiveSheet
act_sheet.Range("A:A").EntireColumn.Hidden = True
act_sheet.Range("B:B").EntireColumn.Hidden = True
This doesn't work:
Dim app As Excel.Application = Globals.ThisAddIn.Application
Dim act_sheet As Excel.Worksheet = app.ActiveSheet
Dim base_hide As New List(Of String)({"A:A", "B:B"})
base_hide.ForEach(Function(x) act_sheet.Range(x).EntireColumn.Hidden = True)
I get no errors compiling it, the string address is taken correctly. Any idea?
Thank you,
C
Found what caused the issue. Running a ForEach loop as lambda with Function() would expect to return something. My code inside the function never run. Changing it to Sub() works as expected.
base_hide.ForEach(Sub(x) act_sheet.Range(x).EntireColumn.Hidden = True)

System.UnauthorizedAccessException only using multithreading

I wrote a code to parse some Web tables.
I get some web tables into an IHTMLElementCollection using Internet Explorer with this code:
TabWeb = IE.document.getelementsbytagname("table")
Then I use a sub who gets an object containing the IHTMLElementCollection and some other data:
Private Sub TblParsing(ByVal ArrVal() As Object)
Dim WTab As mshtml.IHTMLElementCollection = ArrVal(0)
'some code
End sub
My issue is: if I simply "call" this code, it works correctly:
Call TblParsing({WTab, LiRow})
but, if I try to run it into a threadpool:
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf TblParsing), {WTab, LiRow})
the code fails and give me multiple
System.UnauthorizedAccessException
This happens on (each of) these code rows:
Rws = WTab(RifWT("Disc")).Rows.Length
If Not IsError(WTab(6).Cells(1).innertext) Then
Ogg_W = WTab(6).Cells(1).innertext
My goal is to navigate to another web page while my sub perform parsing.
I want to clarify that:
1) I've tryed to send the entire HTML to the sub and get it into a webbrowser but it didn't work because it isn't possible to cast from System.Windows.Forms.HtmlElementCollection to mshtml.IHTMLElementCollection (or I wasn't able to do it);
2) I can't use WebRequest and similar: I'm forced to use InternetExplorer;
3) I can't use System.Windows.Forms.HtmlElementCollection because my parsing code uses Cells, Rows and so on that are unavailable (and I don't want to rewrite all my parsing code)
EDIT:
Ok, I modified my code using answer hints as below:
'This in the caller sub
Dim IE As Object = CreateObject("internetexplorer.application")
'...some code
Dim IE_Body As String = IE.document.body.innerhtml
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf TblParsing_2), {IE_Body, LiRow})
'...some code
'This is the called sub
Private Sub TblParsing_2(ByVal ArrVal() As Object)
Dim domDoc As New mshtml.HTMLDocument
Dim domDoc2 As mshtml.IHTMLDocument2 = CType(domDoc, mshtml.IHTMLDocument2)
domDoc2.write(ArrVal(0))
Dim body As mshtml.IHTMLElement2 = CType(domDoc2.body, mshtml.IHTMLElement2)
Dim TabWeb As mshtml.IHTMLElementCollection = body.getElementsByTagName("TABLE")
'...some code
I get no errors but I'm not sure that it's all right because I tryed to use IE_Body string into webbrowser and it throws errors in the webpage (it shows a popup and I can ignore errors).
Am I using the right way to get Html from Internet Explorer into a string?
EDIT2:
I changed my code to:
Dim IE As New SHDocVw.InternetExplorer
'... some code
Dim sourceIDoc3 As mshtml.IHTMLDocument3 = CType(IE.Document, mshtml.IHTMLDocument3)
Dim html As String = sourceIDoc3.documentElement.outerHTML
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf TblParsing_2), {html, LiRow})
'... some code
Private Sub TblParsing_2(ByVal ArrVal() As Object)
Dim domDoc As New mshtml.HTMLDocument
Dim domDoc2 As mshtml.IHTMLDocument2 = CType(domDoc, mshtml.IHTMLDocument2)
domDoc2.write(ArrVal(0))
Dim body As mshtml.IHTMLElement2 = CType(domDoc2.body, mshtml.IHTMLElement2)
Dim TabWeb As mshtml.IHTMLElementCollection = body.getElementsByTagName("TABLE")
But I get an error PopUp like (I tryed to translate it):
Title:
Web page error
Text:
Debug this page?
This page contains errors that might prevent the proper display or function properly.
If you are not testing the web page, click No.
two checkboxes
do not show this message again
Use script debugger built-in Internet Explorer
It's the same error I got trying to get Html text into a WebBrowser.
But, If I could ignore this error, I think the code could work!
While the pop is showing I get error on
Dim domDoc As New mshtml.HTMLDocument
Error text translated is:
Retrieving the COM class factory for component with CLSID {25336920-03F9-11CF-8FD0-00AA00686F13} failed due to the following error: The 8,001,010th message filter indicated that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVERCALL_RETRYLATER)).
Note that I've alredy set IE.silent = True
Edit: There was confusion as to what the OP meant by "Internet Explorer". I originally assumed that it meant the WinForm Webbrowser control; however the OP is creating the COM browser directly instead of using the .Net wrapper.
To get the browser document's defining HTML, you can cast the document against the mshtml.IHTMLDocument3 interface to expose the documentElement property.
Dim ie As New SHDocVw.InternetExplorer ' Proj COM Ref: Microsoft Internet Controls
ie.Navigate("some url")
' ... other stuff
Dim sourceIDoc3 As mshtml.IHTMLDocument3 = CType(ie.Document, mshtml.IHTMLDocument3)
Dim html As String = sourceIDoc3.documentElement.outerHTML
End Edit.
The following is based on my comment above. You use the WebBrowser.DocumentText property to create a mshtml.HTMLDocument.
Use this property when you want to manipulate the contents of an HTML page displayed in the WebBrowser control using string processing tools.
Once you extract this property as a String, there is no connection to the WebBrowser control and you can process the data in any thread you want.
Dim html As String = WebBrowser1.DocumentText
Dim domDoc As New mshtml.HTMLDocument
Dim domDoc2 As mshtml.IHTMLDocument2 = CType(domDoc, mshtml.IHTMLDocument2)
domDoc2.write(html)
Dim body As mshtml.IHTMLElement2 = CType(domDoc2.body, mshtml.IHTMLElement2)
Dim tables As mshtml.IHTMLElementCollection = body.getElementsByTagName("TABLE")
' ... do something
' cleanup COM objects
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(body)
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(tables)
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(domDoc)
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(domDoc2)

Set a report datasource instance at run time

I have created a report that is based on a business object - this works great. I am now trying to add a button that renders the report directly to PDF (in a winforms application).
I know what I need to do - in code I am creating a ReportViewer, setting the DataSource, specifying the report (it's an embedded resource), then rendering the report into a byte array before using System.IO.File.WriteAllBytes to flush the byte array to disk. One thing I'm hung up on though, is how do I specify the instance of the object properly? I keep getting the "An error has occurred during the report processing" error. In IntelliTrace I can see that an exception is thrown "A data source instance has not been supplied for the data source 'IssRep'" (IssRep is the dataset name in the report. Here is the code:
Dim warning As Warning() = Nothing
Dim streamids As String() = Nothing
Dim mimetype As String = Nothing
Dim encoding As String = Nothing
Dim extension As String = Nothing
Dim viewer As New ReportViewer
Dim bs As New BindingSource
bs.DataSource = issuedet
Dim rds As New ReportDataSource
rds.Value = bs
viewer.LocalReport.DataSources.Add(rds)
viewer.ProcessingMode = ProcessingMode.Local
viewer.LocalReport.ReportEmbeddedResource = "FRSFE.SR.rdlc"
Dim pdfbytes As Byte()
Try
pdfbytes = viewer.LocalReport.Render("PDF", Nothing, mimetype, encoding, extension, streamids, warning)
File.WriteAllBytes("C:\Shared\FRS\SR.PDF", pdfbytes)
Catch ex As Exception
MsgBox(ex.Message)
End Try
I'm pretty sure whatever I'm stuck on is pretty simple as I'm very rusty on .NET but I just can't figure it out!
Try setting rds.Name = "IssRep" before adding it to viewer.LocalReport.DataSources.

Compiling and running code in runtime

I am trying to compile and run code at runtime. I am using the below code to achieve this. However, when i trying to invoke the method, simply a "Find Source" file browser dialog opens and the code is not run. Can anyone please help me here.
Dim VBP As New VBCodeProvider
Dim CVB As System.CodeDom.Compiler.ICodeCompiler
CVB = VBP.CreateCompiler
Dim PM As New System.CodeDom.Compiler.CompilerParameters
PM.GenerateInMemory = True
PM.GenerateExecutable = True
PM.OutputAssembly = "RunCode.dll"
PM.MainClass = "MainClass"
PM.IncludeDebugInformation = True
Dim ASM As System.Reflection.Assembly
For Each ASM In AppDomain.CurrentDomain.GetAssemblies
PM.ReferencedAssemblies.Add(ASM.Location)
Next
Dim CompileResults As System.CodeDom.Compiler.CompilerResults
CompileResults = CVB.CompileAssemblyFromSource(PM, sCode)
Dim CompileErrors As System.CodeDom.Compiler.CompilerError
For Each CompileErrors In CompileResults.Errors
RTMainScript.AppendText(vbCrLf & CompileErrors.ErrorNumber & ": " & CompileErrors.ErrorText & ", " & CompileErrors.Line)
Next
Dim objRun As New Object
Dim vArgs() As Object
objRun = CompileResults.CompiledAssembly.CreateInstance("RunCode.MainClass", False, BindingFlags.CreateInstance, Nothing, vArgs, Nothing, Nothing)
If Not objRun Is Nothing Then
Dim oMethodInfo As MethodInfo = objRun.GetType().GetMethod("Main")
Dim oRetObj As Object = oMethodInfo.Invoke(objRun, BindingFlags.Static Or BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.NonPublic, Nothing, Nothing, Nothing) 'Find source dialog appears here
Else
MsgBox("Compile Error")
End If
The code you provided is incomplete. You are using this method to compile the code:
CompileResults = CVB.CompileAssemblyFromSource(PM, sCode)
But you actually never specified what sCode is. If you are getting an open file browser dialog, then I am quite sure that your sCode is the cause of it. It must have been set somewhere while calculating the variable value to open a file.
If you are trying to change a piece of code that was used to compile from a file then changing the method from CompileAssemblyFromFile() to CompileAssemblyFromSource() is not enough. You need to dig more into the code and change all related methods.
Ensure your threading model is STA.
OpenFileDialog and similar objects will not operate correctly if the threading model is set to MTA.
If you must use MTA for some other reason then you can create your own custom OpenFileDialog class; sort of sucks.