Here is what is going on. When I try and run an AfxMessageBox from my CDialog extension class, I get an errror (see below). I've googled the internet but come up short. This is the only place the messagebox fails, and I know the rest of the code works (I stepped through it).
Does anyone know how to fix this?
Thanks in advance!
Error message when AFXMESSAGEBOX opens:
Unhandled exception at 0x014b4b70 in IsoPro.exe: 0xC0000005: Access violation reading location 0x34333345.
Code to launch AfxMessageBox, from within CDialog
LPTSTR temp;
mainPassword.GetWindowText((LPTSTR)temp,100);
CString cstr;
cstr.Format("mainPassword = %s",temp);
AfxMessageBox(cstr);
Code to display CDialog:
CEnterpriseManagementDialog* emd = new CEnterpriseManagementDialog();
emd->Create(IDD_ENTERPRISE_MANAGEMENT_DIALOG);
emd->ShowWindow(SW_SHOW);
The problem is how you use GetWindowText:
LPTSTR temp;
mainPassword.GetWindowText((LPTSTR)temp,100);
You are letting GetWindowText attempt to write to some unallocated memory passing the uninitialized temp pointer. If you really want to use a raw output buffer, you should allocate room for it before passing a pointer to GetWindowText, e.g.:
TCHAR temp[100];
mainPassword.GetWindowText(temp, _countof(temp));
// NOTE: No need to LPTSTR-cast
But, since you are using C++, you may want to just use a string class like CString, instead of raw buffers, e.g.:
CString password;
mainPassword.GetWindowText(password);
CString msg;
msg.Format(_T("mainPassword = %s"), password.GetString());
// or you can just concatenate CStrings using operator+ ...
AfxMessageBox(msg);
It looks like the variable temp is an uninitialized pointer (the definition of LPTSTR is a char *).
Try defining temp as an array instead:
TCHAR temp[64];
Related
inside my MFC (VC2010 SP1) project, I'm widely using a third party library to write some data in a database. This library is quite old (I've found it compiled for VS2005) and uses _variant_t to handle data.
In a particular case anyway I get a strange behaviour, I'll try to explain it:
// .h
struct myData
{
blastuff
CString strMyCode;
};
class MyClass
{
protected:
myData m_Foo;
};
// .cpp
// In OnInitDialog:
//...
TrdPartRecordset *pRS;
//...
pRS->GetFieldValue( _T("MyDBColumn"), m_Foo.strMyCode );
Now, I do my job and when user press OK, it's time to save to database and here start the problems:
// In OnOK
TrdPartRecordset *pRS;
//...
pRS->SetFieldValue( _T("MyDBColumn"), m_Foo.strMyCode );
Problem: if I do not modify m_Foo.strMyCode, I don't have any problem. What if I modify it? Well, if m_Foo.strMyCode does NOT contain ANY number, still have no problem.
Instead, when I have a number, I get a nasty error:
Unhandled exception at 0x77772d37 in Mosaico.exe: 0xC0000005: Access violation reading location 0x9d7077b7.
which is an attempt to read a deleted location. I've checked m_Foo in the watch and it's correct and valid, so I've digged into library source code:
BOOL TrdPartyRecordset::SetFieldValue(LPCTSTR lpFieldName, CString strValue)
{
_variant_t vtFld;
if(!strValue.IsEmpty())
vtFld.vt = VT_BSTR;
else
vtFld.vt = VT_NULL;
vtFld.bstrVal = strValue.AllocSysString();
BOOL bret = PutFieldValue(lpFieldName, vtFld);
SysFreeString(vtFld.bstrVal);
return bret;
}
What it happens is that vtFld is valid until SysFreeString and it get destroyed after it (I can see it proceding step-by-step with debugger), but ONLY WHEN I HAVE NUMBERS INTO strValue. This doesn't happen when strValue is pure alphabetical.
I've searched around the Internet and found that this kind of error happens when you double release a resource and so I've commented out SysFreeString and boom goes the dynamite: no more crashes.
Anyway is a better programmer than me so I guess that if he put that SysFreeString he had his reasons, moreover, this is the only part of my program where this mechanism crashes.
My question is: do I lose memory commenting out that SysFreeString?
Another one: do you have better solutions?
The reason is simple:
The memory is freed twice!
_variant_t has a destructor. Set the type to VT_BSTR. You also see the pojnter and type to VT_BSTR
After the function you call, you free the memory again and the destructor does the same.
The code should look like this:
_variant_t vtFld;
if(!strValue.IsEmpty())
vtFld = strValue;
else
vtFld.vt = VT_NULL;
return PutFieldValue(lpFieldName, vtFld);
I'm writing C++ dll on Visual studio 2013. My dll should read parameters from ini file. So, I've created a function for this purpose (ReadConnectionSettings()). My static variable serverIP gets value properly during the function working, however once the function complete running the variable (serverIP) loses its value. What seems to be the problem?
static LPTSTR serverIP = _TEXT("");
void ReadConnectionSettings()
{
TCHAR url[256];
GetPrivateProfileString(_T("Connection"), _T("Url"), _T(""), url, 256, NameOfIniFile);
serverIP = url;
}
You are pointing the pointer serverIP at stack memory url.
This goes out of scope when the function exits, so your pointer is left pointing to junk.
What you could do is make serverIP a buffer instead, and copy the URL into it. Then it would persist.
That is:
static TCHAR serverIP[256] = _TEXT("");
Then:
_tcsnccpy(serverIP, url, 255);
Or as #DavidOtano suggested, you could keep your existing serverIP pointer, and use:
serverIP = _tcsdup(url);
But if you do this, you're dynamically allocating memory, so will need to remember to call:
free(serverIP);
when you no longer need it, to avoid a memory leak.
You're setting the static pointer variable to point at a local variable that does not exist anymore after the function has returned.
A good way to return a string from a function in a Windows program, is to return a std::wstring.
Try that.
Regarding LPTSTR and _TEXT, you only need this if you intend to support MFC in DLLs in Windows 9x. Is that the case? If not, just ditch that Microsoft silliness.
The code fixed according to above advice (off the cuff, untouched by compiler's hands):
auto connection_settings()
-> std::wstring
{
std::wstring url( 256, L'#' );
auto const n = GetPrivateProfileString( L"Connection", L"Url", L"", &url[0], url.size(), NameOfIniFile );
url.resize( n );
return url;
}
One nice property of this code is that it no longer modifies a global variable.
EDIT: Dear Future Readers, the std::string had nothing to do with the problem. It was an unterminated array.
In a nutshell, the problem is that adding a declaration of a single std::string to a program that otherwise contains only C causes the error "Access violation reading location 0xfffffffffffffffe."
In the code below, if the line where the std::string is declared is commented out, the program runs to completion without error. If the line however is left in the program (uncommented), the program crashes with the above stated Acess Violation error. When I open the running program in the VS2010 debugger, the Access Violation has occurred at the call to ldap_search_sA().
Notice that the declared std::string is never used. It doesn't have to be used for it to cause the access violation. Simply declaring it will cause the Access Violation.
My suspicion is it has nothing to do with the LDAP code, but I could be wrong.
int main()
{
try {
// Uncommenting the next line causes an Access Violation
// at the call to ldap_search_sA().
// std::string s;
LDAP* pLdapConnection = ldap_initA("eu.scor.local", LDAP_PORT);
ULONG version = LDAP_VERSION3;
ldap_set_option(pLdapConnection, LDAP_OPT_PROTOCOL_VERSION, (void*) &version);
ldap_connect(pLdapConnection, NULL);
ldap_bind_sA(pLdapConnection, NULL, NULL, LDAP_AUTH_NTLM);
LDAPMessage* pSearchResult;
PCHAR pMyAttributes[2];
pMyAttributes[0] = "cn";
pMyAttributes[1] = "description";
ldap_search_sA(pLdapConnection, "dc=eu,dc=scor,dc=local", LDAP_SCOPE_SUBTREE, "objectClass=computer)", pMyAttributes, 0, &pSearchResult);
} catch (...) {
printf("exception\n");
}
return 0;
}
PCHAR pMyAttributes[2];
pMyAttributes[0] = "cn";
pMyAttributes[1] = "description";
Attribute array should be NULL-terminated:
PCHAR pMyAttributes[3];
pMyAttributes[0] = "cn";
pMyAttributes[1] = "description";
pMyAttributes[2] = NULL;
I don't know what ldap_search_sA is, but the ldap_search function in
OpenLDAP takes a pointer to a null pointer terminated array of char*.
The array you are passing isn't correctly terminated, so anything may
happen. I'd recommend using std::vector<char*> for this, in general,
and wrapping the calls in a C++ function which systematically postfixes
the terminator, so you don't forget. Although in such simple cases:
char* attributes[] = { "cn", "description", NULL };
will do the trick. It will probably provoke a warning; it really should
be:
char const* attributes[] = { ... };
But the OpenLDAP interface is legacy C, which ignores const, so you'd
need a const_cast at the call site. (Another argument for wrapping
the function.)
Finally, I'd strongly advise that you drop the obfuscating typedefs
like PCHAR; they just make the code less clear.
According to my experience, when weird things like this are observed in C++, what is in fact happening is that some piece of code somewhere corrupts memory, and this corruption may manifest itself in various odd ways, including the possibility that it may not manifest itself at all. These manifestations vary depending on where things are located in memory, so the introduction of a new variable probably causes things to be moved in memory just enough so as to cause a manifestation of the corruption where otherwise it would not be manifested. So, if I were in your shoes I would entirely forget about the string itself and I would concentrate on the rest of the code, trying to figure out exactly what you do in there which corrupts memory.
I notice that you invoke several functions without checking their return values, even though it is not in the spec of these functions to throw exceptions. So, if any of these functions fails, (starting with ldap_initA,) and you proceed assuming that it did not fail, you may get memory corruption. Have you checked this?
I am debugging some other programmer's source code of a Windows Media Player plugin. This plugin causes WMP to crash sometimes, and sometimes it takes really long time to open plugin settings window. The problem occurs only when opening settings window while music is being played back. It opens without issues if the player is stopped.
While looking through the code and debugging, I have came to the line of code which seems to be the cause of the problems.
The property page has the following member variable:
CComPtr<IDsp_plugin> m_pDsp_plugin;
and the property page at initialization calls get_text method of the COM object:
unsigned char * txt = NULL;
//m_pDsp_plugin is a valid pointer to IDsp_plugin
HRESULT res = m_pDsp_plugin->get_text(&txt);
At this moment hres is "0x80010105: The server threw an exception." and Visual Studio Debug output shows "First-chance exception at 0x764efbae in wmplayer.exe: 0x80010105:
get_text method is defined as follows:
in Dsp_plugin.idl
interface IDsp_plugin : IUnknown
{
HRESULT get_text([out] unsigned char* *pVal);
...
in Dsp_plugin.h
class ATL_NO_VTABLE CDsp_plugin :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CDsp_plugin, &CLSID_Dsp_plugin>,
public IDsp_plugin,
public IMediaObject,
public IWMPPluginEnable,
public ISpecifyPropertyPages
{
STDMETHOD(get_text)(unsigned char* *txt);
...
and finally the method itself which throws this exception:
Dsp_plugin.cpp
STDMETHODIMP CDsp_plugin::get_text (unsigned char* *txt)
{
... // some code for copying a valid string from somewhere to char* y
// 11 bytes of memory for y was allocated using malloc(10+1);
// y contains a valid C string here, tested with debugger and passing to OutputDebugStringA
*txt = (unsigned char*)(y); // This line executes normally, but at the end the caller gets "The server threw an exception." and WMP starts behaving weirdly.
// If I comment it out, the caller gets S_OK and there are no any issues with WMP.
return S_OK;
}
The COM DLL is compiled with setting "Use Unicode Character Set".
I am not experienced COM programmer, but passing strings as unsigned char** seems unusual to me, I have seen mostly BSTR or VARIANT when dealing with COM.
Maybe some COM guru can explain, why this exception happens and can it be possibly fixed just by converting methods to using BSTR* and SysAllocString/SysfreeString instead of unsigned char**/malloc/free ?
Put simply, COM doesn't know how to pass around pointers of type unsigned char *. The default marshalling rules are applied (since the interface definition doesn't specify any parameter attributes), and, if I'm interpreting this correctly, COM marshals the outer pointer itself txt properly, but treats *txt as a pointer to a single unsigned char, not a string.
This may still work if the caller and callee happen to be in the same apartment; from the sounds of it, they're not.
The easiest solution is simply to make the parameter a BSTR *. COM has special handling for BSTR which will ensure it's passed correctly.
From CString to char*, ReleaseBuffer() must be used after GetBuffer(). But why? What will happen if I don't use ReleaseBuffer() after GetBuffer()?
Can somebody show me an example? Thanks.
I'm not sure that this will cause a memory leak, but you must call ReleaseBuffer to ensure that the private members of CString are updated. For example, ReleaseBuffer will update the length field of the CString by looking for the terminating null character.
What will happen if I don't use ReleaseBuffer() after GetBuffer()?
I haven't used MFC (and hopefully won't ever have to touch it with a ten-foot pole) but, as a rule of thumb, whenever you have an API that has both GetXXX() and ReleaseXXX() (especially when the result of GetXXX() conveniently is of the type that ReleaseXXX() takes) -- then when you forget to call ReleaseXXX() for every one of your GetXXX() calls, you will leak an XXX.
Here's an example of how I used CString::GetBuffer() and CString::ReleaseBuffer() :
LPTSTR pUnitBuffer = pAPBElement->m_strUnits.GetBuffer(APB_UNIT_SIZE);
if (pUnitBuffer != "")
{
if (strncmp(pAPBElement->m_strUnits, (char*)pszBuffer[nLoop - nFirst], APB_UNIT_SIZE) != 0)
{
LPTSTR pUnitOriginal = pAPBElement->m_strOriginal.GetBuffer(APB_UNIT_SIZE);
strncpy(pUnitBuffer,
(char*)&pszBuffer[nLoop - nFirst],
APB_UNIT_SIZE);
strncpy(pUnitOriginal,
(char*)&pszBuffer[nLoop - nFirst],
APB_UNIT_SIZE);
pAPBElement->m_strOriginal.ReleaseBuffer();
}
}
pAPBElement->m_strUnits.ReleaseBuffer();
If you do not modify the contents of the CString using the pointer obtained using GetBuffer(), you do NOT need to call ReleaseBuffer() afterwards