Showing posts with label win32api. Show all posts
Showing posts with label win32api. Show all posts

Thursday, November 15, 2007

RichEdit common contrl

i'll keep this post update with all the things about Rich Edit.

#1 The RichEdit Version

The current versions of RichEdit control and their modules are:

ver 1.0 contained in Riched32.dll
ver 2.0 contained in Riched20.dll
ver 3.0 contained in Riched20.dll
ver 4.1 contained in Msftedit.dll

The Rich Edit 3.0 (Riched20.dll) is included in releases of Microsoft Windows 2000 and above.

#2 Initialization
You need to explicitly load the RichEdit library in your application in order to use the control. Hence, to use the 3.0 version call:

if(NULL == LoadLibrary("RichEd20.dll"))
{
// cannot load RichEdit v3.0
}

Thursday, October 04, 2007

the one and only, the TB_ADDSTRING message !

If you try to use TB_ADDSTRING with the string from the resource then you might had blown your head trying to figure out what the heck is happening, why does it fail:

const int iIndex = ::SendMessage(
hToolBar,
TB_ADDSTRING,
hResource,
IDS_TBSEARCH); // string id from module's resource

iIndex is returned -1 (indicating an error).

Now, I looked at my MSDN from disk and then looked at the online version. Nada. But the old friend Mr. Google saved the day (he always does). I got this page:

The problem with TB_ADDSTRING or the AddString method that is simply
a wrapper to this message is that the first character in the string
resource is used as separator and is replaced with a NULL character.

So your string resource must be something similar to: "|Button text||"
where the pipe character is replaced with '\0'.
This is because the string you pass with TB_ADDSTRING message must
have a double null terminator. You can also use the TB_ADDSTRINGS
message with which you can set all the button texts using a string
like this: "|Button 1|Button 2|Button 3|Button 4||".

This is not well documented or not documented at all, I don't
remember. Anyway keep in mind that the text added to the button with
TB_ADDSTRING is not retrieved using TB_GETBUTTONINFO, but only using
TB_GETBUTTONTEXT, this is why if you use this method instead of using
TB_SETBUTTONINFO, the chevron menu does not display the text of the
menu items


No, it's not documented at all.
Something was fishy from the start though.

When you create the toolbar using the CreateToolbarEx API, you pass an array of TBBUTTON structs. TBBUTTON has its last field either an zero-based index or a pointer to string buffers (the last string needed to be terminated by an extra null to indicate the end of the list).
Zero-based index of the button string, or a pointer to a string buffer that contains text for the button.


But the question is: In the case when you specified in the TB_ADDSTRING a resource string id, what's the zero-based index from TBBUTTON for ?

The problem is that the documentation is incomplete due to what the API tried to achieve. It wanted to provide several ways to add strings but the documention failed to explain exactly.

In toolbar controls you can set buttons text in at least 2 ways:
One way is when you create the toolbar using CreateToolbarEx API.
In each TBBUTTON structure you can put either a straight text buffer or a zero-based index of the button string:

TBBUTTON tbbtn = {0};
...
tbbtn.iString = _T("Text");

or

TBBUTTON tbbtn = {0};
...
tbbtn.iString = 0; // index

The index value is the index from the string list you set to the toolbar control using the TB_ADDSTRING message. The string list can be from 2 sources, either from:

a character array with one or more null-terminated strings:

LPCTSTR szTexts[] = {_T("Text1"), _T("Text2\0") };
::SendMessage(hToolbar, TB_ADDSTRING, NULL, (LPARAM)szTexts);

or from a string in the executable resource:

::SendMessage(hToolBar,
TB_ADDSTRING,
hResource,
IDS_TBSEARCH); // string id from module's resource

but in the latter case the resource string needs to be in a special form. Its first character will be used by the Common controls API as string separator, so
IDS_TBSEARCH can look like this: |Text1|Text2||

In the first case, you can use TB_ADDSTRING at a time, to add each string to the control internal list.

::SendMessage(hToolbar, TB_ADDSTRING, NULL, (LPARAM)_T("Text1\0"));
::SendMessage(hToolbar, TB_ADDSTRING, NULL, (LPARAM)_T("Text2\0"));

Another way to set a toolbar button text is using the TB_SETBUTTONINFO message but you are limited to pass only a string buffer.

Thursday, September 27, 2007

MAKEINTRESOURCE macro

Many Win32 API functions use a LPCTSTR parameter as resource name or type.
For example, a trivial one:

HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName);

And the documentation for the lpIconName states that:

Pointer to a null-terminated string that contains the name of the icon resource to be loaded. Alternatively, this parameter can contain the resource identifier in the low-order word and zero in the high-order word. Use the MAKEINTRESOURCE macro to create this value.

Now, how the LoadIcon code knows to diferentiate between a resource string name and a predefined constant like IDI_ASTERISK which is defined as:

#define IDI_ASTERISK MAKEINTRESOURCE(32516)

We are used to the wizard generated resource IDs in our applications but a resource can have any null terminated string as name and type too. Look to the FindResource function for example.

All resource Win32API functions use the macro IS_INTRESOURCE(id)

BOOL IS_INTRESOURCE(
WORD wInteger
);

#define IS_INTRESOURCE(_r) (((ULONG_PTR)(_r) >> 16) == 0)

If the macro is TRUE then the id "specifies the integer identifier of the name or type of the given resource. Otherwise, those parameters are long pointers to null-terminated strings"

Practically, the memory address of a name or type passed as input, is checked to see if its within the WORD boundary, or else said if the memory address is between 0 and unsigned short (65536), because:

typedef unsigned short WORD;

So, for the win32 API functions, if the pointer value has an 'invalid address' it's clear that it's rather an id (a integer, an unsisgned short in fact) then an actual memory address containing a null terminated string from the application.

Monday, July 09, 2007

Win32 HANDLEs

Each time when you use a win32 API which uses a HANDLE remember that the handle Must be valid (not closed).

It is important to understand the concepts of the handle being signaled and being closed.

Signaled state refers to the handle state. It can be signaled or unsignaled. Wait functions for example, like WaitForSingleObject, block current thread until the object gets signaled.

A handle is said to be closed when its reference count reaches zero value. When this happens the handle is closed and doing any waiting on it is error prone.

A handle is a pointer on an object. Wait functions check the state of the object, hence it is a must that the handler (the pointer) is valid. Otherwise, waiting functions wont work properly (while waiting on an invalid handle, you might wait indefinetly).

One example of bogus use is with MFC AfxBeginThread function. Its default behaviour is to auto 'delete' the thread, i.e to close its handle.
Its bad to use the returned handle after the thread is terminated and closed.
That its not a HANDLE. its a wild HANDLE.

This is described excellent in Chapter 12, Threads in the well known book by Jeff Prosise, Programming Windows with MFC, 2nd Edition.

Another missuse, without MFC, might be in an multithreaded application. One threads create a thread and share the handle others thread which use it.

Saturday, March 24, 2007

CreateDialog, CreateWindow or any other window\dialog creation function fails and GetLastError is 0

... then check if you have called InitCommonControls() at very start of your application if you use any common controls (list view, tree view ,etc)

Wednesday, March 01, 2006

process termination

Ive just looked to an interesting blog article talking about when a process terminates.
http://blog.kalmbachnet.de/?postid=65

It seem that there is a subtle difference between how a console application (the main() CRT function) and a Win32 application (WinMain) is handling the process termination.

if you have this:

DWORD WINAPI MyThread2(LPVOID)
{
while(true) { }
return 0;
}

#pragma comment(linker, "/entry:myMain")
int WINAPI myMain()
{
DWORD dwThreadId;
CloseHandle(CreateThread(NULL, 0, MyThread2, NULL, 0, &dwThreadId));
return 0;
}

the application is a windows application (using myMain entrypoint) and it run infinitely.

but a similar console application:

int t_main()
{
DWORD dwThreadId;
CloseHandle(CreateThread(NULL, 0, MyThread2, NULL, 0, &dwThreadId));
return 0;
}

will return immediately after the 'return 0;'

the difference is this one:

the console application uses CRT which, after the user code return from main, it calls ExitProcess which terminates the application.

it seems that when a thread terminates, Win OS internally calls EndThread. The EndThread internally looks if there is any other thread running in the process and calls TerminateThread(if there are any) or ExitProcess (if there isnt any).

hence, in a Win32 application, if any thread returns, internally EndThread is called and this in turn, if no other threads are still running, will call ExitProcess.

in a CRT app, when the main thread returns, ExitProcess is called directly.

Saturday, December 03, 2005

SuspendThread

as the msdn says SuspendThread is for debugging purposes and should not be used.
it may be tempting to use it to pause a worker thread for example but it might not be ok.
the worker thread can be in the middle of executing a CRT function which is thread safe, using sychronization.
if the worker thread is paused after the lock is done, trying to execute from another thread a CRT function, which uses the same syncronization access, might get to a deadlock.

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;

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