#include <windows.h>
#include <psapi.h>
#include <stdio.h>

BOOL WINAPI DebugActiveProcessStop(DWORD dwProcessId);

DWORD LMRomTitleAddress;

DWORD * FindKnownString(HANDLE process, PCCHAR data, DWORD datalen)
{
	static PCHAR scanbuf=NULL;
	if (!scanbuf) scanbuf=malloc(1024*1024);
	
	int answerslen=4;
	DWORD * answers=malloc(sizeof(DWORD)*answerslen);
	int numanswers=0;
	
	MEMORY_BASIC_INFORMATION meminf;
	VirtualQueryEx(process, NULL, &meminf, sizeof(meminf));
	do
	{
		if (meminf.Protect&PAGE_READWRITE)
		{
			if (meminf.RegionSize>1024*1024) meminf.RegionSize=1024*1024;
			ReadProcessMemory(process, meminf.BaseAddress, scanbuf, meminf.RegionSize, NULL);
			
			for (DWORD i=0;i<meminf.RegionSize-datalen;i++)
			{
				if (scanbuf[i]==data[0] && !memcmp(scanbuf+i, data, datalen))
				{
					answers[numanswers]=(DWORD)meminf.BaseAddress+i;
printf("[%i]=%lu\n",numanswers,answers[numanswers]);
					numanswers++;
					if (numanswers==answerslen)
					{
						answerslen*=2;
						answers=realloc(answers, sizeof(DWORD)*answerslen);
					}
				}
			}
		}
	} while (VirtualQueryEx(process, meminf.BaseAddress+meminf.RegionSize, &meminf, sizeof(meminf)));
	
	answers[numanswers]=0;
	return answers;
}

#define IMPOSSIBLE "thisfilecannotpossiblyexist<\\\\\\>.smc"
DWORD * FindRomNameCandidates(LPCSTR path)
{
	STARTUPINFO stinf;
	PROCESS_INFORMATION prinf;
	memset(&stinf, 0, sizeof(stinf));
	stinf.cb=sizeof(stinf);
	//stinf.wShowWindow=SW_HIDE;
	//stinf.dwFlags=STARTF_USESHOWWINDOW;
	CreateProcess(path, "lm "IMPOSSIBLE, NULL, NULL, FALSE, 0/*DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS*/, NULL, NULL, &stinf, &prinf);
	
	Sleep(500);//couldn't get debugging working, MessageBoxA seems to move around in dumb ways. Let's just show message boxes.
	DWORD * ret=FindKnownString(prinf.hProcess, IMPOSSIBLE, strlen(IMPOSSIBLE));
	
/*
	void* mbptr=GetProcAddress(GetModuleHandle("user32.dll"), "MessageBoxA");
//((int(WINAPI*)(HWND,LPCSTR,LPCSTR,UINT))mbptr)(NULL, "A", "A", 0);
	while (1)
	{
		DEBUG_EVENT event;
		WaitForDebugEvent(&event, INFINITE);
		
		if (event.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT)
		{
printf("mb=%p\n",mbptr);
			unsigned char bp=0xCC;
			WriteProcessMemory(prinf.hProcess, (void*)mbptr, (void*)&bp, 1, NULL);
			
unsigned char cow[256];
ReadProcessMemory(prinf.hProcess, (void*)mbptr, cow, 256, NULL);
unsigned char*p=mbptr;
for(int i=0;i<64;i++){printf("%.2X%.2X    ",cow[i],p[i]);}
			
			ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
			continue;
		}
		
		if (event.dwDebugEventCode==EXCEPTION_DEBUG_EVENT)
		{
			if (event.u.Exception.ExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT)
			{
				if (event.u.Exception.ExceptionRecord.ExceptionAddress==mbptr)
				{
puts("OK");
					ret=FindKnownString(prinf.hProcess, IMPOSSIBLE, strlen(IMPOSSIBLE));
					break;
				}
				else
				{
printf("BADPTR=%p\n",event.u.Exception.ExceptionRecord.ExceptionAddress);
					ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
					continue;
				}
			}
			
			ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
			continue;
		}
		
		ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
	}
	
	DebugActiveProcessStop(prinf.dwProcessId);
*/
	
	TerminateProcess(prinf.hProcess, 0);
	CloseHandle(prinf.hProcess);
	CloseHandle(prinf.hThread);
	return ret;
}
#undef IMPOSSIBLE

DWORD FindRomName(HANDLE randomLM)
{
	char path[MAX_PATH];
	GetModuleFileNameEx(randomLM, NULL, path, MAX_PATH);
	
	DWORD* candidates=FindRomNameCandidates(path);
	int numcandidates;
	for (numcandidates=0;candidates[numcandidates];numcandidates++) {}
	
	if (!numcandidates)
	{
		free(candidates);
		return 0;
	}
printf("CAN=%i\n",numcandidates);
	
	int iter=0;
	while (candidates[1] && iter<10)
	{
		DWORD* candidates2=FindRomNameCandidates(path);
		int pos1=0;
		int pos2=0;
		while (candidates[pos2])
		{
printf("[%i]=%p, [%i]=%p | \n", pos1,candidates[pos1],pos2,candidates2[pos2]);
			if (candidates[pos1]<candidates2[pos2])
			{
				memmove(candidates+pos1, candidates+pos1+1, (numcandidates-pos1)*sizeof(DWORD));
				numcandidates--;
printf("can=%lu\n",numcandidates);
			}
			if (candidates[pos1]==candidates2[pos2])
			{
				pos1++;
				pos2++;
			}
			if (candidates[pos1]>candidates2[pos2])
			{
				pos2++;
			}
		}
		if (candidates[pos1])
		{
			candidates[pos1]=0;
			numcandidates=pos1;
		}
		iter++;
	}
	
	DWORD ret=candidates[0];
	free(candidates);
	if (!numcandidates) return 0;
	return ret;
}

void MessUpLM(HWND hwnd)
{
	DWORD pid;
	GetWindowThreadProcessId(hwnd, &pid);
	HANDLE process=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_READ, FALSE, pid);
	
	if (!LMRomTitleAddress) LMRomTitleAddress=FindRomName(process);
	
	char romtitle[MAX_PATH+40];
	ReadProcessMemory(process, (void*)LMRomTitleAddress, romtitle, MAX_PATH, NULL);
	strcat(romtitle, " - Lunar Magic");
	SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)romtitle);
	printf("GOTIT=%p\n", LMRomTitleAddress);
}

BOOL CALLBACK ListWindows(HWND hwnd, LPARAM ignored)
{
	char cl[256];
	GetClassName(hwnd, cl, 256);
	if (!strcmp(cl, "LMFrame")) MessUpLM(hwnd);
	return TRUE;
}

int main()
{
	LMRomTitleAddress=0;
	//SetWindowsHookEx ShellProc
	EnumWindows(ListWindows, 0);
}
