I have to rebuild software that was written in C++/MFC & Unicode. There are two assemblies, one Server and one Client. The Client has to be rebuilt in C#+WPF.
Originally there was a .h file included by both assemblies, to share some global values. I want to use these values in the new C# assembly, too.
My first approach is to use SWIG. So I created a test-Project (that Outputs a DLL) that contains the .h file and let do SWIG its Magic.
This results in a C++ Wrapper for the C++ Project and some .cs files.
Then I created a C# WPF application, included the DLL and the generated cs files from swig.
So far so good.
The .h file contains basically int variables, classes that contain an enum each and some LPCTSTR strings (that are wchar_t * since I use Unicode).
const LPCTSTR ProductName = _T("XYZ");
const int MAX_MESS_ITEMS = 200;
class SPS
{
public:
enum SPS
{
SPS1 = 1,
SPS2 = 2,
SPS3 = 3,
};
};
Using the int and enums is no Problem, but swig isn't able to convert the LPCTSTR to C# string (without doing some customizing). Swig generates a SWIGTYPE_p_LPCTSTR type which does not allow me to get the original Content of the string as defined in the .h file.
As a next Approach I walked through the SWIG Documentation (I use version 3.0.12) and found out about typedef and typemaps.
I tried to include the windows.i and that gave me the first letter of the string assigned to a LPCTSTR variable.
Next I tried to figure out how to use a typemap for this, but I can't get this to work. For me it is pretty difficult to understand how to create a typemap (I have some Problems understanding what is done there and how the Syntax works). Also the lib (that I downloaded with the swigwin.zip) that contains some typemaps for std::string etc. does not help me.
Also Research on stackoverflow and MSDN did not take me closer to a solution.
Are there any good instructions or examples on how to crate a typemap for converting strings (especialy LPCTSTR) ?
What other easy-to-use tools can make the Job? Should I stop using SWIG and use _declspec(dllexport) stuff (with what I don't have any experience)?
I'm not in the Need to convert functions or highly-desgined classes. Just the strings, int, and enums.
Since the two assemblies are communicating over a namedpipe, I concerned to send some data over the pipe when starting the applications, but there are some Information from the global variables needed before the pipe starts doing its work.
Any help concerning this is appreciated :)
Related
A third-party app I have can call extension DLLs if they have C-compliant interfaces as described below.
I would like the third-party app to call my C# DLL, since I would rather write in C# than C. (Maybe my other choice would be to write a C DLL wrapper to call my C# DLL, which is an extra step that I might not get right).
I've searched the net and SO but haven't found (or recognized) a good match to my question.
The best suggestion seemed to be this special marshalling declarations in the C# code here: Calling a C# DLL from C; linking problems
Is it possible to write a C# DLL that has a C-compliant interface like the one below? If so, could someone tell me what I have to do or point me to some documentation?
The third-party app documentation says, "The DLL function must be a PASCAL function that takes a single LPCSTR (long pointer to a constant string) argument. C or C++ DLL functions called must have prototypes equivalent to:
extern "C" __declspec(dllexport) void __stdcall fn(LPCTSTR szParam );
Take a look at this article: https://www.codeproject.com/Articles/12512/Using-the-CDECL-calling-convention-in-C-changing
It discusses a different problem (opposite to yours) but also explains the linkage of C# functions - by default C# uses __stdcall (and it cannot be overridden). This means your third party app should be able to call the C# function as it stands. Have you tried it? Did you get any errors?
Suppose I have a dll written in pure C. I have an inculde file (.h) so I can use the dll from a VS 2012 C project.
Is there any way to generate a C# wrapper class based on the metainfo in the include file, or I must write all the [DllImport]... manually? The C source code for dll is also available.
(Please note: This is not a COM library)
Thanks in advance
There are tools that can help, but by and large you have to write the wrapper code yourself to some degree. The main reason being that a C header file does not fully specify the interface. For instance, consider this function:
void foo(int* x);
Does this function receive a pointer to a single int, or does it receive a pointer to an array? There's no way for you to tell with just this information. So, any tool that creates wrappers must also use some form of annotation to fully describe the semantics of the functions. If those annotations are not present you would need to create them. At which point it probably becomes quicker and easier to write the wrapper manually.
As an alternative to writing C# pinvokes you can use a mixed mode C++/CLI assembly. This can include the header file and link against the import library. Then all you need to do is write a C++/CLI ref class to wrap the interface, and add the C++/CLI assembly as a reference to your C# project.
Introduction to the problem:
I've got to control a certain device through API provided with a DLL file, LIB file, and c header files whose functions are declared as dllimport.
When I use the API in a C++ project everything worked just fine - I included the headers, lib , dll, and called the functions as declared in the header files.
The problem begins when trying to call those functions from a C#.NET project, using [DllImport] attribute: The functions were declared with the exact name and parameters, and running the code did not throw any exception. And yet the device did not respond at all, like the functions had never been actually called.
How it is declared in the C header:
int __declspec(dllimport) Init_Card_RTx(unsigned short device_num, unsigned short enabled_channels, unsigned short xmt_channels);
How it is declared in C#:
[DllImport(Path, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Init_Card_RTx")]
public static extern int Init_Card_RTx(UInt16 device_num, UInt16 enabled_channels, UInt16 xmt_channels);
The questions:
Is that because the functions in the headers are declared dllimport?
In that case, do I have to wrap the DLL with C++ functions declared as dllexport?
What are the steps required for a C DLL to be accessible from C#?
In the C# project, do I have to include the LIB file as well? not just the DLL file itself?
Is that because the functions in the headers are declared dllimport?
Possibly. The functions need to be exported. Whether they are exported or not depends on how they DLL was compiled by whoever gave it to you. I'd guess that they should be though (or the C++ code would try import them and fail).
The first thing I do when troubleshooting this kind of thing is to load the DLL in Dependency Walker which will show you all the exported functions. If they're not showing up, they're not exported, and C# can't call them. If they are showing up, then you're ok and you don't need to change any of your C code or create any wrapper functions.
In that case, do I have to wrap the DLL with C++ functions declared as dllexport?
No. C# can only call C functions using DllImport. C++ does name mangling when exporting functions, which makes things a mess and generally not workable.
What you need to do is make your functions exported somehow. My guess is that they are already exported, but if not, you could make some wrapper functions like this.
int __declspec(dllexport) Init_Card_RTx(unsigned short device_num, unsigned short enabled_channels, unsigned short xmt_channels) {
// just call the other function here
}
These should make the function exported and you should see it show up in dependency walker.
What are the steps required for a C DLL to be accessible from C#?
The CLR has to be able to find the dll (usually you just put it in the same directory as the C# exe), and the functions have to be exported as C functions. That's pretty much it.
In the C# project, do I have to include the LIB file as well? not just the DLL file itself?
You don't need to include anything in the C# project at all, just the public static extern wrapper functions with their DllImport attributes on them. So long as the CLR can find the dll at runtime, that's all you need. If it can't find it at runtime, you should get an exception when you call the first imported method.
PS: Get Dependency walker. I can't recommend it more highly for this kind of thing
This kind of thing is always a pain in the butt. You have to make sure that the byte structure of the data being passed matches what your DLL is expecting, and exactly. The native structures in C# don't know that they are being passed externally, so you have to structure the code more rigorously.
See here for more info:
http://msdn.microsoft.com/en-us/library/awbckfbz(v=vs.110).aspx
The reason the functions are declared as dllimport is (correct me if I'm wrong) the the DLL is provided by your card vendor, that's ok because dllexport is only needed when building the DLL.
[DllImport(Path, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Init_Card_RTx")]
The first argument Path is there only for ilustration purposes, am I rigth?
Can you open the DLL with depends.exe or PE Explorer(http://www.heaventools.com/download-pe-explorer.htm) and see the DLL's export table?
I'm asking this because the function name maybe decorated, that could happen if the DLL was compiled as C++ instead of plain C.
Try declacring it like this (you only do this once, in a CPP file, NOT a header)
extern "C" __declspec(dllexport) int __stdcall Init_Card_RTx(unsigned short device_num, unsigned short enabled_channels, unsigned short xmt_channels)
{
//
}
and in C#:
[DllImport("MyDll.dll")]
int Init_Card_RTx(ushort device_num, ushort enabled_channels, ushort xmt_channels);
you need to export it and declare with extern "C". __stdcall is convenient as it's the default on the .net side. I have a macro in my C++ project to make sure I type it the same everytime.
And yes, get dependencywalker....
I've got technical problem with a new C# program I'm developing.
In this project I need to communicate with another none windows based system on a TCP/IP network.
Al the software written on the other system is done in C and any other future development will be done in C/C++ aswell.
The protocols are all done in C by another engineer and definitions of the protocols are all done using C typedef struct's defining all the variables and using memcpy to extract/put the data packets which works fantastic for C.
All my protocols are supplied as C header files with all the typedef and struct's in them and any changes made to the protocol in the future will be done in the same way.
My question is, if there is any way to use them in C#?
I've tried to compile them as a class into a DLL library but not working cause C# can only use managed C dll's. If I try and compile as managed C class, it just becomes a mess due to the fact that there are many arrays in the protocol and because the C code has to conform to a bunch of mill specs, many of the variables have been typedef'd. Now I could go and redo all the structures in C# but that's going to take a lot of time and I'm going to have to redo it every time a change is made or something added to protocol. Not even to mention the danger of errors slipping in every time I do it.
How it worked with my C projects is that the other engineer would just supply me with the updated header files.
So is there any way to use those header files directly in C# or a automated conversion I can do every time the protocol is updated?
Well I basically need to use this header file to extract the data from the data stream coming over the TCP/IP connection (without begin able to use memcpy)
Reason for using C# is because I use a lot of graphics in WPF and Visual C++ doesn't support WPF
Any help or suggestions would be much appreciated?
I've once had to use C headers in C# to get definitions of marshalled structures sent via TCP/IP. The approach we used was parsing the header files by T4 Text Template. It's a somewhat lenghty task though, you have to write C parser good enough for your headers and use it to produce .cs file, so there is a lot of string mess. For us, it was a good enough solution, so it may help you as well.
Have a look at T4 here: http://msdn.microsoft.com/en-us/library/bb126445.aspx
Not really an answer, more like one possible good solution:
Create a defintion file containing the information now in C header file. Then use that to generate both the .h header and suitable C# source code.
If the data is fairly simple, then also simple key-value file format, or even a csv file, could be used. But if it's more complex, then it's best to use XML, which is simpler to parse programmatically.
If there is resistance to having a language-independent definition file, then you could try to get the .c header file to follow some string formatting rules, so you can parse it simply and generate C# code from it (just make sure that the one writing the .h understands, that it is no longer C, it's actually your own C-like definition language, and any extra C stuff has to go to another file).
You don't and can't use a header file in C# you you need to compile it into dll and from c#
in the c File you need to define #define DLLAPI __declspec(dllexport) and define the methods like like the following DLLAPI *return-value-data-type function-name*
and from c# you need to call it like below
[DllImport(#"*dll-path*")]
public static extern *return-value-datatype function-name*
and if it is needed you do marshalling for datatypes like the following
[DllImport(#"*dll-path*")]
public static extern void InitParam([MarshalAs(UnmanagedType.LPWStr)] string inputFile,
[MarshalAs(UnmanagedType.LPWStr)] string outputFile,
[MarshalAs(UnmanagedType.LPWStr)] string templateFile,
[MarshalAs(UnmanagedType.LPWStr)] string userName,
[MarshalAs(UnmanagedType.LPWStr)] string manifestFilePath,
[MarshalAs(UnmanagedType.LPWStr)] string usersRightList);
[DllImport(#"*dll-path*")]
public static extern Int32 ProtectDocument(
[MarshalAs(UnmanagedType.LPStr)]string validToDate);
[DllImport(#"*dll-path*")]
public static extern void DebugGeneratedFiles(
[MarshalAs(UnmanagedType.LPWStr)] string singedIssuenceLicenseFilePath,
[MarshalAs(UnmanagedType.LPWStr)] string encryptedContentOutputFilePath);
I'm working on a project where I'm converting C++ code to C# manually. I have working knowledge of C# but I've never used C++ before.
What I need to know is how to deal with the header files, since C# does't have anything like that. Say I have buffer.h and buffer.cpp, would I just convert them both and include them in the same buffer.cs file?
Is the C++ header file in any way related to an Ada spec file?
The distinction between includes ".h files" and source ".cpp files" is only one of convention. The convention is that declaration (functions, classes, etc) are in .h files which are #included in implementation (definition), or .cpp files. For most cases you're fine in collapsing X.h and X.cpp to a single X.cs file.
That said, you still need to take a look at what is going on in each file. A basic understanding of C++ would go a long way here, and something I strongly recommend you acquire before you get too far into your translation.
It might help you to think of a C++ header file as containing two major types of things: the class definition, which defines its member data and "interface" (not to be confused with a C# interface type) and "other stuff". The class definition part contains method prototypes and class member variables.
The good news concerning the prototypes is that you simply don't need them in C#. Clients of your class receive prototype information from the implementation itself via the assembly for the namespace. The data members are contained within your C# class implementation, typically as private members which are exposed through C# properties.
The "other stuff" mentioned above can include #defines, which you typically want to turn into const definitions in C#. Other things such as enumerations have equivalents in C# which you of course move into the .cs file for your class.