Fehler beim Einbinden der FtMscLib.dll

Alles rund um TX(T) und RoboPro, mit ft-Hard- und Software
Computing using original ft hard- and software
Forumsregeln
Bitte beachte die Forumsregeln!
Benutzeravatar
hefeteig
Beiträge: 56
Registriert: 01 Nov 2010, 15:17

Fehler beim Einbinden der FtMscLib.dll

Beitrag von hefeteig » 13 Sep 2012, 20:55

Hallo, möchte gerne die FtMscLib verwenden um den TX Controller zu verwenden.
Ich benutze VS2010 und habe dort in ein Konsolenprogramm die FtMscLib.lib und die Headerdateien eingebunden.
Wenn ich das Programm nun compilieren bekomme ich etliche Fehler, aber eigtentlich immer den gleichen, VS versteht das DLLImp scheinbar nicht, es sagt immer
error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt
vermutlich mache ich einen Fehler beim Einbinden der Library gemacht, oder ich muss noch irgendwelche Projekteigenschaften ändern, ich weiß aber nicht was ich falsch mache,
habt ihr eine Idee?
Ich würd mich freuen, wenn ihr ne lösung hättet.
Gruß
Hefeteig

Ad2
Beiträge: 306
Registriert: 31 Okt 2010, 22:20

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von Ad2 » 14 Sep 2012, 09:41

Are you using the static lib or the import lib and dll?
When compiling as c++ you should also enclose the header in extern "C" {}

Benutzeravatar
hefeteig
Beiträge: 56
Registriert: 01 Nov 2010, 15:17

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von hefeteig » 14 Sep 2012, 17:14

I have some .libs in the directory "PC_Programming_RoboTXC\Common\Lib".

ftMscLib.lib
ftMscLib_debug.lib
FtMscLib_Static_LIBCMT_Release.lib
FtMscLib_Static_LIBCMTD_Debug.lib

Which shoud I use now?

And, is it enouth, then I say VS "vorhandenes Element hinzufügen"?
And I also do not understand what you mean with
"enclose the header in extern "C" {}".

Sorry, i am not good in including files and all this thinks, that you have to do,
before using the Libraries and Co.

Gruß Hefeteig

Ad2
Beiträge: 306
Registriert: 31 Okt 2010, 22:20

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von Ad2 » 14 Sep 2012, 22:59

The two small libs (without static) in their name are import libraries. These do not contain the library itself butjust stubs that call the actual functions in ftMscLib.dll. The static libs are real libraries and don't need the dll.
Just add one of the libs eg. the static release lib to your project.
The header file that you #include tells the compiler what the functions in the library look like so it can generate the proper calls. ftMscLib.h contains the following code:

Code: Alles auswählen

#if defined(_DLL_VER)
#define DLLImp extern "C" __declspec(dllimport)
#else
#define DLLImp
#endif
This means that when _DLL_VER is defined, all function prototypes will be preceded by extern "C" __declspec(dllimport), which tells the compiler that the function is C not C++ (which would mangle the name) and is to be found in a DLL.
if _DLL_VER is not defined, and I think that should be the case, DLLImp is defined as whitespace and the header contains normal prototypes suitable for both static libraries and import libraries. For the compiler and linker this makes no difference, the dll is loaded at runtime. I think the dllimport is only useful when you use a definition file.

If indeed DLLImp is defined as nothing, then the first word in each declaration is often DWORD which is not standard C and must be defined. It is typically defined in windows.h but as you are writing a console application you may not have included it. You can also define it yourself: #define DWORD unsigned
The compiler expects a type specifier like int, char, float etc. if it doesn't find one it assumes int (for C) but will not make that assumption for C++. I think this explains the error message. There are however many other symbols that are defined only in windows.h.
The other question is about extern "C". If you compile as C++, the compiler will generate function names that contain information about the argument list (name mangling), the names in the library however are compiled as C and are not mangled. Hence the linker will not be able to find these symbols and you will get linker errors. In order to avoid that, compile as C or write:
extern "C" {
#include "ftMscLib.h"
}
this tells the compiler not to mangle any function names in ftMscLib.h
Hope this helps

Benutzeravatar
hefeteig
Beiträge: 56
Registriert: 01 Nov 2010, 15:17

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von hefeteig » 15 Sep 2012, 21:18

Wow, thank you very much for your
detailed answer.
In fact, then I include windows.h, I have less mistakes (only 20),
after I had also included
#include "common.h"
#include "ROBO_TX_FW.h"
#include "BT.h"
VS compiles it with no errors,
So you are my hero.
But I have 70 warnings, all like this:
warning C4272: "StatusBtConnection": Ist als __declspec(dllimport) markiert. Beim Importieren einer Funktion muss eine systemeigene Aufrufkonvention angegeben werden.
It would not have interest me, but then I say ftxInitLib(); in main (), I get these errors:
- error LNK2031: p/invoke konnte nicht für ""extern "C" unsigned int __clrcall ftxInitLib(void)" (?ftxInitLib@@$$J0YMIXZ)" generiert werden. In den
Metadaten fehlt die Aufrufkonvention.

- error LNK2028: Nicht aufgelöstes Token (0A00000C) ""extern "C" unsigned int __clrcall ftxInitLib(void)" (?ftxInitLib@@$$J0YMIXZ)", auf das in Funktion ""int
__clrcall wmain(int,wchar_t * * const)" (?wmain@@$$HYMHHQAPA_W@Z)" verwiesen wird.

- error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""extern "C" unsigned int __clrcall ftxInitLib(void)" (?ftxInitLib@@$$J0YMIXZ)" in Funktion
""int __clrcall wmain(int,wchar_t * * const)" (?wmain@@$$HYMHHQAPA_W@Z)".

- error LNK1120: 2 nicht aufgelöste externe Verweise.

Now I have really no idea, how to run my program.
I hope you or someone else have a solution.
Or an idea.
Gruß Hefeteig

Ad2
Beiträge: 306
Registriert: 31 Okt 2010, 22:20

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von Ad2 » 15 Sep 2012, 21:50

It seems you are using VS for .NET, the ftMscLib is however native code. Calling native code from managed code is possible but has some peculiarities. I did this some time ago from C# and I remember that it was not so easy, especially callbacks. So compiling your application as native code would be easier. Why are you using .net?

Benutzeravatar
hefeteig
Beiträge: 56
Registriert: 01 Nov 2010, 15:17

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von hefeteig » 15 Sep 2012, 22:47

You are right, I am using .Net, but when it is necessary to not use .Net, i will do what, but where can I say the Projekt, to not use .Net?
Gruß Hefeteig

vleeuwen
Beiträge: 1557
Registriert: 31 Okt 2010, 22:23
Wohnort: Enschede (NL)
Kontaktdaten:

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von vleeuwen » 15 Sep 2012, 23:31

Hi
I am using the FtMscLib at .NET level for the integration of the TX-C into the MS-Robotics Developer Studio platform.
Ad has right, the call back do not operated well in a lot of cases.
The best work arounf for the moment is to write you own wrapper to come from unmanaged C to managed C++.

Ft-computing has the same problems. In his examples are the Callback also not implemented.
I hope that there will be a native managed version of the FtMscLib in the near futur

Benutzeravatar
hefeteig
Beiträge: 56
Registriert: 01 Nov 2010, 15:17

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von hefeteig » 16 Sep 2012, 00:25

What would be the best.
I used sqlite (database) in normal c++ and had luck, to find a library for using it also in C++/CLI.
But I do not need .Net really, so is there a way to disable it?

Ad2
Beiträge: 306
Registriert: 31 Okt 2010, 22:20

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von Ad2 » 16 Sep 2012, 10:34

As a Borland user I'm not an expert here but it seems that when you create a new project (in VS2010 professional or in VS2008 express) you can choose CLR (managed .net code) or WIN32 (native code). So create a new project, add your source files and lib and recompile. A harder way is to make a wrapper using P/invoke (there is a lot of documentation on msdn but it is not easy). The hardest way would be to build your own managed ftMscLib (van Leeuwen would love it), this means you bypass the ftMscLib.dll completely and access the virtual comport directly (create your own implementation of X1).
Good luck

Ad2
Beiträge: 306
Registriert: 31 Okt 2010, 22:20

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von Ad2 » 16 Sep 2012, 12:05

Some time ago I wrote a wiki article about using the ftlib (not ftMscLib) in different programming environments.
I have never posted that article, but here it is, maybe it is of help
When using ftlib some issues may arise, in this wiki I address some of them.

This wiki is intended for fischertechnik users that are comfortable with programming on a PC in Borland C++ builder, Visual C++ or Visual C#.

The ftlib package was provided to make it possible to control a RoboInterface (RI) from a PC with conventional programming languages (i.e. not RoboPro). The main use of the library is to use the RI in online mode and control the outputs from the PC and read the inputs from the RI into the PC. Other uses comprise: interfacing with e.g. RoboPro by means of messages and reading and writing RI memory to interface with a user program running on the RI.

The ftlib is available for download from the fischertechnik site, the current version is V1.70a. The download contains a.o. the library, documentation and examples. A wrapper encapsulating most of the ftlib is available on http://www.ftcomputing.de.

The API as made available in the header files is written in C and the examples are in Visual C++.
The use with Visual C++ is relatively easy although the examples are quite startling. The ftlib API is pretty well documented and including the lib is as easy as including ftlib.h in your source files and adding any of the four static libraries to your project.

Things become more complicated when using the ftlib.dll as a library. There is an example that shows how to do this but that example uses only one source file that actually uses the ftlib. It is quite possible to confine all calls to the ftlib to a single source file but we do not always like this restriction. The restriction is caused by the fact that the header file ftlibdllfunc.h not only contains declarations but also definitions (this is considered bad practice and now it is haunting us). The header contains the following definitions:
The instance handle of the DLL;
Function pointers for each DLL entry;
LoadFtLibDll and UnloadFtLibDll functions.
The presence of these definitions makes that this include file can be included in the project precisely once. Inclusion in a further source file will make the linker complain about multiple definitions of a symbol. On the other hand, not including the header will make the compiler complain about undeclared symbols. A solution seems to be to include ftlibdllfunc.h in one source file and the regular ftlib.h in all other source files. Alas, this does not work either, the linker sees the definition in ftlibdllfunc.h and the declaration in ftlib.h as distinct. This is caused by the fact that the DLL entry points are defined as function pointers [type (*func)();] whereas the declarations are for functions [ type func();]. The difference is an extra level of indirection that often goes unnoticed because C accepts both (*funcptr)() and funcptr() to call a function indirectly. For the file including the ftlibdllfunc.h the compiler will generate indirect calls and for the file including ftlib.h the compiler will generate direct calls, the linker subsequently cannot handle this and issues error messages.
The solution to the problem is to adapt the ftlibdllfunc.h header in such a way that it includes the definitions in one module only (e.g. with a preprocessor symbol defined in precisely one source file) and contains the proper declarations only for every other source file.

//ftlibdllfunc.h
#ifdef LOAD
#define EXTERN

HINSTANCE hFtLibDLL;

#else
#define EXTERN extern
#endif

typedef DWORD (__stdcall *DLL_GetLibVersion) (void);
.
.
EXTERN DLL_GetLibVersion GetLibVersion;
.
.
#ifdef LOAD
DWORD LoadFtLibDll(void)
.
.
#endif

The effect is that symbols that we don’t need in other modules are not declared/defined and those that we do need are declared as extern. So this modified ftlibfuncdll.h can be included in every source file and only in the source file that loads the library shall be preceded by
#define LOAD
The other include file ftlibdll.h contains only declarations and must be included in every source file.

This problem is not specific to Visual C++, we encounter the same problem in Borland C++ Builder. In Builder we must use the DLL because we cannot use the statically linked library. The libraries provided by fischertechnik are in COFF format but Borland requires them to be in OMF format. The utility coff2omf does not do a proper conversion because it is intended for import libraries (libraries that just provide entrypoints to DLL functions). The static ftlib libraries are not of this kind.
We can however try to create an import library from the ftlib.dll with the Borland provided IMPLIB utility. This works fine but the functions have to be declared as extern “C”.

extern “C” {
#include “ftlib.h”
}

Of course the newly created import library has to be added to the project and the ftlib.dll has to be in the path or in the directory of the executable.

The .Net framework and C# are becoming increasingly popular. Using ftlib requires a different approach because the ftlib.h header file cannot be used. Linking the ftlib.dll is however very easy, an import library is not required nor are calls to LoadLibrary and GetProcAddress.
An ftlib function is simply declared as for example:

[DllImport("ftlib.dll")]
public static extern UInt32 GetLibVersion();

This declaration is placed inside the class where we want to use it. The main difference with the original declaration is the return type UInt32 which is the C# equivalent of DWORD.
With some simple substitutions we can call any function in ftlib.dll.


Ftlib C#
FT_HANDLE IntPtr
LPCSTRING string
DWORD UInt32
DWORD* out UInt32
USHORT* out UInt16
UCHAR byte

The trouble starts only when we pass or return pointers to structures. The most important structures are FT_TRANSFER_AREA, NOTIFICATION_EVENTS and SMESSAGE.
Each structure has its own peculiarities. FT_TRANSFER_AREA consists of relatively simple types that can easily be translated but it also has some arrays. C# arrays are objects and the array declaration in a struct will be translated into a reference to the actual array object on the heap. The way to circumvent this is to declare the struct as ‘unsafe’ which allows us to use ‘fixed’ arrays which follow syntax and semantics similar to C.
Furthermore the struct has to be declared with a pack size of 1 (which apparently is not the default).

[StructLayout(LayoutKind.Sequential, Size = 0x200, Pack = 1)]
public unsafe struct FT_TRANSFER_AREA //unsafe because of fixed buffers
{
public UInt32 E; //0
UInt64 rsvd1; //4
// more members
public fixed byte MPWM[32]; //50
// etc...
}

The SMESSAGE is actually a C union, this can be simulated in the following way:

[StructLayout(LayoutKind.Explicit, Size = 6, Pack = 1)]
public unsafe struct SMESSAGE
{
[FieldOffset(0)]
public byte ucHwId;
[FieldOffset(1)]
public byte ucSubId;
[FieldOffset(2)]
public UInt16 uiMsgId;
[FieldOffset(4)]
public UInt16 uiMsg;
[FieldOffset(0)]
public fixed byte aucMsg[6];
[FieldOffset(2)]
public UInt32 dw;
}


The FieldOffset attribute places each member at the appropriate place.
The NOTIFICATION_EVENTS structure is more complicated because it comprises mostly pointers. Two of these pointers are pointers to functions. The C# most natural equivalent is the delegate. Unfortunately structs (which are value types) are sometimes more restrictive than classes (which are object types). In this case I decided to use a class, the handles are substituted by IntPtr’s and the function pointers by delegates.

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void callback_t(IntPtr context);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void msgCallback_t(ref SMESSAGE msg);

[StructLayout(LayoutKind.Sequential)]
public class NOTIFICATION_EVENTS
{
// Callback-Procedure
public callback_t NotificationCallback; // Pointer to the Callback-Procedure
// public IntPtr Context; // Pointer to the Context for the Callback-Procedure
public object Context; // Pointer to the Context for the Callback-Procedure

// for SetEvent()
public System.IntPtr hEvent;

// for posting a Message (PostMessage() with wParam & lParam = 0)
public System.IntPtr WindowsHandle; // handle to the destination window
public UInt32 Message; // message ID

// Callback-Procedure for Messaging
public msgCallback_t CallbackMessage; // Pointer to the Callback-Procedure for Receiving Messages
}


This all looks pretty straight-forward but we have to be aware that we make calls from a managed environment (where memory is managed by a garbage collector(GC)) into an unmanaged environment (where we or ftlib are responsible for the memory management).
To complicate matters, ftlib stores pointers into managed memory and makes calls back into managed memory. The big issue here is that the GC may deallocate chunks of memory or move around pieces of memory without asking or even telling us. The danger is that we pass e.g. a pointer to a struct to ftlib and by the time ftlib decides to use that pointer the actual struct may have been moved. Within C# this is not a problem because the GC updates all references accordingly but the GC has no jurisdiction over unmanaged memory. The so called interop services help us a great deal however. Two special interface elements are important, thunks and GCHandles. These are objects that live in both worlds, they stay at a fixed address but contain references that are updated by the GC. Another solution is to pin certain managed objects to a fixed place in memory, which although possible is quite restrictive.
A thunk is implicitly generated and makes sure that ftlib can call the delegate that was passed to ftlib. We only have to make sure that the delegate (which is an object by itself) stays alive. This is most easily accomplished by declaring it static or in an object with the same lifetime as the connection to the interface device. For data pointers like the Context pointer we need to explicitly allocate a GCHandle (that is, if we need a Context pointer because we can do without). A GCHandle has methods which give a pointer that can be passed to ftlib and vice versa. It also has members which refer to the original managed object.
The callback delegates can elegantly be used in combination with events. Other objects simply subscribe to the event and they get called when an interface device sends an update. It is however still the case that these events are called in the context of the callback thread, so they must be brief and cannot easily interact with the GUI. For display purposes it is therefore much more convenient to use the windows handle and message. For the handle we best use the handle of the main window which can be obtained by:

Ne.WindowsHandle = Process.GetCurrentProcess().MainWindowHandle;
Ne.Message = WM_USER+2000;

WM_USER is a windows constant (equal to 1024) and the value of message must be above this. The messages can be caught in the main window (Form) of the application like this:

// Override WndProc to handle new messages
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_USER + 2000: //notification that the TA was updated by the ft interface
// handle your message
label4.Text = "Hello! " + ((Form2.localdata)(open_intf_form.gch.Target)).i.ToString();
break;

// handle other messages
default:
base.WndProc(ref m);
break;
}
}


vleeuwen
Beiträge: 1557
Registriert: 31 Okt 2010, 22:23
Wohnort: Enschede (NL)
Kontaktdaten:

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von vleeuwen » 16 Sep 2012, 13:09

It is very easy to use Microsoft Visual Studio without the dotNET framework.
In that case you need to choose for an unmanaged project.
See the basics for MS-VS and the very good help inside Visual Studio.

However in that case you are also not able to make use of the dotNetwork feature but that is obvious.

Benutzeravatar
hefeteig
Beiträge: 56
Registriert: 01 Nov 2010, 15:17

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von hefeteig » 18 Sep 2012, 16:43

Thank you very much for your help,
my question now, is, how can I write a Wrapper?
I already tried this http://msdn.microsoft.com/de-de/library ... spx#ID0EMC, but
that comes to the same mistakes.
Have someone an example?
Gruß Hefeteig

Ad2
Beiträge: 306
Registriert: 31 Okt 2010, 22:20

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von Ad2 » 18 Sep 2012, 17:29

Remember that you don't need a wrapper when you use only unmanaged code. But if you want to go the hard way you have to write a module that forwards every call that you need to the unmanaged ftMscLib.dll. For functions that use only simple types this is straight forward. For complex types it is difficult. I don't have an example for C++ but I once wrapped most of the ftlib API in a C# class using the techniques I've outlined in my previous post. Starting with zero knowledge about C# and .Net it took me weeks to write that wrapper, so consider carefully if you really want to go that route.

Benutzeravatar
hefeteig
Beiträge: 56
Registriert: 01 Nov 2010, 15:17

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von hefeteig » 18 Sep 2012, 17:51

Okay, then it is so difficult, I will find an other way.
I thought about 2 programms, which running at the same time.
One is responsable for the ft hardware, the offer one can be a .Net application, what processes the
datas, which I give it by the hardware program.
It is a little bit complicated, but it should function.
I only need a way to exchange datas between programms.
What do you think about my idea?
Gruß Hefeteig

Benutzeravatar
steffalk
ft:pedia-Herausgeber
Beiträge: 1792
Registriert: 01 Nov 2010, 16:41
Wohnort: Karlsruhe
Kontaktdaten:

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von steffalk » 18 Sep 2012, 19:49

Hello,

If you *really* want to go with two distinct processes, then you have to deal with inter-process communication. If one process is unmanaged code, WCF isn't an option, but named pipes are relatively convenient. You just open a pipe on the listening "Server" process, secure it with an ACL (as a best practice; a NULL ACL will allow anyone (!) to talk to the Server), and open the same pipe in the "Client" process. Then what you write into the pipe on one end can be read on the otherone (two-way communication over a single named pipe is possible). You may exchange binary data, or you may define a simple text-based protocol. .NET has nice wrapper classes for named pipes, but they are also relatively easy in unmanaged code (see MSDN).

Regards,
Stefan

Ad2
Beiträge: 306
Registriert: 31 Okt 2010, 22:20

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von Ad2 » 18 Sep 2012, 20:04

I think it creates new problems, I don't know if it is worth it. I thought you didn't need .net, why do you need it?
If you really do need it, please investigate which functions from ftMscLib you really need. Maybe you are lucky and they are simple to wrap. Direct access to the TA is dificult and callbacks are dificult. The rest may be doable so try that first.
There are lots of examples on msdn. Look for p/invoke (for example calling win32 from managed code).
http://msdn.microsoft.com/en-us/library ... s.80).aspx

Benutzeravatar
hefeteig
Beiträge: 56
Registriert: 01 Nov 2010, 15:17

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von hefeteig » 18 Sep 2012, 21:03

I do not know what I really want.
I can live without .Net.
But it is better with it.
I will try out both methods.
However, thank you very much for your help.
Hefeteig

vleeuwen
Beiträge: 1557
Registriert: 31 Okt 2010, 22:23
Wohnort: Enschede (NL)
Kontaktdaten:

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von vleeuwen » 18 Sep 2012, 23:28

Based on your questions I like to ask you: what are your skill levels for C# and C++ software development?

In case your main objective is progrmming for Robotics I like to suggest to switch to MS-Robotics Developer Studio.
In MS-RDS you are able to stay very close to the Robotic problem, make use of a very good visual programming language and in case you prefer to program text based, you don't see the low level problems and the conversion problem from unmanaged to managed code.
The text based program is done inside a framework and delivers as spin off a new visual programming element.

Benutzeravatar
hefeteig
Beiträge: 56
Registriert: 01 Nov 2010, 15:17

Re: Fehler beim Einbinden der FtMscLib.dll

Beitrag von hefeteig » 19 Sep 2012, 21:48

I tried to use the visual programming language, but
I did not find the elements (the simbols for drag and drop on the left sight) to use Ft, like it is documented.
While reading about this problem, I found out, that these elements are not
included in the Version 4.0.
But maybe, you can say me, how I can use Ft in Robotic Studio?
I would be grateful.
Gruß Hefeteig

Antworten