Thursday, November 10, 2005

stuff to do on DLL_PROCESS_ATTACH

it is guaranteed you can call any Kernel32.dll function on the DLL_PROCESS_ATTACH.
Calling any other function from other library is not ok, as the DLLs may not be loaded at that time (although your code links with those libs).
more info can be found in the J. Richter book. and J.Robbins say some problem he had in the past with some thread work in DLL_PROCESS_ATTACH.

using std lib functions between dlls

it is OK to have functions with variables of class vector or other std lib class, and call these functions between different DLLs executable modules or between EXE and DLLs, as long as both of the modules are linked in the same way to the C run time library (hence memory is alocated by the same code) .
info i think can be found in "C/C++ Run-Time Library Considerations", Chapter 6 in "Programming Apps for Windows" by J. Richter.

oversee CloseHandle

there are many WinAPI functions which create and return a HANDLE object, like CreateThread, CreateFile.
in windows header file, a HANDLE is defined like this
typedef void* HANDLE

doing a 'CloseHandle' more than it is needed on the same HANDLE value is as bad as doing 'delete' on the same pointer.
the docs say:
"CloseHandle invalidates the specified object handle, decrements the object's handle count, and performs object retention checks. After the last handle to an object is closed, the object is removed from the system."
so as long as the handle count is not zero, its logic of course to call CloseHandle.

there are few considerations with the HANDLE objects:
- some functions are not requiring to do CloseHandle on the their returned HANDLE object; so always, always read the docs; dont rely on the fact you are an experienced WinAPI programmer; the behaviour might be (it is !) different between functions (in fact you can find an example in the John Robbins book, Debugging Windows);
- doing a CloseHandle on an object which is invalid it may be disastrous;
Once, my CloseHandle hit a memory location where a CString was living;

Tuesday, November 08, 2005

Monday, November 07, 2005

multithreading issue

ok, here is my task:
i have a dialog (main thread) and i have a worker thread running which updates a progressbar on the GUI.
when i press the close button i want the main thread and the worker thread to end cleanly (i want tthe threads to be closed nicely, without any TerminateThread or anything)

now, the problem stay in the fact that when i signal (using an event or something) the worker thread to end and then wait for it to end (using WaitForSingleObject for example) it is possible that in this time the worker thread to send a message to the GUI to update the progressbar(using SendMessage). Now, some may say why that SendMessage is a mistake but maybe not.

I want to be sure that the GUI and worker are synchronized perfectly (i dont want to use PostMessage; in some situations, for example when a buffer is needed to be sent, PostMessage only will not work (the buffer needs to be available when the message arrive to the receiver queue), hence, for PostMessage, some queue mechanism might be needed, if a text buffer for example is sent.

I came across a simple solution:
AtlWaitWithMessageLoop
its a function which use MsgWaitForMultipleObjects and does the job (in fact you can use your own implementation instead)

the idea is that, the main thread needs to be still getting messages for processing but in the same time, it will wait till the given synchronization object becomes invalid (beacause we may have 2 statements which can wait to eachother, a deadlock may appear; we can have the WaitForSingleObject(hWorkerThread); from main thread and the SendMessage from the workerthread)


//
//Stop the 'LoadLogs' thread, if its runnning
//
void CLogPage::StopLoadLogsThread()
{

if(m_hThreadLoadLogs)
{
//thread is accessing the log-file using CFile and it must be stopped before deleting the log-file
//stop the thread and wait till thread is stopped
InterlockedExchange(&m_snRunThread, 0);
AtlWaitWithMessageLoop(m_hThreadLoadLogs);
}

}

shell api power

i've discovered some months ago that the shell libary shlwapi.dll has, beside some well known functions like SHBrowseForFolder also some tiny functions but very useful.
instead of writing your own functions why dont use those which already exist, especially if come from OS DLL's ?
u are sure they are working OK and also it may be faster then yours (applicatinos like Windows Explorer use the DLL already, hence the functions might already be loaded in the memory pages)

those functions stay mostly in so called "Shell Lightweight Utility Functions", and they are grouped in
String Functions,
Path Functions
Registry Functions
Color Palette Functions,
Miscellaneous

For example, i needed a function which gives a text formatted to display the size of a file like this:
100 MB
123 KB
...

this function already exists in shell lib, StrFormatByteSizeW Function or StrFormatByteSizeA Function

so I will always check out the shell functions whenever i have this kind of small tasks to do

watch out for those macros.. "macros are evil !"

macros are evil !

i want to set an item text in a listview control representing a date
ListView_SetItemText(hWnd, iIndex, 1, log.GetTimeString().GetBuffer(0));

the log object is like this:
class CLog : public CObject
{

...
CString GetDateString() { return m_datetime.Format(_T("%d/%m/%Y")); }
CString GetTimeString() { return m_datetime.Format(_T("%H:%M:%S")); }

...

}

ListView_SetItemText(hWnd, iIndex, 1, log.GetTimeString().GetBuffer(0));
is bad because the CString object returned by the GetTimeString is temporary (and valid only in that line) but the ListView_SetItemtext is a macro !
looking inside it, it looks like this:

#define ListView_SetItemText(hwndLV, i, iSubItem_, pszText_) { LV_ITEM _ms_lvi;_ms_lvi.iSubItem = iSubItem_;_ms_lvi.pszText = pszText_;SNDMSG((hwndLV), LVM_SETITEMTEXT, (WPARAM)(i), (LPARAM)(LV_ITEM *)&_ms_lvi);}
so once the buffer is set to _ms_lvi.pszText the CString object is destroyed and the SNDMSG will send an invalid buffer

nice playtool

if there is any human reading my blog and is interested in programming, check this tool of a friend of mine:

www.codecentrix.com

i think its awesome

always use memset on the structures

never leave a structure with unfilled values, for example:

BROWSEINFO bi;
SHBrowseForFolder(&bi);

in order to avoid this, a good practice would be one of these:

- remember to always initialize members we don't need:
bi.hwndOwner = NULL;

- just initialize the variabile:
BROWSEINFO bi = { 0 };

- use memset on the structure:
memset(bi, 0, sizeof(BRWOSEINFO));

my own blog

wow.. ive just created my own blog page