_declspec(dllexport) void Send(string strEmailAddress, string strHostAddress, string strUserName, string strPswrd, string strLocalFile, string strServerLocation, string strErrorMessage )
{
nsFTP::CFTPClient ft ;
wstring wstrHostName ( strHostAddress.begin(),strHostAddress.end() );
string strApplicationUserName = "acpmat";
string strApplicationPswrd = "A1c2p.M3a4t";
wstring wstrUserName ( strApplicationUserName.begin(),strApplicationUserName.end() );
wstring wstrPwrd ( strApplicationPswrd.begin(),strApplicationPswrd.end() );
wstring wstrLocalFile( strLocalFile.begin(),strLocalFile.end() );
wstring wstrServerLoc( strServerLocation.begin(),strServerLocation.end() );
nsFTP::CLogonInfo logonInfo(wstrHostName, 21, wstrUserName, wstrPwrd);
// connect to server
ft.Login(logonInfo);
ft.UploadFile(wstrLocalFile, wstrServerLoc);
CArray<CString, LPCTSTR> xToEmails;
wstring strMailTo( strEmailAddress.begin(), strEmailAddress.end() );
xToEmails.Add(strMailTo.c_str());
const CString xCCEmail;
const CString xReplyTo;
const CString xSubject(strErrorMessage.c_str());
strUserName.append( " " );
strUserName.append( strLocalFile.c_str() );
const CString xBodyFilePath( strUserName.c_str() );
const CString& xFrom = _T("Exe_Crash#cat.com");
const CString& xAttachmentFilePath = _T("");
const CString& xServer = PES_EMAIL_SERVER;
int xPort = PES_EMAIL_PORT;
const CString& xCommand = PES_EMAIL_COMMAND;
int lRes = email::Send(xToEmails, xCCEmail, xReplyTo, xSubject, xBodyFilePath);
return true;
}
I call the above function from another application
typedef void (*FNPTR)(string a, string b, string c, string d, string e, string f, string g );
//typedef int (__cdecl *MYPROC)(LPWSTR);
HINSTANCE hinstLib;
//MYPROC ProcAdd;
BOOL fFreeResult, fRunTimeLinkSuccess;
hinstLib = LoadLibrary(TEXT("DllCrashReport.dll"));
if (hinstLib != NULL)
{
// If the handle is valid, try to get the function address.
if (hinstLib != NULL)
{
FNPTR fn = (FNPTR)GetProcAddress(hinstLib, "Send");
// If the function address is valid, call the function.
if (NULL != fn)
{
TCHAR name_1 [ UNLEN + 1 ];
DWORD size_1 = UNLEN + 1;
GetUserName( (TCHAR*)name_1, &size_1 );
strUserName.clear();
strUserName.append( name_1 );
//use converter (.to_bytes: wstr->str, .from_bytes: str->wstr)
std::string converted_str( strUserName.begin() , strUserName.end() );
fRunTimeLinkSuccess = TRUE;
fn( strEmailAddress, strHostAddress, converted_str, strPswrd, strLocalFile, strServerLocation, strMailErrorMessage );
}
// Free the DLL module.
fFreeResult = FreeLibrary(hinstLib);
}
// If unable to call the DLL function
if (!fRunTimeLinkSuccess)
return ;
}
The call stack shows me this: Symbols loaded.
HEAP[MaterialCheck.exe]: Invalid address specified to RtlValidateHeap( 0000000000390000, 0000000002B82D30 ) and the crash occurs when it says that it tries to > mfc110ud.dll!operator delete(void * p) Line 351 C++
Can someone kindly help me please. THanks
!!!! This is an important finding .. The problem got solved and this was a new learning for me.
While passing strings as parameter into a dll function call from another application , please pass the parameters as "const char*" and not as native strings.
Kindly refer:
C++ Passing std::string by reference to function in dll
Related
I'm currently working on a project where I want to be able to manipulate and graph data with relative ease in Excel. However, a lot of the data involved exceeds Excels row limits considerably and it needs a degree of preprocessing before I can work with it.
To solve this I decided to write a backend in C++ to handle the preprocessing so that it's acceptable for Excel. The aim is to be able to pick several files within excel which are then sent to the .dll to be parsed, preprocessed, and have some averaging applied to make it more easily handled in excel. The data is then passed back to Excel to be graphed, etc.
I've already worked out how to send arrays of data from the .dll to Excel reliably. However, sending data from Excel to the .dll, usually an array of BSTR which hold file paths, has proven more difficult.
After reading through a few questions:
How to create an array of strings in VBA/Excel and send it to a C++ DLL so that it can be iterated through in the DLL
VBA/Excel, and C++ DLL, specifically problems with strings
Calling C++ function from Excel and VBA using DLL created in C++
I thought the following code should work:
// lib.cpp
/*
* clear_log() & write_log(...) both write to a specified log file
*/
inline std::string WINAPI
bstr_string_convert( const BSTR bstr ) {
const auto bstrlen = SysStringLen(bstr);
const auto buffer = new char[bstrlen + 1];
size_t n_char_converted{ 0 };
if ( bstrlen > 0 ) {
const auto err =
wcstombs_s( &n_char_converted,
buffer, bstrlen + 1,
bstr, bstrlen );
}
else {
buffer[0] = '\0';
}
return std::string{ buffer };
}
const std::string log_location{
"C:\\\\path\\to\\log\\location\\"
};
void WINAPI
clear_log( const std::string_view filename ) {
std::fstream log_file( log_location + filename,
std::ios_base::out | std::ios_base::trunc );
log_file.close();
}
void WINAPI
write_log( const std::string_view filename, const std::string_view str ) {
std::fstream log_file( log_location + filename,
std::ios_base::out | std::ios_base::app );
log_file << str << "\n";
log_file.close();
}
// This works
__declspec(dllexport) LPSAFEARRAY WINAPI
get_double_array( _In_ const LPSAFEARRAY* ppsa ) {
CComSafeArray<double> csa(*ppsa);
clear_log("double_log.txt");
write_log( "double_log.txt",
std::format("size: {}", csa.GetCount()) );
for ( LONG i{ csa.GetLowerBound() }; i < csa.GetUpperBound(); ++i ) {
write_log( "double_log.txt",
std::format("{}: {}", i, csa.GetAt(i)) );
}
return csa.Detach();
}
// This doesn't
__declspec(dllexport) LPSAFEARRAY WINAPI
get_str_array( _In_ const LPSAFEARRAY* ppsa ) {
CComSafeArray<BSTR> csa(*ppsa);
clear_log("string_log.txt");
write_log( "string_log.txt",
std::format("size: {}", csa.GetCount()));
for (LONG i{ csa.GetLowerBound() }; i < csa.GetUpperBound(); ++i ) {
write_log( "string_log.txt",
std::format( "{}: {}",
i,
bstr_string_convert(csa.GetAt(i))
) );
}
return csa.Detach();
}
Declare PtrSafe Function send_string_array _
Lib "path\to\dll" _
Alias "_get_str_array#4" _
(ByRef first_element() As String) As String()
Declare PtrSafe Function send_double_array _
Lib "path\to\dll" _
Alias "_get_double_array#4" _
(ByRef ptr() As Double) As Double()
(Not sure what's making the syntax highlighting weird here)
Sub test()
Dim doubles(3) As Double
doubles(0) = 3.141592
doubles(1) = 1235.12617
doubles(2) = -1266.2346
Dim d_result() As Double
d_result = send_double_array(doubles)
Dim n As Long
For n = 0 To 2
Debug.Print d_result(n)
Next n
Dim strings(3) As String
strings(0) = "This"
strings(1) = "is a "
strings(2) = "test."
Dim result() As String
result = send_string_array(strings)
For n = 0 To 2
Debug.Print result(n)
Next n
End Sub
Immediate Window:
3.141592
1235.12617
-1266.2346
??
??
??
double_log.txt:
size: 4
0: 3.141592
1: 1235.12617
2: -1266.2346
string_log.txt:
size: 4
0:
1:
2:
So my question is what am I missing that causes get_double_array(...) to work, but get_str_array(...) doesn't?
As an aside, why does CComSafeArray::GetCount() return 4 for an array declared with 3 elements? Seems like something weird is going on there.
I'm relatively new to C++ and I'm trying out Windows Notification using Win32 API.
This is the method I have:
BOOL Notification::ShowNotification(std::string title, std::string info) {
NOTIFYICONDATA nid = {
sizeof(nid)
};
nid.uFlags = NIF_INFO | NIF_GUID;
nid.guidItem = __uuidof(AppIcon);
nid.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON;
std::wstring wtitle = std::wstring(title.begin(), title.end());
const wchar_t * wchar_title = (STRSAFE_LPCWSTR) wtitle.c_str();
StringCchCopy(nid.szInfoTitle, sizeof(nid.szInfoTitle), wchar_title);
std::wstring wInfo = std::wstring(info.begin(), info.end());
const wchar_t * wchar_Info = (STRSAFE_LPCWSTR) wInfo.c_str();
StringCchCopy(nid.szInfo, sizeof(nid.szInfo), wchar_Info);
LoadIconMetric(g_hInst, MAKEINTRESOURCE(IDI_NOTIFICATIONICON), LIM_LARGE, & nid.hBalloonIcon);
return Shell_NotifyIcon(NIM_MODIFY, & nid);
}
As you can see, there is duplicate code for converting the string type to STRSAFE_LPCWSTR for the variables title and info. I was thinking of a small utility method that would replace the duplicate code.
Something like this:
void Notification::ConvertToLPCWSTR(std::string input, STRSAFE_LPCWSTR &result)
{
std::wstring wide_string = std::wstring(input.begin(), input.end());
result = (STRSAFE_LPCWSTR)wide_string.c_str();
}
And then use it from the ShowNotification method like this, where wchar_title is passed by reference:
STRSAFE_LPCWSTR wchar_title;
ConvertToLPCWSTR(title, wchar_title);
But it is failing because wide_string variable is stack allocated and it goes out of scope when ConvertToLPCWSTR execution is finished, because of which wchar_title is pointing at deallocated memory.
Anyone know of a good way to fix this ?
You need to move all three lines of the repeated code into a small utility function.
static void Notification::ConvertToLPCWSTR(const std::string& input, LPWSTR result, size_t result_max_size) {
std::wstring wInfo = std::wstring(input.begin(), input.end());
const wchar_t * wchar_Info = (STRSAFE_LPCWSTR) wInfo.c_str();
StringCchCopy(result, result_max_size, wchar_Info);
}
And call like
ConvertToLPCWSTR(info, nid.szInfo, sizeof(nid.szInfo));
I came up with the same issue,in which I got a LPTSTR portname param as input from a function.I have to convert this into wstring,so that I can fetch the Port paramaters.
below is the code snippet in which am trying to copy lptstr to wstring.
void C_PORT_MONITOR::SetPrinterComPortParam(LPTSTR PortName)
{
#ifdef _UNICODE
std::wstring l_ComPortName;
#else
std::string l_ComPortName;
#endif
DWORD dwSize,le = 0;
dwSize = sizeof(COMMCONFIG);
LPCOMMCONFIG lpCC = (LPCOMMCONFIG) new BYTE[dwSize];
l_ComPortName = PortName;//mPortName;
if(l_ComPortName.length() <= 0 )
return;
bool SetFlag = false;
//Get COMM port params called to get size of config. block
int length = l_ComPortName.length();
int iPos = l_ComPortName.find_first_of(':');
int iChc = length- iPos; //remove the charactrers after :
l_ComPortName = l_ComPortName.substr(0, (length- iChc)); //remove the characters from colon //COM1
//Get COMM port params with defined size
BOOL ret = GetDefaultCommConfig(l_ComPortName.c_str(), lpCC, &dwSize);
_RPT1(_CRT_WARN, "C_PORT_MONITOR::SetPrinterComPortParam length=%x,iPos=%x,iChc=%x,l_ComPortName=%s",length, iPos, iChc, l_ComPortName);
if(!ret)
{
le = GetLastError();
_RPT1(_CRT_WARN ,"C_PORT_MONITOR::SetPrinterComPortParam LastError=%x",le);
}
I need to assign this portname to l_comportname. and I need to create a substring from this l_comportname as COM1 and I have to use this substring in getdafaultcommconfig()
Your error is the second parameter not the first. Your debugging statement is bugged because it doesn't account for wide strings %s is for narrow strings only, you should use %S for a wide string.
Here's the real error
dwSize = sizeof(COMMCONFIG);
LPCOMMCONFIG lpCC = (LPCOMMCONFIG) new BYTE[dwSize];
lpCC->dwSize = sizeof(COMMCONFIG); // this line is needed
You might need this as well (the documentation isn't very clear)
lpCC->wVersion = 1;
It's very common in Windows programming that you have to initialize a struct with the size of the struct.
Ref: https://technet.microsoft.com/en-us/aa363188(v=vs.90)
My code,
LPSTR Internal::Gz_GetSystemKey( BOOL SHOW_ERROR, BOOL SHOW_KEY ) {
HW_PROFILE_INFO HwProfInfo;
if (!GetCurrentHwProfile(&HwProfInfo))
{
if(SHOW_ERROR)
Message::Error( "An Internal Error Has Occurred", "Gizmo Message", TRUE );
return NULL;
}
std::string __clean( (char*)HwProfInfo.szHwProfileGuid );
__clean.append( std::string( (char*)HwProfInfo.szHwProfileName ) );
LPSTR neet_key = Crypt::CRC32( Crypt::MD5( (char*)__clean.c_str() ) );
if (SHOW_KEY)
Message::Info( neet_key ); // shows expected result
return neet_key; // returns strange ascii result
};
Gz BOOL Gz_CreateContext( BOOL SHOW_ERROR, BOOL SHOW_KEY ) {
HKEY CHECK; // key result container
BOOL RESULT;
std::wstring neet_key_uni; // must use unicode string in RegSetValueExW
if ( RegOpenKey(HKEY_CURRENT_USER, TEXT("Software\\NEET\\Gizmo\\"), &CHECK) != ERROR_SUCCESS )
goto CREATE_REG_CONTEXT;
else
goto STORE_NEET_KEY;
CREATE_REG_CONTEXT:
if ( RegCreateKeyA( HKEY_CURRENT_USER, "Software\\NEET\\Gizmo\\", &CHECK ) != ERROR_SUCCESS ) {
if( SHOW_ERROR )
Message::Error( "Context Could Not Be Created" );
RESULT = FALSE;
goto END_MACRO;
}
STORE_NEET_KEY:
LPSTR neet_key = Internal::Gz_GetSystemKey( SHOW_ERROR, SHOW_KEY ); // GetSystemKey generates good key, returns weird ascii
Message::Notify( neet_key );
neet_key_uni = std::wstring(neet_key, neet_key+strlen(neet_key));
if ( RegSetValueEx( CHECK, TEXT("Key"), 0, REG_SZ, (const BYTE*)neet_key_uni.c_str(), ( neet_key_uni.size() + 1 ) * sizeof( wchar_t ) ) != ERROR_SUCCESS ) {
if( SHOW_ERROR )
Message::Error( "Context Could Not Be Reached" );
RESULT = FALSE;
goto END_MACRO;
}
RESULT = TRUE;
END_MACRO:
RegCloseKey(CHECK); // safely close registry key
return RESULT;
};
I'm creating a simple PC identification lib for practice, not for commercial use.
Message::Info( neet_key );
Shows
but the actual return value is
Any ideas why? The 'Message' namespace/functions are just message boxes. As for the 'Crypt' namespace/functions, they aren't the issue at hand.
From the comments: Who owns the memory for the 'neet_key'? My guess would be that the 'Message::Info' shows a valid value because whatever memory structure its from is still in memory but when you return its no longer in memory. Therefore the returned value prints rubbish.
This is a common issue for the C++ language. I would highly recommend that you avoid using raw pointers where possible (especially when returning from functions/methods). For strings you could obviously use 'std::string'.
Hello all thank you for taking the time to look at my question.
I am having an error during runtime of this program I am making and I have narrowed it down to one l
std::string str(id.Description, (sizeof(id.Description)/sizeof(id.Description[0])));
Here is the complete function
bool isItNvidia()
{
IDirect3D9* pD3D9 = NULL;
pD3D9 = Direct3DCreate9( D3D_SDK_VERSION );
if(pD3D9)
{
UINT dwAdapterCount = pD3D9->GetAdapterCount();
for( UINT iAdapter = 0; iAdapter < dwAdapterCount; iAdapter++ )
{
D3DADAPTER_IDENTIFIER9 id;
ZeroMemory( &id, sizeof( D3DADAPTER_IDENTIFIER9 ) );
pD3D9->GetAdapterIdentifier( iAdapter, 0, &id );
//std::cout<< id.Description<<std::endl;
/*
wchar_t wtext[MAX_DEVICE_IDENTIFIER_STRING];
std::mbstowcs(wtext, id.Description, strlen(id.Description)+1);
LPWSTR ptr = wtext;
MessageBox(NULL, ptr, L"nigg", MB_OK);
*/
std::string str(id.Description, (sizeof(id.Description)/sizeof(id.Description[0])));
std::string comp="NVIDIA";
if(str.find(comp) != std::string::npos)
{
return true;
Beep(300, 500);
}
}
}
return false;
pD3D9->Release();
delete pD3D9;
}
You'll also need the d3d9.h and d3d9.lib files.
I have no clue why it is doing this
the id.Description is a character array
If someone could help I would greatly appreciate it.
Thanks
Just initialize the string with std::string str(id.Description);
Explanation:
This constructor is probably called and this is not what you want:
basic_string( const basic_string& other,
size_type pos,
size_type count = std::basic_string::npos,
const Allocator& alloc = Allocator() );
The pos argument will result in a garbage address.
You get the error because C Runtime (CRT) wasn't initialized properly. Please see here for possible causes of the problem:
http://msdn.microsoft.com/en-us/library/9ecfyw6c.aspx