# Forum > World of Warcraft > World of Warcraft Bots and Programs > WoW Memory Editing >  GetLocalizedText and C++

## jockel

Heya guys,

I'm currently doing some playing around with my C++ library.

I'm using a function pointer to execute Lua_DoString when Wow's EndScene is called.

Now I want to get the return values via the GetLocalizedText function.

Here is what I use for the typdef function pointer:


```
typedef unsigned int (__cdecl * tLuaGetText)(int unkn1, char * luaVar);
tLuaGetText getText = (tLuaGetText)0x005A8500;
```

Now I'm going to execute this piece of code:

doString("test = GetRealZoneText();");
unsigned int a = getText(-1, "test");

The DoString is correctly executed (tried it with CastSpellByName), but the getText part crashs my Wow.

Any ideas on this guys?

Thanks

----------


## SKU

```
0055E046                |.  6A FF             PUSH -1                                                          ; /Arg2 = FFFFFFFF
0055E048                |.  8D55 E0           LEA EDX,[LOCAL.8]                                                ; |
0055E04B                |.  52                PUSH EDX                                                         ; |Arg1 = 7C91E514
0055E04C                |.  8BCE              MOV ECX,ESI                                                      ; |
0055E04E                |.  E8 ADA40400       CALL Wow.005A8500                                                ; \Wow.005A8500
```




```
005A8500                /$  55                PUSH EBP
005A8501                |.  8BEC              MOV EBP,ESP
005A8503                |.  53                PUSH EBX
005A8504                |.  56                PUSH ESI
005A8505                |.  8BF1              MOV ESI,ECX
005A8507                |.  8B46 08           MOV EAX,DWORD PTR DS:[ESI+8]
005A850A                |.  8B58 04           MOV EBX,DWORD PTR DS:[EAX+4]
005A850D                |.  57                PUSH EDI                                                         ;  ntdll.7C920228
005A850E                |.  8B38              MOV EDI,DWORD PTR DS:[EAX]
005A8510                |.  E8 CB3F2100       CALL Wow.007BC4E0
005A8515                |.  3BF8              CMP EDI,EAX
005A8517                |.  75 10             JNZ SHORT Wow.005A8529
005A8519                |.  3BDA              CMP EBX,EDX                                                      ;  ntdll.KiFastSystemCallRet
005A851B                |.  75 0C             JNZ SHORT Wow.005A8529
005A851D                |.  8B86 D00F0000     MOV EAX,DWORD PTR DS:[ESI+FD0]
005A8523                |.  0FB640 1C         MOVZX EAX,BYTE PTR DS:[EAX+1C]
005A8527                |.  EB 0A             JMP SHORT Wow.005A8533
005A8529                |>  8B8E D0000000     MOV ECX,DWORD PTR DS:[ESI+D0]
005A852F                |.  0FB641 42         MOVZX EAX,BYTE PTR DS:[ECX+42]
005A8533                |>  5F                POP EDI                                                          ;  kernel32.7C817077
005A8534                |.  5E                POP ESI                                                          ;  kernel32.7C817077
005A8535                |.  83E8 01           SUB EAX,1
005A8538                |.  5B                POP EBX                                                          ;  kernel32.7C817077
005A8539                |.  B8 02000000       MOV EAX,2
005A853E                |.  75 05             JNZ SHORT Wow.005A8545
005A8540                |.  B8 03000000       MOV EAX,3
005A8545                |>  8B55 0C           MOV EDX,[ARG.2]
005A8548                |.  50                PUSH EAX                                                         ; /Arg3 = 00000000
005A8549                |.  8B45 08           MOV EAX,[ARG.1]                                                  ; |Wow.<ModuleEntryPoint>
005A854C                |.  52                PUSH EDX                                                         ; |Arg2 = 7C91E514
005A854D                |.  50                PUSH EAX                                                         ; |Arg1 = 00000000
005A854E                |.  E8 1D2CEFFF       CALL Wow.0049B170                                                ; \Wow.0049B170
005A8553                |.  83C4 0C           ADD ESP,0C
005A8556                |.  5D                POP EBP                                                          ;  kernel32.7C817077
005A8557                \.  C2 0800           RETN 8
```

Looks like a __thiscall (definitively not a __cdecl), and you're pushing the arguments in the wrong order.

----------


## jockel

Thanks for the fast response,

Using __thiscall won't crash my Wow anymore,
so the right order of the arguments should be:



```
typedef unsigned int (__thiscall * tLuaGetText)( char * luaVar, int unkn1);
tLuaGetText getText = (tLuaGetText)0x005A8500;
```




```
0055E04C                |.  8BCE              MOV ECX,ESI
```

This means that the playerbase is moved into ecx right?

Doesn't the function call automatically do this for me, or do I have to manually manage this with inline asm.

----------


## Cypher

"Doesn't the function call automatically do this for me, or do I have to manually manage this with inline asm."
Think about that for a few minutes, then kick yourself for asking such a stupid question.

Also, that typedef you pasted above shouldn't even work. I'm almost certain that's not valid C++. You can't declare a function explicitly as __thiscall using the '__thiscall' keyword, you have to declare the function as a member of a class and let it use __thiscall implicitly.

This is legal and should work though I think:
typedef void (SomeClass::* tFoo)();

----------


## wraithZX

__thiscall just tells the compiler that the first argument is the this argument.
(Actually it fudges the first argument to be placed in ecx - the same place that 'this' normally would be.)

So:



```
typedef int (__thiscall *pFunc)(void *p, int arg);
```

is valid for


```
struct P
{
   int Func(int arg);
};
```

i.e.


```
pFunc Func = P::Func; // yeah yeah I know, not valid, work with me here
P p;
Func(p, 5);
p.Func(5);
```

----------


## Cypher

> __thiscall just tells the compiler that the first argument is the this argument.
> (Actually it fudges the first argument to be placed in ecx - the same place that 'this' normally would be.)
> 
> So:
> 
> 
> 
> ```
> typedef int (__thiscall *pFunc)(void *p, int arg);
> ...


What you've done there is totally different to what I meant was invalid, but it seems I was mistaken. This does actually compile:
typedef void (__thiscall* tFoobar)(UINT This);
tFoobar oFoobar = reinterpret_cast<tFoobar>(0xDEADBEEF);
oFoobar(1); 

EDIT:
Though, you'd want to be careful. Compilers implement the C++ member function calling convention differently, so whilst that may work with MSVC, if you compile it with GCC it may fail. You're probably better off manually moving 'this' into ECX.

EDIT2:
Pretty sure most major compilers have it. But its also worth noting __thiscall is a nonstandard language extension.

----------


## wraithZX

Yep. Assuming your 'this' pointer sits at 0x00000001  :Wink:

----------


## jockel

Hum, thanks for the answers guys, I did some testing around for the last hours, but I'm not able to get it working.

According to cyphers last post I tried:



> typedef int (__thiscall* tLuaGetText)(char * a, int b);
> tLuaGetText getText = reinterpret_cast<tLuaGetText>(0x005A8500);


Which crashes my Wow with a read error at the GetText offset.


So I tried what Cypher was first posting with the implizit declaration of the function:




> struct sLuaHelper {
> int __thiscall tLuaGetText(char * luaVar, int unkn1); 
> };
> 
> typedef int (sLuaHelper:: * tLuaGetText)(char * a, int b);
> 
> tLuaGetText getText = (tLuaGetText)0x005A8500;


The compiler gives me in the red markes line an error that he can't convert "tLuaGetText " to int.
I can't get the function build together correctly, can you give me a hint on this?

----------


## SKU

Cypher: Close your eyes now.



```
#include <Windows.h>
#include <string>
#include <boost/format.hpp>

// GetText
typedef char* (__thiscall * tGetText)(void* pThis, char* sText, DWORD_PTR unk1);
tGetText oGetText = reinterpret_cast<tGetText>(0x005A8500);

// DoString
typedef void (__cdecl * tDoString)(const char* sCommand1,const char* sCommand2, void* pState /*  = null */);
tDoString oDoString = reinterpret_cast<tDoString>(0x0049AB60);

// startup routine
void start()
{
	// fugly. 0 pointer checks anyone? Get the local player..
	DWORD_PTR dwLocalPlayer = *reinterpret_cast<DWORD_PTR*>(*reinterpret_cast<DWORD_PTR*>(*reinterpret_cast<DWORD_PTR*>(0x10BD5F4) + 0x34) + 0x24);
	// call dostring with random crap
	oDoString("sText = GetMinimapZoneText();", "sText = GetMinimapZoneText();", NULL);
	// get text
	std::string sResult(oGetText(reinterpret_cast<void*>(dwLocalPlayer), "sText", -1));
	// show the result
	MessageBoxA(NULL, sResult.c_str(), "ZOMG", MB_OK);
}

// dll entry point
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
	if (dwReason == DLL_PROCESS_ATTACH)
		CreateThread(0, 0, (LPTHREAD_START_ROUTINE)start, 0, 0, 0);

	return TRUE;
}
```

----------


## Cypher

Don't do this:
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)start, 0, 0, 0);

It's evil and will potentially crash randomly on x64. Plus, it ****s with anything that relies on TLS.

First off, don't use CreateThread, use beginthreadex. Second, match the ThreadProc prototype correctly and pass in the pointer like this:
Foo(&Start);

----------


## SKU

Will do in the future, thanks.  :Smile:

----------


## jockel

Thanks for the bunch of information.

So since GetLocalizedText needs the playerbase as an argument, I assume that this function doesn't work before we are ingame, is this right?

----------


## namreeb

> Don't do this:
> CreateThread(0, 0, (LPTHREAD_START_ROUTINE)start, 0, 0, 0);
> 
> It's evil and will potentially crash randomly on x64. Plus, it ****s with anything that relies on TLS.
> 
> First off, don't use CreateThread, use beginthreadex. Second, match the ThreadProc prototype correctly and pass in the pointer like this:
> Foo(&Start);


Meaning compiled as x64 or just running on an x64 system?

----------


## lanman92

Just running on an x64 will have the possibility to crash. I know from experience... Sigh. It's not hard, just change your proto.

----------


## flo8464

Sorry for digging out this old thread. 

I tried to use dostring/gettext but had problems doing it. 

C&Ped SKUs code and got a valid result. 

I was confused and tried "sText = GetMinimapZoneText();" with my code and it worked. 

So my code has to be valid, there is a problem with the lua-code I supply to my function. 




> "count = GetItemCount(6256);"


Why does this always return 0? 
If I type it ingame as "/script ..." it returns the correct value, 1. 

Or should I call GetItemCount() directly ? I hope not, using 2 functions for everything sounds much more comfortable.

----------


## Shynd

Name your variables something unique; how many variables named 'count' do you think are referenced in all of the Blizzard UI and other AddOns you have installed and why do you think that GetLocalizedText("count") is going to return YOUR count instead of one of the dozens of others that are probably being used?

----------


## flo8464

> Name your variables something unique; how many variables named 'count' do you think are referenced in all of the Blizzard UI and other AddOns you have installed and why do you think that GetLocalizedText("count") is going to return YOUR count instead of one of the dozens of others that are probably being used?


Thanks for your reply.

Well...

1.) Tried it with iiitemcccounttt as varname .. .doesn't work, too.
2.) Like I said, ingame as 

/script count = GetItemCount(6256)
/script print(count);

It works :/

----------


## flo8464

Apologize for Double-posting.

Anyone got an idea?

----------


## lanman92

You could write a stub function that returns the address of the string and just call that. You'd have to register a lua function though(patch the protection check). This is probably similar to what GetLocalizedText does but w/e. Actually, you could just have an injected function that doesn't have to be registered that just pops a var off the lua stack and returns it.

----------


## flo8464

> You could write a stub function that returns the address of the string and just call that. You'd have to register a lua function though(patch the protection check). This is probably similar to what GetLocalizedText does but w/e. Actually, you could just have an injected function that doesn't have to be registered that just pops a var off the lua stack and returns it.


Well, GetLocalisedText works fine. 
The problem is using lua-functions with arguments with DoString.
I really don't know why they fail..well, print() works for some reasons.

----------


## Cypher

> Well, GetLocalisedText works fine. 
> The problem is using lua-functions with arguments with DoString.
> I really don't know why they fail..well, print() works for some reasons.



Just because your post is a tad unclear and I don't want people to be confused.

Lua functions with arguments work fine with DoString. Your code is screwed.

----------


## flo8464

Much to screw? 



```
typedef void  (__cdecl *DoLuaStringPtr)(const char* lString,const char* lString2, void* luastate);
DoLuaStringPtr	 DoLuaString = reinterpret_cast<DoLuaStringPtr>(0x49AAB0);

DoLuaString("print(GetItemCount(6256))", "print(GetItemCount(6256))", NULL);
```

----------


## ramey

I have zero problems using DoString.

----------


## flo8464

> I have zero problems using DoString.


You are doing it like me ?

----------


## ramey

> You are doing it like me ?


I used to, but at the moment I am creating my own DoString macro

edit: For some functions are you just not escaping your quotes? :|

----------


## flo8464

> I used to, but at the moment I am creating my own DoString macro
> 
> edit: For some functions are you just not escaping your quotes? :|


Where should I escape quotes if the only ones I use are those to tell the compiler its a string ?
And I don't get what you mean when you say you create your own macro? There is nothing more comfortable than a function pointer...

----------


## ramey

> Where should I escape quotes if the only ones I use are those to tell the compiler its a string ?
> And I don't get what you mean when you say you create your own macro? There is nothing more comfortable than a function pointer...


For example DoString("message(\"lol\")", "message(\"lol\")", NULL);

...

Lua_DoString is a macro itself in lua, you might want to have a look at the lua source sometime. It is a macro of a few functions, but I create my own macro.

----------


## flo8464

> For example DoString("message(\"lol\")", "message(\"lol\")", NULL);
> 
> ...
> 
> Lua_DoString is a macro itself in lua, you might want to have a look at the lua source sometime. It is a macro of a few functions, but I create my own macro.



I know how its implemented in Lua (Combining loadstring and pcall) , using lua for my scripting in c++ applications for 1 year now  :Wink: 

Back to topic: Did you use DoString() like I posted here or different? I really cant figure out whats wrong ...

----------


## ramey

I have used it like that before. What exactly is the problem?

----------


## flo8464

> I have used it like that before. What exactly is the problem?


GetItemCount(6256) returns zero if used by DoString() --> wrong
GetItemCount(6256) returns one if used as "\script xxx" in WoW-chatbox --> correct

I also can't use all other Lua-Functions with aguments ...except print().

That doesn't make sense to me.

----------


## ramey

Only thing I can recommend is not using GetLocalizedText, since it sucks.  :Smile:

----------


## flo8464

> Only thing I can recommend is not using GetLocalizedText, since it sucks.


I don't even use it at the moment :/

And GetText returns the correct value if I execute the Lua-command in WoW-Chatbox..

----------

