c++-clifreezemixed-mode

StringToCoTaskMemUni or StringToCoTaskMemAnsi methods can cause hang?


I have the below code in c++/CLI and observing hang while converting the .net string to char * using StringToCoTaskMemAnsi

const char* CDICashInStringStore::CDIGetStringVal( void )
{
    unsigned int identifier = (unsigned int)_id;
    debug(" cashincdistores--routing call to .Net for CDI String %d", identifier);
    NCR::APTRA::INDCDataAccess::IStringValue^ stringValueProvider = (NCR::APTRA::INDCDataAccess::IStringValue^)GetStringProvider()->GetProvider();
    String^ strValue = stringValueProvider->GetStringValue(identifier);
    debug(" cashincdistores-- going to call StringToCoTaskMemAnsi);
    IntPtr iPtr = Marshal::StringToCoTaskMemAnsi(strValue);
    debug(" cashincdistores-- StringToCoTaskMemAnsi called);
    // use a local (retVal is not needed)
    const char * ansiStr = strdup((const char *) iPtr.ToPointer());
    Marshal::FreeCoTaskMem(iPtr);


    debug(" cashincdistores--got results %d %s",identifier,ansiStr);
    // The returned memory will be free() 'ed by the user
    return ansiStr;
}

In our logging I can see "cashincdistores-- going to call StringToCoTaskMemAnsi" and suspecting there is a hang after calling the 'StringToCoTaskMemAnsi' method.

Does there is a chance of hang in 'StringToCoTaskMemAnsi' marshalling method. what could cause the hang ?


Solution

  • Why are you using COM in the first place? You don't need any COM in that code.

    Disclaimer: You should probably not be returning a const char * someone else will have to free from your function. That's a very easy way to produce memory leaks or multiple free errors.

    Ignoring the disclaimer above, you have a couple possibilities:

    First way:

    #include <msclr/marshal.h>
    
    msclr::interop::marshal_context context;
    const char* strValueAsCString = context.marshal_as<const char*>(strValue);
    
    // Probably bad
    const char* ansiStr = strdup(strValueAsCString);
    

    The strValueAsCString pointer will remain valid as long as context is in scope.


    Another way:

    #include <string>
    #include <msclr/marshal_cppstd.h>
    
    std::string strValueAsStdString = msclr::interop::marshal_as<std::string>(strValue);
    
    // Probably bad
    const char* ansiStr = strdup(strValueAsStdString.c_str());
    

    Here, the std::string manages the lifetime of the string.


    See Overview of Marshaling for reference.