VFP and .NET Interop
wwDotNetBridge difficulty getting started
Gravatar is a globally recognized avatar based on your email address. wwDotNetBridge difficulty getting started
  Terry Y
  All
  Aug 27, 2017 @ 03:11pm

I am attempting to interface my VFP program(s) to InterActiveBrokers.com and having difficulties. I have installed wwDotNetBridge and am using your simple program example:

clear
set default to "c:\Trident\"

#INCLUDE 'C:\TRIDENT\WCONNECT.h'
SET PROCEDURE TO 'C:\trident\wwUtils' ADDITIVE
SET PROCEDURE TO 'C:\trident\wwEval' ADDITIVE
SET PROCEDURE TO 'C:\trident\CodeBlockClass' ADDITIVE
SET PROCEDURE TO 'C:\trident\wwHTTP' ADDITIVE
SET PROCEDURE TO 'C:\trident\WWPOP3' ADDITIVE

SET CLASSLIB TO 'C:\trident\wwIPStuff' ADDITIVE
SET CLASSLIB TO 'C:\trident\wwXML' ADDITIVE

*** Load library and initialize wwDotnetBridge
do wwDotNetBridge
LOCAL loBridge as wwDotNetBridge
loBridge = CreateObject("wwDotNetBridge")
? loBridge.cErrorMsg

*** Load an assembly from disk
*loBridge.LoadAssembly("bin\OpenPop.dll")
loBridge.LoadAssembly("c:\TWS API\source\CSharpClient\activex\bin\Release\TWSLib.dll")
? loBridge.cErrorMsg

*** Create an instance of a class - note: No COM registration
*loPop = loBridge.CreateInstance("OpenPop.Pop3.Pop3Client")
loSSC = loBridge.CreateInstance("IBApi.EClient")
? loSSC.cErrorMsg

*** This won't work due to overloads
* loPop.Connect("pop3.server.net",587,.f.)

*** So, call indirectly instead
LoLogin = loBridge.InvokeMethod(loSSC,"Connect","127.0.0.1",7497,.f.)
? loLogin.cErrorMsg

return
Execution stops @ "loSSC = loBridge.CreateInstance("IBApi.EClient")" and I get the error message:

I am getting the "IBApi.EClient" from the documentation @ http://interactivebrokers.github.io/tws-api/namespaceIBApi.html#gsc.tab=0 and when I look at the left-column listing I see namespaces, and when I click-thru, I see reference to the namespace being: IBApi, and the first class listing is for: ECLient, which appears to emulate your code: *loPop = loBridge.CreateInstance("OpenPop.Pop3.Pop3Client"). I am confused!!

The source code provided with the API from InterActiveBrokers has source for the TWSlib.DLL as being: TWS.CS and when I look at the code there, I see:

/* Copyright (C) 2013 Interactive Brokers LLC. All rights reserved.  This code is subject to the terms
 * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */

using IBApi;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using System.Linq;
using System.Threading;
using System.Collections;

namespace TWSLib
{
    [ProgId("Tws.TwsCtrl")]
    [Guid("0A77CCF8-052C-11D6-B0EC-00B0D074179C")]
    [ComVisible(true), ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(ITwsEvents))]
    public class Tws: UserControl, EWrapper, ITws, IDisposable
    {
        static T GetCustomAtribute<T>(ICustomAttributeProvider t) where T : Attribute
        {
            var cas = t.GetCustomAttributes(typeof(T), false);

            if (cas.Length < 0)
                throw new KeyNotFoundException();

            return cas[0] as T;
        }

        [ComRegisterFunction]
        public static void Register(Type t)
        {
            var clsidSubKey = Registry.ClassesRoot.OpenSubKey("CLSID", true).CreateSubKey("{" + GetCustomAtribute<GuidAttribute>(new StackFrame().GetMethod().DeclaringType).Value + "}");
            var typelibguid = "{" + GetCustomAtribute<GuidAttribute>(Assembly.GetExecutingAssembly()).Value + "}";

            clsidSubKey.CreateSubKey("Control");
            clsidSubKey.CreateSubKey("TypeLib").SetValue("", typelibguid);
            clsidSubKey.CreateSubKey("Version").SetValue("", "1.0");
        }

So, I see a different namespace of TWSLib, not IBApi. So, I tried that namespace in the code, and I get the same error. I am now really confused!!

Why do I get an error?

Gravatar is a globally recognized avatar based on your email address. re: wwDotNetBridge difficulty getting started
  Rick Strahl
  Terry Y
  Aug 27, 2017 @ 11:38pm

You'll want to print loBridge.cErrorMsg not loSCC.cErrorMsg to see what went wrong. Most likely your parameters to the constructor are incorrect.

Whatever the C# code you're showing has nothing to do with the code you are calling so not sure what that is...

It also looks to me that what you're trying to call is already a COM object, so if this thing is installed on your machine, you can use it directly through COM without wwdotnetbridge. It looks like it's set up as an ActiveX control... +++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: wwDotNetBridge difficulty getting started
  Terry Y
  Rick Strahl
  Aug 29, 2017 @ 01:34pm

Boy, now I am really confused!!

I tried to use it like other APIs that I DO USE, but I was simply NOT able to even connect, leave alone execute functions in the .DLL so then I asked around and I got this suggestion from one fellow:

"I think you’d be far better off using the ActiveX API than trying to use or create some sort of middleware.   I don’t use Foxpro myself, but since it’s a COM host it should have no difficulty using the ActiveX dll, which works just fine in Excel, VB6 etc.   If you download and install the API from http://interactivebrokers.github.io/, the ActiveX API type library is automatically registered for you. This file resides in C:\TWS API\source\CSharpClient\activex\bin\Release, along with the TWSLib.dll which contains the ActiveX API binary.   To add a reference to your Visual Foxpro project, look for CSharpAPI in the ‘Available References’ list (I’ve no idea why IB don’t use something sensible for the visible name such as ‘IB ActiveX API v9.72’, but there you are).   Once you’ve added the reference, you should be able to browse the library using the Object Browser (I’m assuming that Foxpro uses the same Object Browser as all the other VBA-hosting applications and VB6 itself). You’ll find all the API methods, properties and events in the Tws class.   You have to create your Tws object explicitly – you can’t host it on a form. I don’t know Foxpro syntax but in VB6 or VBA you do this:   Private WithEvents mTWS As New TWS   Then you have the whole API at your disposal:   mTWS.connect(…)   Dim contract as IContract Set contract = mTWS.createContract(…)   mTWS.reqMktData(…)   etc."

So ... I went off and tried to find references to: "Private WithEvents mTWS As New TWS" and saw that perhaps I needed a COM SERVER. I tried some code I found which failed, so I searched on. Then I saw your "wwDotNetBridge" and figured that I should be able to connect with it. Again, I met with failure. I am not a newbee to VPF and using APIs, but really this thing has me befuddled.

You say it's already ActiveX API, but the ideas presented above suggest otherwise since VFP does not have this "Private WithEvents" built-in. That is why I thought your "wwDotNetBridge" would be a solution, but I am against the wall - again.

I would genuinely appreciate some help with this situation, at least to get to connect with the server and execute at least one function. If I get that much help, I am confident that I can do the rest I need done. How can I get from here to there?

Gravatar is a globally recognized avatar based on your email address. re: wwDotNetBridge difficulty getting started
  Rick Strahl
  Terry Y
  Aug 29, 2017 @ 04:01pm

The code you posted last time was COM registration code for the .NET DLL which to me seems to indicate that the API you are calling already has COM enabled features. This may or may not be the case, because we can't look at what you're working with.

Without knowing much more about what APIs that you are trying to call we're not going to give you a specific solution or help.

You need to look at the .NET APIs and their signatures to know how to call the code from FoxPro. If the code required to work with is complex and requires a lot of interaction with the component it may be easier to create a small .NET wrapper class and then call that from FoxPro with wwDotnetBridge. In many cases this is easier than trying to use interop to deal with the actual .NET interaction from FoxPro - it's possible but more work that way generally.

Either way you need to understand the APIs that you are trying to call and have access to the full call signatures including the constructors to instantiate the objects.

I recommend you take a look at the wwDotnetBridge article that describes how .NET COM interop works and how wwDotnetBridge enables many additional features that otherwise wouldn't be possible.

+++ Rick ---

© 1996-2017