Are there any other options to use apart from the activex controls.
We are trying to add the CsiCoraScript and CsiDataSource as member variables of one of our classes, but we are unable to hook into the events because we don't have a window or control to attached the activex control to.
We have used the visual studio wizard to generate the class files.
We are using c++.
Any ideas as to how we can get around this?
It sounds like you are trying to create a "console" application that uses the SDK. We have had customers do this before with success, but there are some extra steps to be performed in the configuration of the project. As you have already discovered, the ActiveX controls in the SDK rely on some of the "Windows Forms" objects to participate in the process of capturing events and responding to them. So if the ActiveX control is not hosted on a windows form, special/additional action is required.
Here is the list of steps we have for setting up a C# application as an SDK app. This has not yet been tried with C++, but you may be able to adapt it and get where you need to go. I'll give you this for now to try, and then see what we can work up for C++ and send that along later. Please give special attention to the "Windows Messaging Pump" (Step 6) as that is one of the key concepts for succeeding within an SDK console application.
-------
9 Steps for creating a LoggerNet SDK Console Application in C# .NET
1.Create your project as a console application
2.Add key references to the Project
3.Include "System.Windows.Forms" as a reference
4.Include the desired SDK control "type library" as a reference
5.Be sure to put "using System.Windows.Forms;" in your list of directives
6.Use "Application.Run()'" in your Main routine. This does two things: 1) It starts the "Windows Messaging Pump" and 2) It blocks (i.e. prevents) the application from exiting so it can wait for events to trigger/fire.
7.Declare your SDK control class properly
8.Insert the proper event definition(s). These are similar to definitions that are inserted automatically in windows “forms” applications.
9.Insert the proper event handler routine(s)
I've confirmed the steps needed to implement a LoggerNet SDK console app in C++.
I've temporarily posted the information here:
ftp://csicust:cr1000@ftp-ae.campbellsci.com/SDKConsoleAppforC++.pdf
A sample application can also be temporarily
found here:
ftp://csicust:cr1000@ftp-ae.campbellsci.com/SDKConAppCPP.zip
Here are the 10 steps:
1.Create your project as a CLR console application
2.Add key references to the Project (see steps 3 and 4)
3.Include "System.Windows.Forms" as a reference
4.Include the desired SDK control "type library" as a reference
5.Be sure to put "using namespace System::Windows::Forms;" in your
list of utilized namespaces in AssemblyInfo.cpp
6.Use "System::Windows::Forms::Application::Run();" in your Main
routine. This does two things: 1) It starts the "Windows Messaging Pump"
and 2) It blocks (i.e. prevents) the application from exiting so it can
wait for events to trigger/fire.
7.Declare your SDK control class properly
8. Insert the proper event definition(s). These are similar to definitions
that are inserted automatically in windows “forms” applications.
9.Insert the proper event handler routine(s)
10.Put in some code that will trigger the events of the control
Alternatives for using ActiveX/COM controls are as follows:
Use the JavaSDK. You don't have the full functionality of LoggerNet, but you can write custom programs to connect to
a datalogger and collect its data. This is easiest when you have TCP/IP connectivity with your dataloggers.
http://www.campbellsci.com/java-sdk
Use the "freely downloadable" BMP5 SDK. This is a
classic windows DLL. It has only basic functionality
for connecting to a datalogger and retrieving data.
http://www.campbellsci.com/bmp5
See also:
http://www.campbellsci.com/sdk
version using MFC or ATL?
Thanks for making the example.
This software will also be run as a service.
Another alternative to the ActiveX controls is to use a web api call to get the data via HTTP (if you have a CR1000, CR3000 with NL115/NL120 or CR800 series with PPP connection)
Take a look at "Web Server/API Commands" in the CRBasic Editor online help. Data can be queried out of the logger in html, json, toa5, tob1, xml format.
RE: MFC or ATL console SDK app:
There are extensive and complete MFC C++ examples included with the SDK (patch up to v4.1 if you need to). These are not console applications, but your task would be to take the MFC application examples shown and put them into a console application.
Here are some articles that could give you some guidance:
http://www.codeproject.com/Messages/1234257/Re-Using-ActiveX-wrapper-class-in-MFC-console.aspx
http://www.codeproject.com/KB/COM/consoleactivex.aspx
I have something running now, but CoraScript is causing exceptions. It doesn't always fail on the same line when calling "executeScript". Which is making it harder to track down.
Are there any know issues with using corascript?
I am using the following to create it
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
IID_ICsiCora, (void**)&CsiCora);
I am using the same code to create a CsiDataSource aswell.
If i run just the code using the datasource control it is working fine.(creating an advisor and handling the OnAdviseRecords event). I can run this multiple times without any errors.
With the script control i am using the following commands(in this order using async)
- move-device
- selective-manual-poll
- table-data-index
Once those commands are processed i create an advisor and wait for the "OnAdviseRecords" Event.
But during the execution of those commands corascript is causing exceptions. The exception occurs on any of the commands above.
Example
> CsiCoraScript.dll!08690a91()
[Frames below may be incorrect and/or missing, no symbols loaded for CsiCoraScript.dll]
ole32.dll!774fd430()
oleaut32.dll!77124a44()
ole32.dll!774fd430()
oleaut32.dll!77124a44()
CsiCoraScript.dll!08769a0e()
CsiCoraScript.dll!086db91f()
user32.dll!7e418734()
user32.dll!7e418816()
user32.dll!7e4189cd()
user32.dll!7e418a10()
ole32.dll!7753049a()
ole32.dll!77526949()
ole32.dll!7752687c()
ole32.dll!774fe3ee()
ole32.dll!774fe456()
kernel32.dll!7c80b729()
Are you running the executeScript method
synchronously or asynchronously ?
(see section 15.1.2, page 15-3 of the server SDK manual)
http://www.campbellsci.com/documents/manuals/loggernet-server-sdk.pdf
---
use the second parameter to determine whether the method performs asynchronously or synchronously. If you want this command to execute synchronously, pass in a zero (0) for the asyncID. If an asyncID other than zero (0) is specified, the onScriptComplete() event will be triggered with the result and the asyncID that was specified.
---
I would recommend that you work out the details of running
the command synchronously first before you try it
asynchronously.
Also, what version of the SDK are you using ? 2.2 ? 2.3 ?
4.0 ? 4.1 ?
What happens when you run a corascript with the MFC C++ sample application ? Does that work without a crash ?
Have you looked through the MFC C++ sample app for ideas
on how to use the control ?
I am running the script asynchronously. Just passing in the number one as the parameter.
I am using version 4.1.6.0 of the CsiCoraScript.dll and the CsiDataSource.dll.
Running the already compiled MFC examples run fine. Although the application is using it a bit differently to how i am(I'm using the CoCreateInstance instead of using the dataexchange to assign it to a member variable).
Also as i said i can run just the CsiDataSource part of the program and it runs fine without any exceptions.
Let me ask you one last thing before we start diving into the low-level details of your program.
What happens if you ensure that the three different corascript calls each use a different AsyncID ? My current understanding is that all three calls are using "1"
for the AsyncID. That could cause some confusion, as
there could possibly be three transactions in process
all at the same time that have the same ID. If one
of them happens to finish before the others then
that could get the control confused.
You would probably only have success using "1" for the
AsyncID as long as you could ensure that each script finishes before that was launched after it. If you put in "zero" to force the calls to be synchronous, does it eliminate the exceptions ?
I will change the numbers.
But I only execute the next command once the previous one has completed.
running it synchronously is working without causing any of the exceptions.
Problem is we need to run it in async mode
the part of the software running this code is run in another thread.
CWinThread *pThread = AfxBeginThread(MyThreadProc, 0);
Hello Hilltop,
Did using unique AsyncIDs help ?
I'm going to have you review the information below
about the Single Threaded Apartment limitations of
the SDK controls. If that information doesn't lead
you to a solution, then we are next going to need
to duplicate your issue in-house and run it in our
debugger IDEs. That would require you to create a very
minimal version of your program that does very little
except duplicate the issue. We need you to send us that
code. You will have to contact customer support at 435-227-9100 and ask for the SDK support specialist.
At that point you can get an email contact for sending in your source code.
----
The ActiveX controls are registered as "Single Threaded Apartment" (STA) controls. They are actually registered with the "Single" Threading model, which maps to the "Legacy STA" Apartment model. What this means is that they will always run within the first Single threaded apartment that is created.
The most important thing to consider in all this is to be sure you know which thread events are executing on. We suggest that you output the thread ID and be sure it is what you are expecting.
Here is a great article that discusses apartment models:
http://www.codeproject.com/KB/COM/CCOMThread.aspx
Please be aware that the ActiveX controls will only work correctly when installed and run as Legacy STA.
Just like to let you know that i have a version running now, not using the async option.
Running the ExecuteCommand in another thread.
Thanks for your help.