October 30, 2025, 12:44:27 PM

News:

IWBasic runs in Windows 11!


Windows API conventions

Started by Parker, January 27, 2006, 11:34:35 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Parker

Just thought I'd point this out...
When you declare the API functions yourself (have no headers) you have to get used to what everything is in reality, like MS typedefs DWORD as unsigned int, also HANDLE, and LP* means a pointer to x. Also the function names that handle strings have an A or W appended to them in order to designate the ANSI or Unicode versions. Some structures have this too which is why I've been talking about the addition to the typedef command. In C it's all hidden from you, since you either define UNICODE or you don't, and that determines what the typedef ends up as.

For example, this function from MSDN:
LONG SetWindowLong(     

    HWND hWnd,
    int nIndex,
    LONG dwNewLong
);

If you look at the bottom of the page, you will see "Implemented as ANSI and Unicode versions." which means that there's either an A or W tacked onto the end depending on what function you want to use. Since Aurora doesn't support unicode quite yet, let's assume we're using the ANSI one. We might convert it like this
declare import, SetWindowLongA(
    unsigned int hWnd,
    int nIndex,
    unsigned int dwNewLong
),unsigned int;


Which (modified a little) is perfectly okay in C too. The reason it's declared differently is compilers give warnings about incompatible types even if they are the same with different names (typedef). So for example if you tried to pass an HMENU in place of hWnd, the VC++ compiler (or GCC, any other C compiler) would give you an incompatible type warning, which would tell you to go back and check that area, and maybe that's why your program wasn't working correctly. Of course sometimes it's annoying, like doing (HMENU)1 with CreateWindowEx in order to make it not complain. But at least you know you're doing that on purpose. We'll have all that to deal with when the headers are translated :)

The other part of this is the unicode vs ANSI. Windows uses UTF-16 which means that each unicode character consists of 16 bits (a word) except for some special cases which I won't get into. So obviously they're incompatible (believe me, MessageBoxW with ASCII "Hello" gives a couple chinese characters as UTF-16 ;)). In the C headers it has parts that look something like this
#ifdef UNICODE
#define MessageBox MessageBoxW
#else
#define MessageBox MessageBoxA
#endif

which means that if you define UNICODE before including that file, MessageBox will resolve into MessageBoxW, the "wide character" message box, otherwise it will be MessageBoxA, the ASCII/ANSI one.

Aurora doesn't yet support using #define in this way, but it does support the ALIAS keyword. So this for example
declare import, MessageBox alias MessageBoxA(
    ...

will allow you to call MessageBox for one, and be able to easily switch between the unicode and ASCII versions by changing the A to W or vice versa in the declaration. C also has a macro that makes it easy to switch between ASCII and Unicode strings
#ifdef UNICODE
#define _T(x) L##x
#else
#define _T(x) x
#endif

but from what I've heard the compiler will automatically adjust strings to unicode if you define UNICODE (when it's implemented) so that's not a problem.

I realize this is a bit lengthy but I hope it will be a good guide.

Doc

I'm mostly "API illiterate" and that even makes good sense to me.

Thanks for the nice piece of work, Parker.

-Doc-