Hello folks :)

Allow me to introduce myself. I am Haktivex, a programmer for a tool known as TibiCAM, used to record movies for an online game known as Tibia.

Now heres the issue. For a long time we supported all operating systems, Windows 98, ME, etc. However recently these operating systems have stopped working. Some things to note:

1. We switched compilers (Microsoft Visual C++ Express) - Originally was compiled on Visual C++ 6.0

2. Compiling on Visual C++ 2003 did not help either.

3. None of the FindWindow code was changed.

4. Works fine on XP, etc.

When running on Windows 98/ME, instead of FindWindow finding the Tibia client, instead it finds DLL files, usually something like directx files, and some people have reported it finding Gadu-Gadu (IM program) files.

I have considered that the issue could be caused by ansi/unicode but I have no grounds to confirm this consideration. It could also be the compilers. Would anybody suggest that the Visual C++ 6.0 be used? Or is there something we can change with our current compilers/IDE's to get support back?

Here is the single line of code that is giving us so much trouble:

HWND hTemp = FindWindow("tibiaclient", NULL);

Thanks alot,
Haktivex.

Dani AI

Generated

Short version: the bug turned out to be the module-enumeration logic, not FindWindow or Unicode. On Win98/ME your code was taking the first MODULEENTRY32 returned and copying szExePath — on older systems the module list order is not guaranteed, so that “first” entry can be a DLL (DirectX, etc.) and not the main EXE. That explains why XP behaved and 98/ME did not. See the Module32First/PROCESSENTRY32 docs for how these snapshots work. (learn.microsoft.com)

Fix outline (robust across Win9x and NT):

  • Get PID from the HWND with GetWindowThreadProcessId.
  • Take a process snapshot (TH32CS_SNAPPROCESS) and read PROCESSENTRY32.szExeFile to learn the process executable name.
  • Take a module snapshot for that PID (TH32CS_SNAPMODULE) and iterate Module32First/Module32Next until you find the module whose szModule matches the exe filename (case-insensitive). Use that module’s szExePath as the full path. Initialize dwSize before calls and check return values. The MSDN docs show these functions and the recommended usage. (learn.microsoft.com)

Troubleshooting notes:

  • Toolhelp snapshots can fail or return inconsistent results if the target’s loader data isn’t ready; check errors (e.g. ERROR_BAD_LENGTH / ERROR_PARTIAL_COPY) and retry briefly. For NT-based systems you can also use PSAPI/QueryFullProcessImageName or GetModuleFileNameEx as a more direct alternative when available. See the CreateToolhelp32Snapshot and PSAPI docs for details and caveats. (learn.microsoft.com)

Tiebacks: ’s Unicode tip is fine for portability but wouldn’t explain the wrong path; ’s snapshot idea is on the right track — combine the process snapshot step with a module loop as described above.

Recommended Answers

All 5 Replies

I don't know why these errors occur, but you might want to try creating processsnapshots to find the handles.

This way is a bit harder, and it's much more code, but it might just work, right?


Greetz, Eddy

I don't know why these errors occur, but you might want to try creating processsnapshots to find the handles.

This way is a bit harder, and it's much more code, but it might just work, right?


Greetz, Eddy

Hello,

Process Snapshots require (as far as I am concerned) the process id of an application, which can be found using FindWindow - which is causing us these troubles.

Regards,
Haktivex.

// snapshot.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <Tlhelp32.h>

using namespace std;


int main(int argc, char* argv[])
{
	DWORD tibiaID;
	HANDLE hProcessSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0);
	if(hProcessSnapshot == INVALID_HANDLE_VALUE)
	{
		cout << "invalid snapshot handle" << endl;
	}

	PROCESSENTRY32 ProcessStruct;

	ProcessStruct.dwSize = sizeof(PROCESSENTRY32);

	Process32First(hProcessSnapshot, &ProcessStruct);

	if(strcmp(ProcessStruct.szExeFile, "tibia.exe") == 0) 
	{ 
	   //you have the right process.
		tibiaID = ProcessStruct.th32ProcessID;
	} 
	else 
	{ 
	   // tibia.exe is not the first process
		//looping through the other records
		while(Process32Next(hProcessSnapshot, &ProcessStruct))
		{			
			if(strcmp(ProcessStruct.szExeFile, "tibia.exe") == 0) 
			{
				//the right record has been found
				tibiaID = ProcessStruct.th32ProcessID;
				break;
			}
		}
         
	}
	cout << tibiaID;
	return 0;
}

retreives the processID of tibia.exe. You can also compare to the module name of tibia.exe.

Creating a handle from the ID is something you already know, so that won't be a problem.

Yours,
Eddy

> HWND hTemp = FindWindow("tibiaclient", NULL);
The newer compilers use UNICODE by default.

I think you can either turn this off.

Or prepare your code for the future by writing
HWND hTemp = FindWindow( _TEXT("tibiaclient"), NULL);

http://www.i18nguy.com/unicode/c-unicode.html

Thanks for your reply Salem.

Unfortunately, I have just realized that I was looking after the wrong problem all along. FindWindow is doing it's job correctly, it is the next few lines causing the problem.

// Now get the ProcessID, so we can get a snapshot and open the process.
    GetWindowThreadProcessId(hTemp, &lTibiaProcessID);
    
    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, lTibiaProcessID);
    Module32First(hSnapshot, modA);
    strcpy(szTibiaPath, modA->szExePath);

Under Windows NT/XP/ etc this works just fine and dandy, and returns the path correctly. However, under Windows 98/ME etc, this returns some file not relevant to what we are searching for. The FindWindow procedure as originally thought to be the problem is not.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.