Multiple IWebBrowser2 not releasing memory - c++

I've a big plain c++ project where I implemented a webbrowser control (the idea come from https://github.com/Tobbe).
Well I inject some external method with the AddCustomObject. The problem is when I need to dispose a big page (1.9KB) with many object (tinymce, jquery ecc) for local editing ... the memory increasing every time I open the page.
I've searched, googled, readed, contacted the original developer... nope.
In the close method the code is this:
if (ibrowser != 0) {
IConnectionPointContainer *cpc = 0;
ibrowser->QueryInterface(IID_IConnectionPointContainer, (void**)&cpc);
if (cpc != 0) {
IConnectionPoint *cp = 0;
cpc->FindConnectionPoint(DIID_DWebBrowserEvents2, &cp);
if (cp != 0) {
cp->Unadvise(cookie);
cp->Release();
}
cpc->Release();
}
IOleObject *iole = 0;
ibrowser->QueryInterface(IID_IOleObject, (void**)&iole);
/*ibrowser->Stop();
ibrowser->ExecWB(OLECMDID_CLOSE, OLECMDEXECOPT_DONTPROMPTUSER, 0, 0);
ibrowser->put_Visible(VARIANT_FALSE);*/
UINT refCount = ibrowser->Release();
ibrowser = 0;
if (iole != 0) {
iole->Close(OLECLOSE_NOSAVE);
iole->Release();
}
}
Debugging in Vs2008 I've saw many CustomObject::AddRef and Release maybe due to setTimeout
I've no idea how to resolve this... need help!
Thank's!
Andrea

Related

SetPerTcpConnectionEStats fails and can't get GetPerTcpConnectionEStats multiple times c++

I am following the example in https://learn.microsoft.com/en-gb/windows/win32/api/iphlpapi/nf-iphlpapi-getpertcp6connectionestats?redirectedfrom=MSDN to get the TCP statistics. Although, I got it working and get the statistics in the first place, still I want to record them every a time interval (which I haven't managed to do so), and I have the following questions.
The SetPerTcpConnectionEStats () fails with status != NO_ERROR and equal to 5. Although, it fails, I can get the statistics. Why?
I want to get the statistics every, let's say 1 second. I have tried two different ways; a) to use a while loop and use a std::this_thread::sleep_for(1s), where I could get the statistics every ~1sec, but the whole app was stalling (is it because of the this), I supposed that I am blocking the operation of the main, and b) (since a) failed) I tried to call TcpStatistics() from another function (in different class) that is triggered every 1 sec (I store clientConnectRow to a global var). However, in that case (b), GetPerTcpConnectionEStats() fails with winStatus = 1214 (ERROR_INVALID_NETNAME) and of course TcpStatistics() cannot get any of the statistics.
a)
ClassB::ClassB()
{
UINT winStatus = GetTcpRow(localPort, hostPort, MIB_TCP_STATE_ESTAB, (PMIB_TCPROW)clientConnectRow);
ToggleAllEstats(clientConnectRow, TRUE);
thread t1(&ClassB::TcpStatistics, this, clientConnectRow);
t1.join();
}
ClassB::TcpStatistics()
{
while (true)
{
GetAndOutputEstats(row, TcpConnectionEstatsBandwidth)
// some more code here
this_thread::sleep_for(milliseconds(1000));
}
}
b)
ClassB::ClassB()
{
MIB_TCPROW client4ConnectRow;
void* clientConnectRow = NULL;
clientConnectRow = &client4ConnectRow;
UINT winStatus = GetTcpRow(localPort, hostPort, MIB_TCP_STATE_ESTAB, (PMIB_TCPROW)clientConnectRow);
m_clientConnectRow = clientConnectRow;
TcpStatistics();
}
ClassB::TcpStatistics()
{
ToggleAllEstats(m_clientConnectRow , TRUE);
void* row = m_clientConnectRow;
GetAndOutputEstats(row, TcpConnectionEstatsBandwidth)
// some more code here
}
ClassB::GetAndOutputEstats(void* row, TCP_ESTATS_TYPE type)
{
//...
winStatus = GetPerTcpConnectionEStats((PMIB_TCPROW)row, type, NULL, 0, 0, ros, 0, rosSize, rod, 0, rodSize);
if (winStatus != NO_ERROR) {wprintf(L"\nGetPerTcpConnectionEStats %s failed. status = %d", estatsTypeNames[type], winStatus); //
}
else { ...}
}
ClassA::FunA()
{
classB_ptr->TcpStatistics();
}
I found a work around for the second part of my question. I am posting it here, in case someone else find it useful. There might be other solutions too, more advanced, but this is how I did it myself. We have to first Obtain MIB_TCPROW corresponding to the TCP connection and then to Enable Estats collection before dumping current stats. So, what I did was to add all of these in a function and call this instead, every time I want to get the stats.
void
ClassB::FunSetTcpStats()
{
MIB_TCPROW client4ConnectRow;
void* clientConnectRow = NULL;
clientConnectRow = &client4ConnectRow;
//this is for the statistics
UINT winStatus = GetTcpRow(lPort, hPort, MIB_TCP_STATE_ESTAB, (PMIB_TCPROW)clientConnectRow); //lPort & hPort in htons!
if (winStatus != ERROR_SUCCESS) {
wprintf(L"\nGetTcpRow failed on the client established connection with %d", winStatus);
return;
}
//
// Enable Estats collection and dump current stats.
//
ToggleAllEstats(clientConnectRow, TRUE);
TcpStatistics(clientConnectRow); // same as GetAllEstats() in msdn
}

Check if Windows Computer on Ethernet Via C++

So I have tried looking at a couple of different answers for this. One that I thought may have promise was this one:
How to check network interface type is Ethernet or Wireless on Windows using Qt?
However, I don't really know too much about Networking or even about Windows. Personally, I cannot understand most of the Microsoft documentation on their websites. I have tried things like INetworkConnection, NativeWiFi, etc. But either they do not do what I want, or I just cannot figure out how to do it from the available documentation.
With that being said, I would like to use C++ to check if the device this program is being run on is connected to the internet via Ethernet cable. Basically, I want to do the following:
If the computer is connected to Wireless only, run the program
If the computer is connected to Wired only, don't run the program
If the computer is connected to both Wired AND Wireless, don't run the program
However, the problem is that I don't know how to check if the device has Ethernet connected. Is there a way to do this? I am NOT using QT. Thank you!
EDIT: I should also include what I have tried so far.
I tried using GetAdaptersInfo and getting the Type trait from the PIP_ADAPTER_INFO variable type, but that always gives me Unknown type 71 whether I am on Ethernet or not.
The documentation for that GetAdaptersInfo is here:
https://msdn.microsoft.com/en-us/library/aa365917%28VS.85%29.aspx
Thanks
EDIT 2: Here is the code I was using for GetAdaptersInfo
bool is_on_ethernet{
PIP_ADAPTER_INFO pAdapterInfo;
PIP_ADAPTER_INFO pAdapter = NULL;
DWORD dwRetVal = 0;
UINT i;
struct tm newtime;
char buffer[32];
errno_t error;
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
if(pAdapterInfo == NULL)
printf("Error allocating memory need to call GetAdaptersInfo");
if(GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW){
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
}
if((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR){
pAdapter = pAdapterInfo;
switch(pAdapter->Type){
case MIB_IF_TYPE_OTHER:
printf("Other\n");
return false;
break;
case MIB_IF_TYPE_ETHERNET:
printf("Ethernet\h");
return true;
break;
case MIB_IF_TYPE_TOKENRING:
printf("Token Ring\n");
return false;
break;
case MIB_IF_TYPE_FDDI
printf("FDDI\n");
return false;
break;
case MIB_IF_TYPE_PPP
printf("PPP\n");
return false;
break;
case MIB_IF_TYPE_LOOPBACK
printf("Lookback\n");
return false;
break;
case MIB_IF_TYPE_SLIP
printf("Slip\n");
return false;
break;
default
printf("Unknown type %ld\n\n", pAdapter->Type);
return false;
break;
}
}
if(pAdapterInfo)
free(pAdapterInfo);
return false;
}
Your problem is somewhat difficult as it can be really complicated to get the "current" network adapter --- windows routes packets depending on network adapter configuration and destination reachability so your "current" adapter may change at any time ... but since you already know how to retrieve IPs and MACs ("hardware address") of available adapters you could simply use your hack to retrieve a MAC for your current IP and filter/search inside of my second function for it! The field "PhysicalAddress" is what you're looking for, thats the MAC adress
I have made the experience that the only, somewhat reliable way of doing that is via GetIfTable and GetIfTable2, the former returns somewhat superficial adpater info and the latter provides great detail.
Heres a sample implementation, as it uses the detailed function you can also query for WLAN adapters :
vector<MIB_IF_ROW2>* getDevices(NDIS_PHYSICAL_MEDIUM type)
{
vector<MIB_IF_ROW2> *v = new vector<MIB_IF_ROW2>();
PMIB_IF_TABLE2 table = NULL;
if(GetIfTable2Ex(MibIfTableRaw, &table) == NOERROR && table)
{
UINT32 i = 0;
for(; i < table->NumEntries; i++)
{
MIB_IF_ROW2 row;
ZeroMemory(&row, sizeof(MIB_IF_ROW2));
row.InterfaceIndex = i;
if(GetIfEntry2(&row) == NOERROR)
{
if(row.PhysicalMediumType == type)
{
v->push_back(row);
}
}
}
FreeMibTable(table);
}
return v;
}
Now all you need to do is iterate over the list and filter out disabled adapters and whatnot :
vector<MIB_IF_ROW2>* wlan = getDevices(NdisPhysicalMediumNative802_11); //WLAN adapters
//see https://msdn.microsoft.com/en-us/library/windows/desktop/aa814491(v=vs.85).aspx, "PhysicalMediumType" for a full list
for(auto &row : *v)
{
//do some additional filtering, this needs to be changed for non-WLAN
if( row.TunnelType == TUNNEL_TYPE_NONE &&
row.AccessType != NET_IF_ACCESS_LOOPBACK &&
row.Type == IF_TYPE_IEEE80211 &&
row.InterfaceAndOperStatusFlags.HardwareInterface == TRUE)
{
//HERE BE DRAGONS!
}
}
Now its quite easy to generate lists of WLAN adapters and non-WLAN adapters (see comment in second function), search for your current MAC and conclude that it is wired or wireless - but be aware that these lists may overlap since 802.11 basically is an extended version of 802.3 but 802.3 does not include 802.11 (since its an extension) - so you will need a tiny bit of if/else logic going on in order to seperate WLAN from non-WLAN adapters.
You could also use WlanEnumInterfaces to get all of the WLAN adapters but thats basically the same as using the above function with NdisPhysicalMediumNative802_11 as parameter ...
So first, thank you very much to user #Nighthawk441 for pointing me in the right direction for this. Without this user, I would most certainly have not come up with a solution.
That being said, the solution I have right now is, at best, a hack. It seems to work, but I don't think it is even close to the best option. Thus, I will leave this as an answer but I will not accept it for a little while in the event that a better answer is found. I am also very open to any comments anyone may have as it pertains to this answer.
In short, what I did was I looped through all of the Adapters from GetAdaptersInfo. In order to see if the adapter was connected, I compared the IP address of the adapter to the string "0.0.0.0", as if it were something other than this I felt it was safe to say that the adapter was connected. So, without further ado, here is the code that I implemented.
bool is_on_ethernet(){
PIP_ADAPTER_INFO pAdapterInfo;
PIP_ADAPTER_INFO pAdapter = NULL;
DWORD dwRetVal = 0;
UINT i;
struct tm newtime;
char buffer[32];
errno_t error;
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
if(pAdapterInfo == NULL)
printf("Error allocating memory needed to call GetAdaptersInfo");
if(GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW){
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
}
if((dwRetValue = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR){
do{
pAdapter = pAdapterInfo;
string ip_string = pAdapter->IpAddressList.IpAddress.String;
switch(pAdapter->Type){
case MIB_IF_TYPE_OTHER:
printf("Other\n");
break;
...
case MIB_IF_TYPE_ETHERNET:
printf("Ethernet\n");
//new code
if(ip_string.compare("0.0.0.0") != 0){
free(pAdapterInfo);
return true;
}
break;
default:
printf("Unknown type %ld\n", pAdapter->Type);
break;
}
}while(pAdapterInfo = pAdapterInfo->Next);
}
if(pAdapterInfo)
free(pAdapterInfo);
return false;
}
Looking at this reference really helped me:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365819%28v=vs.85%29.aspx
So thank you to Nighthawk for supplying that information to me. Hopefully this will help someone else! If anyone has any comments or any other answers, feel free to post them! Thanks!
Based on #specializt's answer, and with some minor modification, I got it work for me as following:
BOOL getDevices(NDIS_PHYSICAL_MEDIUM type, vector<MIB_IF_ROW2>& vetIFRow)
{
PMIB_IF_TABLE2 table = NULL;
if (GetIfTable2Ex(MibIfTableRaw, &table) != NOERROR || !table)
{
return FALSE;
}
for (ULONG i = 0; i < table->NumEntries; i++)
{
MIB_IF_ROW2 row;
ZeroMemory(&row, sizeof(MIB_IF_ROW2));
row.InterfaceIndex = i;
if (GetIfEntry2(&row) == NOERROR && row.PhysicalMediumType == type)
{
vetIFRow.push_back(row);
}
}
FreeMibTable(table);
return TRUE;
}
BOOL isNetIFConnected(const MIB_IF_ROW2& row, IFTYPE Type)
{
return (row.TunnelType == TUNNEL_TYPE_NONE &&
row.AccessType != NET_IF_ACCESS_LOOPBACK &&
row.Type == Type &&
row.InterfaceAndOperStatusFlags.HardwareInterface == TRUE &&
row.MediaConnectState == MediaConnectStateConnected);
}
tstring getNetWorkType()
{
vector<MIB_IF_ROW2> vectRow;
BOOL bRet = getDevices(NdisPhysicalMedium802_3, vectRow); // ETHERNET adapters
if (bRet)
{
for (auto it = vectRow.begin(); it != vectRow.end(); it++)
{
if (isNetIFConnected(*it, IF_TYPE_ETHERNET_CSMACD))
{
return L"ETHERNET";
}
}
}
vectRow.clear();
bRet = getDevices(NdisPhysicalMediumNative802_11, vectRow); //WLAN adapters
if (bRet)
{
for (auto it = vectRow.begin(); it != vectRow.end(); it++)
{
if (isNetIFConnected(*it, IF_TYPE_IEEE80211))
{
return L"WIFI";
}
}
}
return L"Unknown";
}
Thanks to #specializt

Importing DLL's doesn't work the same (VS2003 to VS2010, multithreaded to multithreaded DLL)

During a massive code update from a mix of VC6, VS2003, and VS2005, I am running into a problem where VS2010 doesn't behave like VS2003 did. The application will scan a directory of DLL's and attempt to load them in one by one. This is done here:
CConfigPlugin::CConfigPlugin(LPCTSTR szPluginName)
{
ASSERT(szPluginName);
ASSERT(AfxIsValidString(szPluginName));
m_csFullpath = szPluginName;
m_hModule = LoadLibrary(m_csFullpath);
m_pInterface = (IConfigDllInterface *) NULL;
pInterface pPtr = pInterface(NULL);
if (m_hModule != NULL)
{
// If we loaded the DLL get the interface pointer
pPtr = pInterface(GetProcAddress(m_hModule, "GetInterface"));
}
if (pPtr != NULL)
{
pPtr(&m_pInterface);
}
else
{
::FreeLibrary(m_hModule);
m_hModule = HMODULE(NULL);
}
}
All DLL's show as being loaded:
...
'GenConfig.exe': Loaded 'C:\src\Debug\config\GenLogonConfig.dll', Symbols loaded.
'GenConfig.exe': Loaded 'C:\src\Debug\config\GenReportConfig.dll', Symbols loaded.
'GenConfig.exe': Loaded 'C:\src\Debug\config\ImportConfig.dll', Symbols loaded.
...
Each DLL has an identical GetInterface implementation shown below:
CConfigDllInterfaceImpl<CParentDlg> gdllObj;
BOOL GetInterface(IConfigDllInterface **ppPtr)
{
*ppPtr = &gdllObj;
// Temporary edit to test if gdllObj is set to proper parent.
CString name;
name = gdllObj.GetDisplayName();
// End edit
return true;
}
With a template as shown below:
__declspec(selectany) UINT guiAdvise;
template <class T> class CConfigDllInterfaceImpl : public IConfigDllInterface
{
public:
CConfigDllInterfaceImpl()
{
guiAdvise = RegisterWindowMessage(_T("GenConfig"));
m_pDlg = NULL;
}
virtual LPCTSTR GetDisplayName() const
{
static CString csTemp;
csTemp.LoadString(IDS_DISPLAY_NAME);
return csTemp;
}
// Can't be virtual because it uses the template T argument
BOOL DoModal(HWND hParent)
{
ASSERT(IsWindow(hParent));
if (m_pDlg == (T *) NULL)
{
m_pDlg = new T(CWnd::FromHandle(hParent));
return m_pDlg->Create();
}
else if (IsWindow(m_pDlg->GetSafeHwnd()))
{
m_pDlg->PostMessage(guiAdvise, eAdviseSwitchViews);
m_pDlg->SetActiveWindow();
}
return TRUE;
} // SNIP...
I can tell that my template isn't properly registering to its intended parent. GetDisplayName just returns "". My suspicion the cause of my problem is that I made a decision a month ago to change everything to Multithreaded DLL from Multithreaded. These are all MFC projects and it seemed the simplest and easiest way to just use _AFXDLL and make everything properly compile and link. All of the rest of my projects work fine, but I believe that because of the way this DLL is loaded:
CConfigDllInterfaceImpl gdllObj;
No longer works the way it used to.
So, question 1: Is my suspicion correct? Or am I completely offbase?
Question 2: If my suspicion is correct, how do I work around this? It isn't an option to go back to multithreaded at this point.
Thanks in advance.
I finally have some time to get back to answering this. Collin Dauphinee was correct in that it was a resource issue. I don't know why VS2003 is different from VS2010, but the solution was very simple.
CConfigPlugin::CConfigPlugin(LPCTSTR szPluginName)
{
ASSERT(szPluginName);
ASSERT(AfxIsValidString(szPluginName));
// Save off current Afx resource handle.
HINSTANCE hCurrentAfx = AfxGetResourceHandle(); // <--- Didn't need to
// do this before.
m_csFullpath = szPluginName;
m_hModule = NULL;
m_hModule = LoadLibrary(m_csFullpath);
m_pInterface = (IConfigDllInterface *) NULL;
pInterface pPtr = pInterface(NULL);
if (m_hModule != NULL)
{
AfxSetResourceHandle(m_hModule); // <--- here is where the resources
// get properly set. This is the
// solution to the problem.
// If we loaded the DLL get the interface pointer
pPtr = pInterface(GetProcAddress(m_hModule, "GetInterface"));
}
if (pPtr != NULL)
{
pPtr(&m_pInterface);
}
else
{
::FreeLibrary(m_hModule);
m_hModule = HMODULE(NULL);
}
// Now put Afx back.
AfxSetResourceHandle(hCurrentAfx);
}
I hope this helps someone else. I was stuck for days on this one.

How to get the names of all power schemes in windows 7 in C++?

I have to get the names of all available power schemes in windows 7. I try to enumerate them with the power management functions and I do get the right amount but when I call "PowerReadFriendlyName" (http://msdn.microsoft.com/en-us/library/windows/desktop/aa372740%28v=vs.85%29.aspx) it works sometimes and fails sometimes:
UCHAR displayBuffer[256];
DWORD displayBufferSize = sizeof(displayBuffer);
GUID buffer;
DWORD bufferSize = sizeof(buffer);
int index;
int fail=0,ok=0;
//
for(index = 0 ; ; index++)
{ ZeroMemory(&buffer, sizeof(buffer));
ZeroMemory(&displayBuffer, sizeof(displayBuffer));
if (PowerEnumerate(NULL,NULL,NULL, ACCESS_SCHEME,index,(UCHAR*)&buffer,&bufferSize) == ERROR_SUCCESS)
{ if (PowerReadFriendlyName(NULL, &buffer,&NO_SUBGROUP_GUID,NULL,displayBuffer,&displayBufferSize) == ERROR_SUCCESS)
{ ok++;
// stuff to todo
}
else
{ fail++;
// why?
}
}
else
{ break;
}
}
At first I had 2 custom power schemes and the retrieval of their name always failed. The standard 3 power schemes (high performance, balanced, power saver) always worked.
So I thought it had to do with the custom schemes and I manually added 2 more of them. But as it turns out now one of them actually works and I can get its name (both were derived from balanced).
I then manually added another 2 custom schemes (this time derived from power saver) and this time both seemed to work. I now have 9 in total and I can get the names of 6 of them. I cannot get the name of the 2 original custom power schemes (both derived from balanced) as well as the 2nd of the ones I added the first time.
When I type "powercfg -list" in a console I can get the list of all power schemes, but how can I get the names of all power schemes reliably in c++ without redirecting/parsing the console but using the windows power management functions?
The documentation of the PowerReadFriendlyName() function does not mention that the variable holding the length of the buffer gets overwritten in a successful call with a non-NULL buffer. It has therefore be set before each call of PowerReadFriendlyName() or it can fail:
UCHAR displayBuffer[2048];
DWORD displayBufferSize;
GUID buffer;
DWORD bufferSize = sizeof(buffer);
int index;
int fail=0,ok=0;
//
for(index = 0 ; ; index++)
{ ZeroMemory(&buffer, sizeof(buffer));
ZeroMemory(&displayBuffer, sizeof(displayBuffer));
if (PowerEnumerate(NULL,NULL,NULL, ACCESS_SCHEME,index,(UCHAR*)&buffer,&bufferSize) == ERROR_SUCCESS)
{ displayBufferSize = sizeof(displayBuffer);
if (PowerReadFriendlyName(NULL, &buffer,&NO_SUBGROUP_GUID,NULL,displayBuffer,&displayBufferSize) == ERROR_SUCCESS)
{ ok++;
// stuff to todo
}
else
{ fail++;
}
}
else
{ break;
}
}

Memory validate in difficult task within thread

I'm currently creating a sound system for my project. Every call PlayAsync creating instance of sound in std::thread callback. The sound data proceed in cycle in this callback. When thread proceeds it store sound instance in static vector. When thread ends (sound complete) - it delete sound instance and decrement instance count. When application ends - it must stop all sounds immediate, sending interrupt to every cycle of sound.
The problem is in array keeping these sounds. I am not sure, but I think vector isn't right choice for this purpose.. Here is a code.
void gSound::PlayAsync()
{
std::thread t(gSound::Play,mp_Audio,std::ref(*this));
t.detach();
}
HRESULT gSound::Play(IXAudio2* s_XAudio,gSound& sound)
{
gSound* pSound = new gSound(sound);
pSound->m_Disposed = false;
HRESULT hr;
// Create the source voice
IXAudio2SourceVoice* pSourceVoice;
if( FAILED( hr = s_XAudio->CreateSourceVoice( &pSourceVoice, pSound->pwfx ) ) )
{
gDebug::ShowMessage(L"Error creating source voice");
return hr;
}
// Submit the wave sample data using an XAUDIO2_BUFFER structure
XAUDIO2_BUFFER buffer = {0};
buffer.pAudioData = pSound->pbWaveData;
buffer.Flags = XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer
buffer.AudioBytes = pSound->cbWaveSize;
if( FAILED( hr = pSourceVoice->SubmitSourceBuffer( &buffer ) ) )
{
gDebug::ShowMessage(L"Error submitting source buffer");
pSourceVoice->DestroyVoice();
return hr;
}
hr = pSourceVoice->Start( 0 );
// Let the sound play
BOOL isRunning = TRUE;
m_soundInstanceCount++;
mp_SoundInstances.push_back(pSound); #MARK2
while( SUCCEEDED( hr ) && isRunning && pSourceVoice != nullptr && !pSound->m_Interrupted)
{
XAUDIO2_VOICE_STATE state;
pSourceVoice->GetState( &state );
isRunning = ( state.BuffersQueued > 0 ) != 0;
Sleep(10);
}
pSourceVoice->DestroyVoice();
delete pSound;pSound = nullptr; //its correct ??
m_soundInstanceCount--;
return 0;
}
void gSound::InterrupAllSoundInstances()
{
for(auto Iter = mp_SoundInstances.begin(); Iter != mp_SoundInstances.end(); Iter++)
{
if(*Iter != nullptr)//#MARK1
{
(*Iter)->m_Interrupted = true;
}
}
}
And this I call in application class before disposing sound objects, after main application loop immediate.
gSound::InterrupAllSoundInstances();
while (gSound::m_soundInstanceCount>0)//waiting for deleting all sound instances in threads
{
}
Questions:
So #MARK1 - How to check memory validation in vector? I don't have experience about it. And get errors when try check invalid memory (it's not equals null)
And #MARK2 - How to use vector correctly? Or maybe vector is bad choice? Every time I create sound instance it increases size. It's not good.
A typical issue:
delete pSound;
pSound = nullptr; // issue
This does not do what you think.
It will effectively set pSound to null, but there are other copies of the same pointer too (at least one in the vector) which do not get nullified. This is why you do not find nullptr in your vector.
Instead you could register the index into the vector and nullify that: mp_SoundInstances[index] = nullptr;.
However, I am afraid that you simply do not understand memory handling well and you lack structure. For memory handling, it's hard to tell without details and your system seems complicated enough that I am afraid it would tell too long to explain. For structure, you should read a bit about the Observer pattern.