Closing WRQ Reflection instance from Access VBA - vba

This is my first question so please go easy on me.
My company is working with Reflection for UNIX and OpenVMS and I'm building a database that interacts with the software as it is impossible for me to access the database behind the Reflection application (too many authorizations required etc...).
I'm working with MS Access 2013 right now and coding in VBA. My main issue is closing the Reflection instance in a clean manner.
The following code works fine for me :
Sub Test()
Dim strUserId As String
Dim MyObject As Reflection2.Session
Set MyObject = GetObject(Path)
strUserId = InputBox("Enter user ID.")
ContractNum = InputBox("Enter a contract number :")
With MyObject
.Visible = True
.Connect
.Transmit strUserId
.TransmitTerminalKey rcVtEnterKey
.Transmit ContractNum
.TransmitTerminalKey rcVtEnterKey
sContractNum = .GetText(1, 18, 1, 28)
'Do other shit
End With
**Exit Reflection**
Set MyObject = Nothing
End Sub
I have tried the following methods :
MyObject.Close ==> Returns : "Run-time error '438': Object doesn't support this property of method"
MyObject.Exit ==> Returns : "Run-time error '438': Object doesn't support this property of method"
MyObject.Quit ==> Returns : "Run-time error '10097': This function not available when running Reflection as a document object."
There is: MyObject.ConfirmExit = True but as it says, it only confirms and doesn't close.
Anyway I was hoping someone would help before doing a hard closing through Shell command (wouldn't be difficult to find on Google I guess).
Thank you!!

Found a way using the following code, it is quite a harsh closing but works fine for the moment :
Function TaskKill(sTaskName)
TaskKill = CreateObject("WScript.Shell").Run("taskkill /f /im " & sTaskName, 0, True)
End Function
If TaskKill("r2win.exe") = 0 Then MsgBox "Terminated" Else MsgBox "Failed"
Hope that helps

Related

using Late Binding and early binding in VBA simultaneously

I have a problem as below.
A program is written using early binding in VBA and it only works with all the references connected.
but there are some systems where the references are not connected and when the program is ran on those systems there is a compile error.
so I thought maybe I can use late binding to connect the references but it still shows compile error.
condition is that I cant convert the variables in code to late binding.
Public oPart As Part
Sub CATMain()
Dim refname()
Dim reffullPath()
Dim refGUID()
ReDim refname(5)
refname() = Array("INFITF,MECMOD", "ProductStructureTypeLib")
ReDim reffullPath(5)
reffullPath() = Array("D:\opt\ds\catia\B28_VWGROUP\win_b64\code\bin\MecModTypeLib.tlb", "D:\opt\ds\catia\B28_VWGROUP\win_b64\code\bin\PSTypeLib.tlb")
ReDim refGUID(5)
refGUID() = Array("{0D90A5C9-3B08-11D1-A26C-0000F87546FD}", "{5065F8B6-61BB-11D1-9D85-0000F8759F82}")
CheckAndAddReference refname(), reffullPath(), refGUID()
End Sub
Sub CheckAndAddReference(refname() As Variant, refLocation() As Variant, refGUID() As Variant)
Set VBAEditorx = CreateObject("MSAPC.Apc").VBE 'Application.VBE
Set vbProj = VBAEditorx.ActiveVBProject 'ActiveWorkbook.VBProject
For j = 0 To UBound(refname)
For i = 1 To vbProj.References.Count
RefCon = False
If vbProj.References.Item(i).Name = refname(j) Then
RefCon = True
Exit For
End If
Next
If RefCon = False Then
vbProj.References.AddFromFile refLocation(j)
End If
Next
End Sub
the first line "Public oPart As Part" , I cant make it as Object because there are many of these in original program.
the above line requires a reference called "INFITF,MECMOD" which is not connected in some systems.
when I try to late bind it, it is showing the error as
Compile error:
user type not defined
so I wanted to ask weather i can late bind the reference while the line "Public oPart As Part" remains same in the code without showing an error.
or I need to make all the early bound objects into "As Object".

How to get data in Access VBA from a C# method that returns an object List

I'm calling a C# WebService method called getInterventions() on a VBA Access 2003 application through a custom DLL. The signature of this method is as follows:
List<Item> getInterventions(string, string, string, string, string, string)
Item is a custom defined class.
When I try to retrieve the result of getInterventions() on VBA Access code, it pops a VBA Runtime error 242 : object required
The following is my code:
Dim WsObject As Object
Dim result As Object
Set WsObject = CreateObject("Namespace1.Path.To.Class") 'This isn't the actual DLL path as I cannot share that
'Set result = WsObject .getSingleIntervention("123, "0", "123456789", "") ' this works
Set result = WsObject .getInterventions("", "", "123456789", "", "", "") 'this doesn't work
If result Is Nothing Then
'do some stuff
Else
'do some other stuff
End If
getSingleIntervention() is a similar method which returns a single object rather than a list of objects. Returning the result of this method works without issues (see commented line). This proves that both the WS & DLL calls work. This method is defined as follows:
Item getSingleIntervention(string, string, string, string)
I have tested calling getInterventions() directly from the C# code via Visual Studio 2015 with the same parameters I'm passing in my VBA code and it worked. This proves that it's not an issue with parameters or the method content.
My conclusion:
I am guessing it's something to do with the fact that I can't simply store a C# List of objects into a VBA Object.
Any help would be appreciated, thank you.
Please, automatically add mscorlib.tlb reference, running the next code:
Sub addMscorlibRef() 'necessary to use ArrayList
'Add a reference to 'Mscorlib.dll':
'In case of error ('Programmatic access to Visual Basic Project not trusted'):
'Options->Trust Center->Trust Center Settings->Macro Settings->Developer Macro Settings->
' check "Trust access to the VBA project object model"
If dir("C:\Windows\Microsoft.NET\Framework64\v4.0.30319", vbDirectory) = "" Then _
MsgBox "You need to install ""Framework version 3.5"".": Exit Sub
On Error Resume Next
Application.VBE.ActiveVBProject.References.AddFromFile "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.tlb"
If err.Number = 32813 Then
err.Clear: On Error GoTo 0
MsgBox "The reference already exists...": Exit Sub
Else
On Error GoTo 0
MsgBox """Mscorlib"" reference added successfully..."
End If
End Sub
Then try declaring Dim result As ArrayList.
The ArrayList is the same one that is used in C#. Then, adapt the dll to use such an object. As you deduced, no any object able to be used in VBA can receive the C# list object content.

Proper release of COM objects in code

I have just started to migrate some code from VBA to VB.Net. So I am an absolute beginner in VB.Net – but I want to do things right. Maybe some of my questions are stupid but I guess that is because I am a beginner.
So as a first exercise I have developed my first piece of code (see below). Now I thought I have to release ALL COM objects again. Two of them throw errors already while writing the code. And others throw errors at runtime.
But the funny thing is: Weather I release the rest of the COM objects or not (by making the relevant not yet commented lines of Marshal.Release to comments as well – then all lines starting with Marshal.Release are comment lines) the behavior of the code is absolutely the same to my eyes.
Can anybody tell me where I can see/find the difference?
The internet tells me that there must be a difference?
But I guess I just don’t understand (till now).
Besides this many more questions are in my head:
Does every “Dim” statement create a COM Object - that has to be released later on?
If not how do I detect whether a COM object has been created or not? Which “Dim” statements create COM object and which don't?
In this example: Dim ActiveWindow As Object = Nothing Try ActiveWindow = Me.HostApplication.ActiveWindow() Catch End Try
Is
Marshal.ReleaseComObject(ActiveWindow)
identical to
Marshal.ReleaseComObject(Me.HostApplication.ActiveWindow())?
According to this:
http://www.codeproject.com/Tips/235230/Proper-Way-of-Releasing-COM-Objects-in-NET
Would it not be better to release each "level" separately like this:
Marshal.ReleaseComObject(Me.HostApplication.ActiveWindow())
Marshal.ReleaseComObject(Me.HostApplication)
Marshal.ReleaseComObject(Me)
Overall: Am I trying to release too much? Or is it correct / good practie?
And what does "GC.Collect()" and "… = Null" have to do with all this? I have not used it at all. Should I better use it? Why? ( "... = Null" I have seen here:
http://www.codeproject.com/Tips/162691/Proper-Way-of-Releasing-COM-Objects-in-NET)
Why do I get “ShapeCount was not declared …” - Error if I try to do “Marshal.ReleaseComObject(ShapeCount)”? The same with “ShRange”. I think these are COM objects as well?!?
How do I notice when is the best time to release the COM object again? When I process/debug my code step by step with F11 will it be possible for me to determine the best (soonest) point of release? So far I have no “feeling” about when the COM object is not needed anymore and I can release it.
Any help and explanations very welcome.
Here is the code I am talking about:
Imports System.Runtime.InteropServices
Imports System.ComponentModel
Imports System.Windows.Forms
Imports AddinExpress.MSO
Imports PowerPoint = Microsoft.Office.Interop.PowerPoint
'Add-in Express Add-in Module
<GuidAttribute("D75C609E-7632-400F-8A6F-6A6E6E744E75"),
ProgIdAttribute("MyAddin8.AddinModule")> _
Public Class AddinModule
Inherits AddinExpress.MSO.ADXAddinModule
#Region " Add-in Express automatic code "
[…]
#End Region
Public Shared Shadows ReadOnly Property CurrentInstance() As AddinModule
Get
Return CType(AddinExpress.MSO.ADXAddinModule.CurrentInstance, AddinModule)
End Get
End Property
Public ReadOnly Property PowerPointApp() As PowerPoint._Application
Get
Return CType(HostApplication, PowerPoint._Application)
End Get
End Property
Private Sub AdxRibbonButton2_OnClick(sender As Object, control As IRibbonControl, pressed As Boolean) Handles AdxRibbonButton2.OnClick
MsgBox(GetInfoString2())
End Sub
Friend Function GetInfoString2() As String
Dim ActiveWindow As Object = Nothing
Try
ActiveWindow = Me.HostApplication.ActiveWindow()
Catch
End Try
Dim Result As String = "No document window found!"
If Not ActiveWindow Is Nothing Then
Select Case Me.HostType
Case ADXOfficeHostApp.ohaPowerPoint
Dim Selection As PowerPoint.Selection =
CType(ActiveWindow, PowerPoint.DocumentWindow).Selection
Dim WindowViewType As PowerPoint.PpViewType = PowerPoint.PpViewType.ppViewNormal
Dim SlideRange As PowerPoint.SlideRange = Selection.SlideRange
Dim SlideCountString = SlideRange.Count.ToString()
If WindowViewType = 9 And SlideCountString < 2 Then
Dim ShRange As PowerPoint.ShapeRange = Nothing
Try
ShRange = Selection.ShapeRange
Catch
End Try
If Not ShRange Is Nothing Then
Dim ShapeCount = ShRange.Count.ToString()
Result = "You have " + ShapeCount _
+ " shapes selected."
Else
Result = "You have 0 shapes selected."
End If
End If
'Marshal.ReleaseComObject(ShapeCount)
'Marshal.ReleaseComObject(ShRange)
'Marshal.ReleaseComObject(WindowViewType)
'Marshal.ReleaseComObject(SlideCountString)
Marshal.ReleaseComObject(SlideRange)
Marshal.ReleaseComObject(Selection)
Case Else
Result = AddinName + " doesn't support " + HostName
End Select
'Marshal.ReleaseComObject(Me.HostType)
'Marshal.ReleaseComObject(Result)
Marshal.ReleaseComObject(Me.HostApplication.ActiveWindow())
Marshal.ReleaseComObject(Me.HostApplication)
'Marshal.ReleaseComObject(Me)
End If
Return Result
End Function
End Class
The ReleaseComObject method of the Marshal class decrements the reference count of the specified Runtime Callable Wrapper (RCW) associated with the specified COM object, it doesn't release an object. It comes from the COM nature.
Typically you need to release every object returned from the Office (PowerPoint in your case) object model. Exceptions are objects passed to event handlers as parameters.
You may read more about that and find answers to your multiple questions in the When to release COM objects in Office add-ins developed in .NET article.
FinalReleaseComObject calls ReleaseComObject til it returns 0 which means release of COM object. Calling them in reverse order as in Excel objects(Application, Workbook, Worksheet) is the proper way to dispose of COM objects that are related.
Exception Condition
ArgumentException
o is not a valid COM object.
ArgumentNullException
o is null.

Powerpoint Visual Basic code not working

Recently I have been using a lot of macro visual basic in my PowerPoint. Everything was working fine and then I needed to add a Try and Catch statement. It seemed not to work but I thought maybe it changed in newer versions. Now after trying to make a dictionary in visual basic using PowerPoint the same thing happened. It didn't work and the text was red.
This is the code for the dictionary:
Dim test As New Dictionary(Of String, Integer)
test.Add("1", 1)
Is there anyway of adding dictionaries to it when using PowerPoint? or is this code wrong? The same thing with try and catch statements?
You need to ensure the reference to System.Collections.Generic is declared.
At the top of your code add:
Imports System.Collections.Generic
You are very unclear on the end result but try something like this.
Sub test()
On Error Goto Handler
Dim test AS New Collection
test.Add "1", "27"
test.Add 15, "Monkeys"
Exit Sub
Handler:
Msgbox "Error Number: " & Err & " Occurred. Its message text is: " & Error(Err)
End Sub
VBA Does not have Try and Catch you must handle all errors with On Error GoTo then you can process the Errors by the Error Number. See Here
Also note I used a Collection which uses an Item and Key structure. Not sure what you are going for with this but you can retrieve Items by Key in a Collection which might be fine for you. e.g.
test.Item(1) 'will return "1" by index
test.Item("27") 'will return "1" by key
test.Item(2) ' will return 15 by index
test.Item("Monkeys") 'will return 15 by key

Object Reference Error VB.NET

I keep getting an error:
System.NullReferenceException: Object reference not set to an instance
of an object.
Everytime I run the application outside the IDE, but for some magical reason, it works fine inside the IDE. I am definitely sure the error is caused by this code as the app ran smoothly when I removed it:
Public Function GetCommonFolder() As String
On Error GoTo ErrH
Dim winPath As String = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)
Dim commonfolderpath As String
commonfolderpath = Replace(winPath & "\MyApp Data", "\\", "\")
If My.Computer.FileSystem.DirectoryExists(commonfolderpath) = False Then
System.IO.Directory.CreateDirectory(commonfolderpath)
End If
GetCommonFolder = commonfolderpath
Exit Function
ErrH:
GetCommonFolder = ""
Msgbox("Error retrieving common folder")
End Function
Does anyone here know what is causing this annoying problem?
It seems like the user that you run the program on outside the IDE doesn't have access to the common application data folder. Try executing it by "Run as administrator". Are you running on Windows Vista or newer? Maybe you have to require UAC elevation?