I am calling a c++ method from .NET like below,
[DllImport("CPCModule.dll", EntryPoint = "FuncName", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern long FuncName([MarshalAs(UnmanagedType.LPStr)]string inFile, [MarshalAs(UnmanagedType.LPStr)]ref string OutFile);
Public Void test()
{
string altFileName = string.Empty;
string FileName = "{MyInputFullPath}"
long ret;
ret = ClassName.FuncName(FileName, ref altFileName);
........
}
The C++ code is as follows,
static ICPC* pCPC;
extern "C" long _stdcall FuncName(char* inFile, char** outFile)
{
......
hr = pCPC->UPPat2File(inFile, outFile);
return hr;
}
In the .NET code, i am passing a input file. This input file will be decoded in the method UPPat2File and put it in a output file. After the above code, the outFile is filled with proper value and the hr also return S_OK.
But after the end of the method, it was supposed to come back to .NET code (and the altFileName should be filled with the outFile). But instead it is crashing with the below exception, "An unhandled exception of type 'System.AccessViolationException' occurred in .NETdllname.dll. Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt." It is not coming back to .NET code.
Related
Here is the function that writes data to the JSON file initially:
template<typename Writer>
inline void ToJSON(Writer& writer) {
writer.StartObject();
writer.String("msg_type");
writer.Int(type);
writer.String("msg");
writer.String(msg.c_str());
writer.EndObject();
}
This message then gets parsed by this function:
static SvrMessage FromJSON(const char* json)
{
rapidjson::Document d;
qDebug() << json;
if (d.Parse<0>(json).HasParseError()) throw std::exception("Unable to parse message");
auto type = static_cast<SvrMessage::msg_type>(d["msg_type"].GetInt());
auto msg = d["msg"].GetString();
return SvrMessage(type, msg);
};
When I run the program in release mode, everything works fine and the message is parsed properly. However, in debug mode, the following line will throw an error because it is unable to parse the message.
if (d.Parse<0>(json).HasParseError()) throw std::exception("Unable to parse message");
I've looked through all of my project settings as well, and cannot find any discrepancies that would cause the parsing to fail.
Found the issue, when the JSON was being formed initially, the rapid json stringbuffer GetString() method was returning a char*, which was being freed from the stack in debug mode before it could be used. Changing the return type to a string solved the issue. Here's my fixed method that writes the JSON object:
StringBuffer sb;
Writer<StringBuffer> writer(sb);
writer.StartObject();
writer.String("msg_type");
writer.Int(msg.Type());
writer.String("msg");
writer.String(msg.Msg().c_str());
writer.EndObject();
const char* ret_val = sb.GetString();
std::string return_string(ret_val);
return return_string;
I've created an After Effects script that extracts data from JSON files downloaded from an HTTPS URL. The problem is with the C++ DLL I've coded to download it and pass it back to the script. Even though it has been working fine, there was one instance of memory leak - After Effects issued a popup saying, "STRING MEMORY LEAK".
I'm new to C++ but I've managed to compose a DLL that downloads the files based on the examples provided with the After Effects installation (samplelib and basicexternalobject) as well as by Microsoft's C++ documentation. The Adobe JavaScript Tools Guide says that the method "ESFreeMem()" must be "called to free memory allocated for a null-terminated string passed to or from library functions". The problem is I don't know how or where to use it. I'm using After Effects CC 15.0.0 (build 180) on Windows 7.
This is the C++ function that gets some parameters from the javascript caller and returns a string with the JSON contents. If it fails it returns a bool (FALSE) so that the script can do what is necessary in this case.
extern "C" TvgAfx_Com_API long DownloadJson(TaggedData* argv, long argc, TaggedData * result)
{
//... first I check the arguments passed
// The returned value type
result->type = kTypeString;
//Converts from string into LPCWSTR ---------------------------------------------------
std::wstring stemp = s2ws(argv[0].data.string);
LPCWSTR jsonLink = stemp.c_str();
std::wstring stemp02 = s2ws(argv[1].data.string);
LPCWSTR jsonHeader = stemp02.c_str();
//--------------------------------------------------------------------------------------
//Class that does the HTTP request
WinHttpClient client(jsonLink, jsonHeader);
//Synchronous request
if (client.SendHttpsRequest())
{
string httpResponse = client.GetHttpResponse();
if (httpResponse.length() > 0)
{
//Sends response string back to javascript
result->data.string = getNewBuffer(httpResponse);
}
else
{
//Sends FALSE back to javascript
result->type = kTypeBool;
result->data.intval = 0;
}
}
else
{
//Sends FALSE back to javascript
result->type = kTypeBool;
result->data.intval = 0;
}
return kESErrOK;
}
The class WinHttpClient that does the actual request frees the memory allocated to the buffer that holds the response. Here's a piece of code:
// Read the data.
ZeroMemory(pszOutBuffer, dwSize + 1);
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded))
{
//Log error
}
else
{
resource.append(pszOutBuffer).c_str();
}
// Free the memory allocated to the buffer.
delete[] pszOutBuffer;
This is the function that the Adobe example uses to hold the string that will be returned to javascript:
//brief Utility function to handle strings and memory clean up
static char* getNewBuffer(string& s)
{
// Dynamically allocate memory buffer to hold the string
// to pass back to JavaScript
char* buff = new char[1 + s.length()];
memset(buff, 0, s.length() + 1);
strcpy(buff, s.c_str());
return buff;
}
Now, the manual says this method must be implemented:
/**
* \brief Free any string memory which has been returned as function result.
* JavaScipt calls this function to release the memory associated with the string.
* Used for the direct interface.
*
* \param *p Pointer to the string
*/
extern "C" SAMPLIB void ESFreeMem (void* p)
{
if (p)
free (p);
}
What I understand from this is that the memory associated with the json string returned must be released. But didn't the request class already do it? I just don't know where to call this method and what to pass on to it. I would appreciate any help. Thanks a lot!
When you create a DLL ExternalObject for After Effects, it's really just an interface that you call via some ExtendScript script. You have to load the ExternalObject in the AE Script and once loaded, the methods / functions you create in the C++ class can be called from the script.
You have to know how to load the DLL in an ExtendScript script file. Then, you can call the methods of the DLL.
I am attempting to pass a string from python to a c++ library. However, I have been crashing with variations of segfaults std::bad_alloc, and invalid type messages while I have been attempting to do so. Here is the code that I am attempting to use in c++:
#define DLLEXPORT extern "C"
DLLEXPORT std::string returnAString()
{
std::string ret = "Returning string from lib";
return ret;
}
DLLEXPORT char* returnACharArray()
{
return "Returning char* from lib";
}
DLLEXPORT void passInAString(std::string incomingString)
{
printf("Recieved message in passInAString\n");
printf("Recieved incoming message: %s", incomingString);
}
DLLEXPORT void passInACharArray(char* incomingString)
{
printf("Recieved message in passInACharArray\n");
printf("Recieved incoming message: %s", incomingString);
}
Realistically, with what I am doing I can work with either the char* or the std::string once it gets in my c++ code, and I don't really have a preference either way. Here is what I am doing in python:
from ctypes import *
import os
libPath = os.path.join(os.getcwd(), "mylib.so")
lib = cdll.LoadLibrary(libPath)
string = "hello from python"
lib.passInAString(string)
#lib.passInACharArray(string)
#ret = lib.returnAString()
#print("recieved string: " + string)
#ret = lib.returnACharArray()
#print("recieved char*: " + string)
here, I will uncomment whichever line I am attempting to test. When passing in a string, I will get my first printf statement, I will get std::bad_alloc. When I pass in a char*, I get a segfault. When I attempt to receive a message, I get back a number (I am assuming that this is the pointer), but I am unable to decode this message into an actual string message.
I have attempted to use c_char_p to convert my python string into a char* to pass to my library, but when I do that I get "invalid type". Trying to convert the returned message by doing c_char_p(lib.returnACharArray) and then print(str(string.value)) then gives me the hex value of 4 bytes... which is not what I am returning.
What am I missing to make this functionality work?
Your DLL has the wrong argument types.
Since you're passing a string from Python the function should take a char*. You can convert this to a std::string within the function if you want to.
There's a table in the Python docs showing the corresponding types in both C and Python here: https://docs.python.org/3.6/library/ctypes.html#fundamental-data-types
Edit: Just realized the string types differ for Python 3 meaning the function needs to be declared differently.
e.g.
// Python2, or Python3 passing bytes
DLLEXPORT void passInAString(char* incomingString)
{
printf("Received message in passInAString\n");
printf("Received incoming message: %s", incomingString);
std::string myStr = incomingString;
// and do stuff with myStr if needed
printf("Incoming message as std::string is %s", myStr.c_str());
}
// Python3 passing strings
DLLEXPORT void passStringPy3(wchar_t* wideString)
{
printf("Message >>%ls<<\n", wideString);
}
I make an OCX in C++ Builder Borland. My OCX has these function as I describe it:
Login
Write
Read
DebugOutput
GetVal
I am using this OCX in my c# application. In c# side I have a button and list box. The button calls login method from OCX and the list box shows this method's output.
In OCX side, the login method creates a command for server (with socket programming) to get authentication. Then call Write function to writes on socket. Then gets response from socket and calls Read function to reads the socket response.
The Read method reading the result and send it to DebugOutput to debug the output stream and call GetVal to find Last main server response. Then they pass their parameters to each other. after all the C# side show the result (SUCCESS | FAIL ) for login methods.
I used BSTR. (I read the topics about BSTR in stackoverflow and on MSDN but I think I did not get it well in my solution). These are my code in OCX side:
BSTR STDMETHODCALLTYPE TVImpl::Login(BSTR PassWord)
{
wchar_t wcs1[500];
Var *var=new Var();
//here make the command
...................
//get the server response to show to user
BSTR read=::SysAllocString(Write(wcs1));
if(read!=NULL) ::SysFreeString(read);
return read;
}
BSTR STDMETHODCALLTYPE TVImpl::Read()
{
BSTR str ;
try
{
IdTCPClient1->ReadTimeout=100;
str =::SysAllocString( IdTCPClient1->IOHandler->ReadLn().c_str());
}
catch(Exception &e)
{
str= e.Message.c_str();
}
str=(DebugOutput(str));
return str;
}
BSTR STDMETHODCALLTYPE TVImpl::Write(BSTR str)
{
IdTCPClient1->IOHandler->WriteLn(str) ;
BSTR str2=::SysAllocString(L"TST");
str2=Read();
return str2;
}
BSTR STDMETHODCALLTYPE TVImpl::GetVal(BSTR st,BSTR ValTyp)
{
BSTR res;
AnsiString stAnsi;
//Do some thing with st and save it to stAnsi
.................
res=(BSTR)WideString(stAnsi);
return ::SysAllocString(res);
}
BSTR STDMETHODCALLTYPE TVImpl::DebugOutput(BSTR st)
{
Var *val=new Var();
BSTR res;
res=GetVal(st,val->CMD_CMD);
if(res==val->CMD_AUTHENTICATE)
res=GetVal(st,val->XPassword);
return res;
}
In C3 code it was hanging. I know my problem is to use sysAllocString. but I when I used ::sysFreestring for each one in each method again my C# code hanging.
This is my C# code :
private void button4_Click(object sender, EventArgs e)
{
VinSockCmplt.Vin vin = new Vin();
listBox1.Items.Add(vin.Login("1234"));
}
You should not return BSTR (or any "complex" type that various compilers compile in various ways). The recommended return type for COM methods is HRESULT (a 32-bit integer). Also, you must not release a BSTR you just allocated and return it to the caller.
Here is how you could layout your methods:
HRESULT STDMETHODCALLTYPE TVImpl::Login(BSTR PassWord, /*out*/ BSTR *pRead)
{
...
*pRead = ::SysAllocString(L"blabla"); // allocate a BSTR
...
// don't SysFreeString here, the caller should do it
...
return S_OK;
}
If you were defining your interface in a .idl file, it would be something like:
interface IMyInterface : IUnknown
{
...
HRESULT Login([in] BSTR PassWord, [out, retval] BSTR *pRead);
...
}
retval is used to indicate assignment semantics are possible for languages that support it, like what you were trying to achieve initially with code like this var read = obj.Login("mypass")
There are lots of mistakes in your code:
if(read!=NULL) ::SysFreeString(read); return read; frees a string and then returns it
str= e.Message.c_str(); ... return str; returns a pointer to something that isn't even a BSTR
BSTR str2=::SysAllocString(L"TST"); str2=Read(); allocates a string and then leaks that string immediately
res=(BSTR)WideString(stAnsi); creates a dangling pointer
All of these are undefined behaviour (except the leak) and might cause a crash.
Also, I'm not sure if it is valid to have your functions return BSTR; the normal convention in COM programming is that functions return HRESULT and any "return values" go back via [out] parameters. This is compatible with all languages that have COM bindings; whereas actually returning BSTR limits your code compatibility. (I could be wrong - would welcome corrections here). You can see this technique used in the other question you linked.
To get help with a question like "Why is my code crashing?", see How to Ask and How to create a Minimal, Complete, and Verifiable example.
Let me start off by saying that VB is not my strong suit.
I am developing a C++ dll to be used in a VB6 application's dll.
I have successfully instantiated the (C++) classes in VB. I am trying to access data members of the class using this syntax: "vbCppObj.dataMemberName".
I can confirm that this works for boolean and enum types and it invokes the getter methods defined in my class.
I have to access a string from the (C++) class as well.
The getter function for the string is given below:
class MyCPPClass
{
private:
WCHAR* CPPErrorString = L"This is a string";
public:
HRESULT __stdcall get_CPPErrorString(BSTR* pVal)
{
BSTR str = ::SysAllocString(CPPErrorString);
if(str)
*pVal = str;
return S_OK;
}
};
I am unable to debug the C++ dll right now.
I access this value in the VB6 code as follows:
ErrorString = vbCppObj.CPPErrorString
Logger.log "[Log]:" & ErrorString
"ErrorString" is a String type in VB. When this line executes, the "ErrorString" object shows "<Out of memory>" (when I hover over it). If I step further, to the logging code, it gives me a "Error 14: Out of string space".
Also, I have typed this code in the browser so, it may not be 100% correct.
As it turns out, I had to convert the string into a "_b_str" and then to a "BSTR". That worked for me.
I had tried it earlier but I don't know why it didn't work at that time.
Why you just don't use LPCTSTR?
I'm not an advanced C/C++ programmer, but this should work
class MyCPPClass
{
private:
LPCTSTR CPPErrorString = "This is a string";
public:
HRESULT __stdcall get_CPPErrorString(LPCTSTR * pVal)
{
// copy the value
*pVal = CPPErrorString;
// return
return S_OK;
}
}