Welcome!

Join our community of MMORPG enthusiasts and private server developers! By registering, you'll gain access to in-depth discussions on source codes, binaries, and the latest developments in MMORPG server files. Collaborate with like-minded individuals, explore tutorials, and share insights on building and optimizing private servers. Join us today and unlock the full potential of MMORPG server development!

Join Today!

Dll to CreateFont in C++.

Joined
Feb 22, 2008
Messages
2,415
Reaction score
738
Location
Brazil
I'm creating a new DLL to manage fonts as the one created by formav to add new maps.

The thing is:
// QF 1873!
void * ret = (void*)0x70D7E0;
void * Font1 = (void*)0x3103170;
void * Font2 = (void*)0x3103174;
void * Font3 = (void*)0x3103178;


LPCSTR fontName = "Comic Sans MS";

_declspec(dllexport) signed int _cdecl InitializeFont()
{
// 00416774 |. E8 C7D3FFFF CALL 1873a_qu.00413B40


HFONT fonte = ::CreateFont(16,0,0,0,FW_THIN,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,4,FIXED_PITCH+FF_MODERN,fontName);
*(HFONT*) ret = fonte;
return 1;

}
That offset is where I need to set the call to my dll. Ok, that way it works fine.
But the thing, I have another one for create font.

004B86A0 > 56 PUSH ESI
_declspec(dllexport) signed int _cdecl InitializeFonts()
{
HFONT fonte = ::CreateFont(16,0,0,0,FW_THIN,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,4,FIXED_PITCH+FF_MODERN,fontName);
*(HFONT*) Font1 = fonte;
HFONT fonte2 = ::CreateFont(16,0,0,0,FW_THIN,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,4,FIXED_PITCH+FF_MODERN,fontName);
*(HFONT*) Font2 = fonte2;
HFONT fonte3 = ::CreateFont(16,0,0,0,FW_THIN,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,4,FIXED_PITCH+FF_MODERN,fontName);
*(HFONT*) Font3 = fonte3;


return 1;
}
But the thing is:

The calls are made correctly, the first offset calls IntializeFont and the 2nd calls InitializeFonts.

But,even if I'm not calling the 2nd sub, my game crashes. If I comment InitializeFonts the game opens.
Why is that?
With olly, I can see a lot of INT3 instructions that weren't there after I included the second function. This also happens for after the 2nd functions (of dll) starts.

I know this isn't the right place to ask this, but this is related to PT and there are many C++ lovers here.
 
Last edited:
All the code which creates the fonts the game uses is already included. I see no reason to remove it to an external DLL.

I can see why replacing it with functions in international would allow more fonts and different colours in different places... but not just the hFont creation. So I'm going to assume the is the start of something larger.

INT 3 = 00 If I'm not mistaken. It's also the call that launches your debugger. (which is a good thing, and done by design)

I don't understand syntax that uses "= ::" :: is an operator overload, = is an operator... I have no idea how those two would interact, but I'm fairly certain that isn't the right way to use them.

The uses it like this:-
Code:
hFont = CreateFont(36,10,250,0,FW_DONTCARE,FALSE,TRUE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY, VARIABLE_PITCH,TEXT("Arial"));

Additionally, you haven't shown the code which declares, or allocates the memory for the hFont structure that that API creates... are you relying on the game.exe to do that? That can be really dangerous.

Just some thoughts.
 
This is my full code.
// Hook.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"


/*
typedef void (*t_font) (HFONT);

t_font Seta = (t_font)0x70D7E0;
assim com parametros!
*/


void * ret = (void*)0x70D7E0;
void * Font1 = (void*)0x3103170;
void * Font2 = (void*)0x3103174;
void * Font3 = (void*)0x3103178;


LPCSTR fontName = "Comic Sans MS";

_declspec(dllexport) signed int _cdecl InitializeFont()
{
// 00416774 |. E8 C7D3FFFF CALL 1873a_qu.00413B40


HFONT fonte = ::CreateFont(18,0,0,0,FW_THIN,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,4,FIXED_PITCH+FF_MODERN,fontName);
*(HFONT*) ret = fonte;
return 1;

}

/*_declspec(dllexport) signed int _cdecl InitializeFonts()
{
HFONT fonte = ::CreateFont(16,0,0,0,FW_THIN,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,4,FIXED_PITCH+FF_MODERN,fontName);
*(HFONT*) Font1 = fonte;
HFONT fonte2 = ::CreateFont(16,0,0,0,FW_THIN,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,4,FIXED_PITCH+FF_MODERN,fontName);
*(HFONT*) Font2 = fonte2;
HFONT fonte3 = ::CreateFont(16,0,0,0,FW_THIN,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,4,FIXED_PITCH+FF_MODERN,fontName);
*(HFONT*) Font3 = fonte3;


return 1;
}*/

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{


switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:

break;

case DLL_PROCESS_DETACH:

break;
}

return TRUE;
}
Compiled in C++ 6.0.
That way, this DLL works 100% in QF 1873. But, even "uncommenting" the 2nd function, without making any changes in game, causes game to crash, IDK why.
And, with the 2nd func commented, there is no INT3. Game calls directly the PUSB EBP from Hook.InitializeFont.

*I'm doing it just to get experience with C++.*

The :: doesn't make any difference. I think it is some kind of C++ 6.0 syntax. You can use it or not.
 
Last edited:
Oh okay... well Interrupts are illegal outside their use in debugger and kernel mode drivers. You shouldn't use them in an application.

You see them in Olly as padding between routines. It will stop stuff overrunning and causing problems without the application getting shut down.

That's why they usually look greyed out... they shouldn't ever get executed.
 
Err... messing with IATs and EATs is never a simple job. CFF is the easiest and most reliable tool I've ever seen, and it can still take me 3 attempts to get the PE file how I really wanted it at the end.

Sometimes it works first time, and I do a little jig... but not always, and I never expect it to. I never modify the PE structure more than once either... that's why I haven't modified it at all in the butchered releases, so that others can.

It seems the more times you edit and save the less reliable the next edit is.
 
I think my point is that I don't understand what or where your problem is. You don't suddenly get INT 3 instruction appearing in your C++ code that you didn't write. o.O

You have said many things, and I'm not sure which of them is "a problem" and which are by design.

I don't understand why you are trying to wrap a perfectly simple API in a complex set of C++ code (though I'm sure you have your reasons), and I don't know what you are doing to your IATs in order to implement it. It's very hard to link assembler (not Object Oriented) to a C++ dll (which is), unless all external interfaces to the C++ are actually C interfaces... which is what the original API is anyway, and how most of the internal calls inside game.exe are written.

(not all, but most)

C++ looks precarious, but you are looking at it with C# programmers eye, so I understand that.

You function takes no parameters, and always returns 1 (true from Window.h). I don't see the point in that. The assembly routine mov EAX,1 : Ret would do effectively the same job.

HFONT fonte, fonte2, fonte3; is not declared before it is used... which you shouldn't do, but can. Therefore they are never specifically declared any memory space to store the returned HFONT structure, so could do untold damage. (if the compiler allows it they will appear on the heap and get wiped in the next garbage collection run) They are local in scope, and not static so they should be destroyed at the point you return to game.exe... (module scope change should trigger garbage collection) again, I don't see the point.

From my reading, your changes shouldn't achieve anything except wast time, and risk trashing the memory structure. The fact that it does manage to break the game.exe is not surprising, but the why would seem as likely the way you implemented it in the game.exe as what you wrote in C.

Have you tried calling your DLL from a test exe you wrote your self in C / C++ as a test rig?

--- EDIT ---
No, I see now... despite the removal of all indentation by using [QU0TE] tags instead of [C0DE] tags (which doesn't help) you are hoping that *(HFONT*) ret = fonte; will update the pointer in game.exe location 0x70D7E0... but I can't see how it would work like that with that many pointer references.

Hang on. I'll get my C head on:-
Code:
#include <Windows.h>

char[] fontName = "Comic Sans MS";
LPCSTR szFontName = *fontName;

_declspec(dllexport) signed int _cdecl InitializeFont(HFONT FontStruct)
{
// 00416774 |. E8 C7D3FFFF CALL 1873a_qu.00413B40


Retrun (
        FontStruct = CreateFont(18,
                                0,
                                0,
                                0,
                                FW_THIN,
                                FALSE,
                                FALSE,
                                FALSE,
                                DEFAULT_CHARSET,
                                OUT_TT_PRECIS,
                                CLIP_DEFAULT_PRECIS,
                                4,
                                FIXED_PITCH & FF_MODERN,
                                szFontName)
       )
}

BOOL APIENTRY DllMain(HANDLE hModule,
                      DWORD ul_reason_for_call,
                      LPVOID lpReserved)
    {
    switch (ul_reason_for_call){
        case DLL_PROCESS_ATTACH:
            break;
        case DLL_PROCESS_DETACH:
            break;}
    return TRUE;
}
More like that. PUSH the pointer to the Font struct from game.exe then CALL that export.
 
Last edited:
I'm doing it just to learn.

My problem is when I create two exported functions in my dll and try to call them from game.exe.

Game crashes, because:

CALL DllFunction (in game)
If I follow it, I see:

INT3
INT3
INT3
INT3
Real Beggining

BUT, if I remove the 2nd routine, the INT3 are gone, and everything goes fine. More clear now?
 
Not really. The INT 3 is in disassembly of your compiled DLL?

If so, it is to ALIGN the next routine to a DWord boundary (faster CALL operation) as I said earlier.

Some C compilers pad with NOP, some with random INTerrupt that will crash if you call it, some with those weird MOV AL,AL type instructions that do nothing.
 
Don't, it ain't broke. That is exactly as it should be, if you fix then worse things will happen. XD

actually... depending on your compiler version, you may be able to use compiler options to sacrifice speed for size by setting alignment of functions and data to "none" instead of "4" or "DWord" or how-ever your particular compiler terms it... not all the VC Express versions allow this, but MS C underneath does, and the paid for versions always do.

It's not a compromise you should really be considering seriously though.
 
Last edited:
There isn't really any such thing as .net C++, that's just a marketing gimmick. It's Visual C++ 7 (from VS 2003) that MS called .Net because they where calling everything .Net then, like Apple would probably have renamed their entire company iApple a few years back if it weren't so expensive. XD

Before anyone says anything:-
Noting for or against MS or Apple. Everything against marketing boys that create stupid terms that make an engineers job harder to communicate. Is it COM, COM+, DCOM, AcitveX? Is there really a difference, or should they just have a different version number... I think DirectX 10 is more alien to DirectX 3 than DCOM is to ActiveX, and GDI+_is nothing like GDI... how are we supposed to make sense of these terms?
If you are using VC++ later than Version 6, then it is capable of building CLR assemblies that can be linked to the .Net framework. But wouldn't advise doing that as a matter of habit. That's really for very specialised instances. (and I suspect to quell the initial outrage from existing developers)

Anyway... it's not worth using, if you want .Net you should sacrifice x86 / x64 / ARM / ai64 and go with MSIL or you are wasting a perfectly good resource. So you may as well write C#, VB.net or J#.

The null operations in between exports should not pose any problems for you at all... unless you are making some dire mistake at the point of linking. (either via IAT or LoadLibrary())

Write that test-bed exe to call your DLL routines, and see how it does it... this may give you incite into what you are doing wrong when you try to call it from game.exe, or point out a very real flaw in your C++.
PE Explorer seeing ALIGNmnet, next to Olly seeing the true nonsense that pads between functions. (in grey)
SheenBR - Dll to CreateFont in C++. - RaGEZONE Forums
P.S. The Debug routine is disabled via conditional compile, because this is the release build of IntStr.dll... I leave the export in there, because I call it from Inetnational.dll, which doesn't know if you are debugging or not. The code is a stack context change and return to normal stack frame before return... nothing else.

If GAS aligned the way your compiler is, the NOP, and pointless LEA ESI,[ESI] would all be filled with INT 3. It doesn't matter, it should never get executed.
 
Last edited:
Back