payal1711
asked on
string to CString conversion error
Hi,
I have an C++ unmanaged dll that has a method signature like:
void DoConversion(CString videoIn, CString videoOut)
I am building a VC++.NET managed wrapper class for this dll. It has the following method:
public:
[DllImport("anothertestpro c.dll",
EntryPoint="?convertd@Cano thertestpr ocApp@@QAE XQAD0@Z",
CallingConvention=CallingC onvention: :ThisCall) ]
static void convertd(CString, CString );
};
The final C#.Net call should look something like this:
convertd(string, string);
I am very new to the unmanaged and managed wrappers and all this stuff. It gives me error when I try to pass string values to CString type.
Does anyone know how to go about this whole thing?
Thanks.
I have an C++ unmanaged dll that has a method signature like:
void DoConversion(CString videoIn, CString videoOut)
I am building a VC++.NET managed wrapper class for this dll. It has the following method:
public:
[DllImport("anothertestpro
EntryPoint="?convertd@Cano
CallingConvention=CallingC
static void convertd(CString, CString );
};
The final C#.Net call should look something like this:
convertd(string, string);
I am very new to the unmanaged and managed wrappers and all this stuff. It gives me error when I try to pass string values to CString type.
Does anyone know how to go about this whole thing?
Thanks.
Example:
string foo1 = "Hello World";
CString foo2 = foo1.c_str();
string foo1 = "Hello World";
CString foo2 = foo1.c_str();
To pass the value back to string, use the CString::operator LPCTSTR() function
Is unmanaged Dll written in MFC, what version of MFC?
ASKER
I have written the unmanaged Dll using Visual Studio 2005. I don't know what version it uses. None of the above things are working. Let me know if you find any answers. Thanks.
ASKER
Yes it is MFC in a shared dll.
>>None of the above things are working.
Please post the new code, and please state exactly how it's not working?
We can give you further assistence if you give us proper feedback.
Please post the new code, and please state exactly how it's not working?
We can give you further assistence if you give us proper feedback.
ASKER
function in unmanaged dll:
void DoConversion (LPCTSTR, LPCTSTR);
managed wrapper:
[DllImport("anothertestpro
EntryPoint = "?convertd@Canothertestpro
CallingConvention = CallingConvention.ThisCall
private static extern void convertd(string videoIn, string videoOut);
managed call:
convertd(string p2, string p3);
Below is the error I get.
A call to PInvoke function 'ManagedDemo!ManagedDemo.F
I have checked the signature using dumpbin and copied it exactly the same way and also have updated the reference dll in the managed project.
Do I have to specify an entry point in my Dll using "BOOL APIENTRY DllMain". I found this in one of the example projects found on internet.
Thanks.
Why did you change the function signature?
That's not what I recommended.
I recommend you leave the function signature as it was, and change the calling code, to pass the right type.
That's not what I recommended.
I recommend you leave the function signature as it was, and change the calling code, to pass the right type.
//Example calling code
void foo()
{
std::string data1 = "Hello World";
std::string data2 = "Goodby World";
DoConversion(data1.c_str() , data2.c_str());
The above code will work with the original function signature.
void foo()
{
std::string data1 = "Hello World";
std::string data2 = "Goodby World";
DoConversion(data1.c_str()
The above code will work with the original function signature.
ASKER
ok, how do you write the same thing in C#.net. because my final call is from a c# form.
I cannot do using namespace std;
>> ok, how do you write the same thing in C#.net. because my final call is from a c# form.
What do you mean by you're final call?
Do you mean the calling function, or the DoConversion implementation.
If you need to cross over languages, then I recommend you use a simple type like "const char*".
What do you mean by you're final call?
Do you mean the calling function, or the DoConversion implementation.
If you need to cross over languages, then I recommend you use a simple type like "const char*".
ASKER
I mean the call from my c# code.The implementation is in c++. And yes it is using cross over languages. How do I work with const char* then? Can you show me the calls in the functions?
>>Can you show me the calls in the functions?
I'm not that familiar with C#, so I can't post example code callin the DoConversion function.
I'm sure C# has an easy method to convert from String to const char* type.
C++ function should be declared as the following:
void DoConversion (const char*, const char*);
You need to make this change on ALL parts of your code that declares or implements DoConversion.
Do a keyword search for "DoConversion" on your project on ALL types (*.*) of files (an not just *.cpp and *.c).
After making your changes, do a Rebuild-ALL.
I'm not that familiar with C#, so I can't post example code callin the DoConversion function.
I'm sure C# has an easy method to convert from String to const char* type.
C++ function should be declared as the following:
void DoConversion (const char*, const char*);
You need to make this change on ALL parts of your code that declares or implements DoConversion.
Do a keyword search for "DoConversion" on your project on ALL types (*.*) of files (an not just *.cpp and *.c).
After making your changes, do a Rebuild-ALL.
ASKER
ok below is what I am doing now
C++ function:
void DoConversion(const char* videoIn, const char* videoOut)
managed wrapper class call:
[DllImport("anothertestpro
EntryPoint = "?convertd@Canothertestpro
CallingConvention = CallingConvention::ThisCal
static void convertd(const char* videoIn, const char* videoOut);
In my C# project, I add the managed wrapper class dll as a reference. But now it wants sbyte* as arguments. Below is the error I get:
The best overloaded method match for 'testmanaged.ImageWrap.con
This error reminds me that I had tried this before also. I came to know then that sbyte is for integer characters or something of that kind. How do I resolve this?
Thanks.
>>This error reminds me that I had tried this before also. I came to know then that sbyte is for integer characters or something of
>>that kind. How do I resolve this?
I think you need to post this part of the quesion in the c# topic area, or post a link to this question in the C# topic area.
>>that kind. How do I resolve this?
I think you need to post this part of the quesion in the c# topic area, or post a link to this question in the C# topic area.
See the following reference:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpcondefaultmarshalingforstrings.asp
Basically use CharSet.Ansi and let System.Interop take care of things for you:
[DllImport("anothertestpro c.dll",
EntryPoint = "?convertd@Canothertestpro cApp@@QAEX PBD0@Z",
CallingConvention = CallingConvention.ThisCall , CharSet=CharSet.Ansi)]
static extern void convertd(String videoIn, String videoOut);
And then calling it with:
string videoIn = "video in";
string videoOut = "video out";
IntPtr pCppObj = myCppObjConstructor(); // whatever DLLImport you've got defined to return a pointer to an instance of your C++ object
convertd(pCppObj, videoIn, videoOut);
myCppObjDestructor(pCppObj );
If you want to manually marshal stuff yourself then look at System.Runtime.InteropServ ices.Marsh al.StringT oHGlobalAn si:
http://msdn2.microsoft.com/en-us/library/system.runtime.interopservices.marshal.stringtohglobalansi.aspx
I think it would look something like:
[DllImport("anothertestpro c.dll",
EntryPoint = "?convertd@Canothertestpro cApp@@QAEX PBD0@Z",
CallingConvention = CallingConvention.ThisCall )]
unsafe extern static void convertd(char* videoIn, char* videoOut);
And then using it:
string videoIn = "video in";
string videoOut = "video out";
IntPtr pvidIn = System.Runtime.InteropServ ices.Marsh al.StringT oHGlobalAn si(videoIn );
IntPtr pvidOut = System.Runtime.InteropServ ices.Marsh al.StringT oHGlobalAn si(videoOu t);
IntPtr pCppObj = myCppObjConstructor();
convertd(pCppObj, (char*) pvidIn, (char*) pvidOut);
System.Runtime.InteropServ ices.Marsh al.FreeHGl obal(pvidI n);
System.Runtime.InteropServ ices.Marsh al.FreeHGl obal(pvidO ut);
myCppObjDestructor(pCppObj );
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpcondefaultmarshalingforstrings.asp
Basically use CharSet.Ansi and let System.Interop take care of things for you:
[DllImport("anothertestpro
EntryPoint = "?convertd@Canothertestpro
CallingConvention = CallingConvention.ThisCall
static extern void convertd(String videoIn, String videoOut);
And then calling it with:
string videoIn = "video in";
string videoOut = "video out";
IntPtr pCppObj = myCppObjConstructor(); // whatever DLLImport you've got defined to return a pointer to an instance of your C++ object
convertd(pCppObj, videoIn, videoOut);
myCppObjDestructor(pCppObj
If you want to manually marshal stuff yourself then look at System.Runtime.InteropServ
http://msdn2.microsoft.com/en-us/library/system.runtime.interopservices.marshal.stringtohglobalansi.aspx
I think it would look something like:
[DllImport("anothertestpro
EntryPoint = "?convertd@Canothertestpro
CallingConvention = CallingConvention.ThisCall
unsafe extern static void convertd(char* videoIn, char* videoOut);
And then using it:
string videoIn = "video in";
string videoOut = "video out";
IntPtr pvidIn = System.Runtime.InteropServ
IntPtr pvidOut = System.Runtime.InteropServ
IntPtr pCppObj = myCppObjConstructor();
convertd(pCppObj, (char*) pvidIn, (char*) pvidOut);
System.Runtime.InteropServ
System.Runtime.InteropServ
myCppObjDestructor(pCppObj
Why do you use PInvoke in C++? You can do this directly from C#.
If you write C++ wrapper, you can call unmanaged functions directly. Add unmanaged library to libker settings, include it's h-file to the project, and make direct call.
If you write C++ wrapper, you can call unmanaged functions directly. Add unmanaged library to libker settings, include it's h-file to the project, and make direct call.
Yeah... my post was all C# -- calling it directly from C# without any form of C++ wrapper besides a wrap to get an instance of your object. Sorry... didn't make that clear. And to further clarify, I have no idea why you'd want to actually marshal stuff yourself (in this case), but posted it because you seemed to be going down that path.
And, finally, AlexFM would certainly know more than I would about how to do any/all of this.
And, finally, AlexFM would certainly know more than I would about how to do any/all of this.
ASKER
Thanks clockwatcher.
I get the following error in the C# code posted below:
PInvokeStackImbalance was detected. "A call to PInvoke function 'ManagedDemo!ManagedDemo.F
Here is what my C# code looks like now.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string p2 = "C:\\bla105_050a_008_cp_00
string p3 = "C:\\New Folder 2\\newimage_0001.tga";
convertd(p2, p3);
}
[DllImport("anothertestpro
EntryPoint = "?convertd@Canothertestpro
CallingConvention = CallingConvention.ThisCall
CharSet = CharSet.Ansi)]
static extern void convertd(string videoIn, string videoOut);
}
What am I doing wrong here? I didn't understand your comment "a wrap to get an instance of your object" what object. I have eliminated the C++ wrapper class totally. There is only unmanged dll and then this C# code.
Thanks.
You're using the ThisCall calling convention which implies that you want to call a method of a C++ unmanaged class or you want to pass a variable number of arguments. If your not calling a class method (or a function that takes a variable number of arguments) then you shouldn't be using ThisCall. If you are, then you need to pass the pointer to your unmanaged class as the first parameter (in the case that you're calling a method of a class). In order to get a pointer to your C# unmanaged class, you'd have to have some sort of class factory standard cdecl type DLLImport that you called that returned a pointer to it. You'd also want to have a destructor wrapper.
If you're just calling a standard function, you probably want to change your call type to Cdecl.
If you're just calling a standard function, you probably want to change your call type to Cdecl.
Sorry... meant to say:
In order to get a pointer to your C++ unmanaged class
not
In order to get a pointer to your C# unmanaged class
In order to get a pointer to your C++ unmanaged class
not
In order to get a pointer to your C# unmanaged class
ASKER
I am calling a class method described below in my unmanaged class
BEGIN_MESSAGE_MAP(Canother
END_MESSAGE_MAP()
// CanothertestprocApp construction
CanothertestprocApp::Canot
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
// The one and only CanothertestprocApp object
CanothertestprocApp theApp;
// CanothertestprocApp initialization
BOOL CanothertestprocApp::InitI
{
CWinApp::InitInstance();
return TRUE;
}
void CanothertestprocApp::conve
{
DoConversion(videoIn, videoOut);
}
-----------and the signature is as below in the header file:
class CanothertestprocApp : public CWinApp
{
public:
CanothertestprocApp();
// Overrides
public:
virtual BOOL InitInstance();
CPPWIN32DLL_API void convertd(const char*, const char*);
DECLARE_MESSAGE_MAP()
};
-------------------
and I gave you my C# code in the previous posting.
So I am calling a class method from an unmanaged class but it does not have variable number of arguments. It always has two fixed arguments. So should I be using ThisCall at all? How do I pass pointer to my unmanaged class? Can you please show me how to in the code that I posted. That will be really helpful.
Thanks.
Ignore the variable number of parameters stuff. ThisCall is strictly for use with member functions. That's what I thought and what made sense. Tired and misread the documentation.
ASKER
I forgot to post the following macros in the unmanaged header file
#ifndef __AFXWIN_H__
#error "include 'stdafx.h' before including this file for PCH"
#endif
#ifdef CPPWIN32DLL_EXPORTS
#define CPPWIN32DLL_API __declspec(dllexport)
#else
#define CPPWIN32DLL_API __declspec(dllimport)
#endif
Thanks.
So it's a MFC DLL? I'll have to take a look. Or someone else will have to jump in.
I'm definitely not a MFC programmer. I would expect that you'd want to expose your DoConversion call directly instead of wrapped in a method call of your MFC CWinApp subclass. Something like:
__declspec(dllexport) void DoConversion(char*, char*);
extern "C" __declspec(dllexport) void DoConversion(char* vidIn, char* vidOut)
{
AFX_MANAGE_STATE(AfxGetSta ticModuleS tate( ));
// .. do whateve DoConversion does here
}
And get rid of all that junk within your CWinApp subclass. My guess is that CWinApp just encapsulates the standard DllMain call of a standard DLL. But again I'm not a MFC programmer.
I don't have time right now to try to put together a test, but I expect that's how you expose functions from MFC dlls-- not as methods of your CWinApp object itself.
I'm definitely not a MFC programmer. I would expect that you'd want to expose your DoConversion call directly instead of wrapped in a method call of your MFC CWinApp subclass. Something like:
__declspec(dllexport) void DoConversion(char*, char*);
extern "C" __declspec(dllexport) void DoConversion(char* vidIn, char* vidOut)
{
AFX_MANAGE_STATE(AfxGetSta
// .. do whateve DoConversion does here
}
And get rid of all that junk within your CWinApp subclass. My guess is that CWinApp just encapsulates the standard DllMain call of a standard DLL. But again I'm not a MFC programmer.
I don't have time right now to try to put together a test, but I expect that's how you expose functions from MFC dlls-- not as methods of your CWinApp object itself.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
It works!!!!
Thanks so much clockwatcher. All the points go to you.
Thanks Axter for your help!!
This was my first MFC/unmanaged C++ project. I learned a lot from it. Thanks everybody for your time.
-Payal
To pass a string value to CString use the string::c_str() method.
David Maisonave (Axter)
Cheers!