Okay, I don't know how useful this will be, but I've actually written something I think might be worth sharing. :) So here it is, my desperate attempt To Be Not Useless here on the forum: :grin:

Modified TextOut Tutorial: TextOut.zip (~5,900 bytes)

The MFC CFont class has a method called "CreatePointFont" that takes a font name and a point size and handles all the ickiness of translating from points to logical to device coordinates. I have ported this code to assembler. Creating fonts is now as easy as picking a font name and point size.

Of course, I'm still so new at this that the only way to get it is to copy the tutorial program I modified and extract the code... it's not really big enough yet to merit its own library. Though it could be the *start* of one. How would I create a .inc/.lib pair out of this?



Anyway, give it a whirl, and let me know what you think. If you change FontName and/or FontSize in the .data section, it will change the font accordingly. Also note that I play around with the font color and background color, search for the two RGB macro calls to change those if you don't like Cyan on Dark Grey.

Cheers!

-Chalain
Posted on 2002-04-25 14:33:39 by Chalain
hi
the example works well. but
CreateFontIndirect - you should use DeleteObject when you no longer need it .
the same for GetDC , when you no longer need it use ReleaseDC
otherwise you will get some memory leaks :(


bye

eko
Posted on 2002-04-25 17:02:35 by eko

hi
the example works well. but
CreateFontIndirect - you should use DeleteObject when you no longer need it .
the same for GetDC , when you no longer need it use ReleaseDC
otherwise you will get some memory leaks :(


DOH! Thank you, you are correct. I assumed (incorrectly) that since the screen DC was a common device context I didn't need to release it.

I have modified CreatePointFontIndirect to release the DC if (and only if) it had to create the DC with GetDC(NULL). (It would be bad to release the caller's DC for them. :grin: )

As always with assembler, making this change immediately put me out of my depth. All of my error tests can no longer simply check for an error, push the error code and ret... they also have to check to see if we created our own DC and release it.

Here's what I did:


    [*] Created a "clean up" section labeled "AllDone:" at the end of the proc
    [*] Changed the error ret's to jmp AllDone's
    [*] Coded AllDone to do nothing if we didn't create the DC, otherwise push the HFONT return value, invoke ReleaseDC, and pop eax


    Does that sound about right? Here's the error test and AllDone section, comments are certainly welcome:

        invoke GetDeviceCaps, hdc, LOGPIXELSY
    
    test eax,eax
    jnz @F
    invoke StdOut, addr ErrGetDeviceCaps
    jmp AllDone
    @@:

    ; [SNIP: Rest of function]

    AllDone:
    cmp hadToGetCommonDC, 0
    jz @F
    push eax ; preserve return value before DC cleanup
    invoke ReleaseDC, NULL, hdc
    pop eax ; restore HFONT
    @@:
    ret ; HFONT (or NULL) is in eax
    CreatePointFontIndirect endp


    Heh, I just realized that in the tutorial sample, I *still* forgot to call DeleteObject on the HFONT. However, that's the caller's responsibility, and is a defect in my example code, not my "library function" :grin: (I'll go fix it in a minute).

    Cheers,

    -Chalain
Posted on 2002-04-25 17:37:55 by Chalain
Fixed the sample code. It now invokes DeleteObject, hFont before ret-ing from WinMain. This time I just went for the quick-n-dirty "invoke DeleteObject, hFont" right before each ret, rather than doing a jmp to a cleanup section.

Cheers,

-Chalain
Posted on 2002-04-25 17:43:07 by Chalain
The 'AllDone:' solution you made is the way a conservative programmer would do it.

The 'dirty' method is justifiable only if the cleanup is very simple, such as a single API call.

So basically, you're right on track. Good job!
Posted on 2002-04-25 17:54:06 by AmkG