Build JUCE application on Windows 95

If you are writing a JUCE program, and want it can run on all 32bit Windows system, then Windows 95 maybe a bar. So, I present a header file here for solving this problem. At the beginning of this file, there is the usage. All code is here, enjoy. Sorry for my poor English.

[code]
/*

This file is an extension for JUCE library - "Jules’ Utility Class Extensions"
Copyright 2006 by Dandy Cheung.


If you want to run your JUCE application on Windows 9x series, then this file
is for you.

You should do these steps:

  1. place this file into the juce\build\win32\platform_specific_code directory

  2. change the files:
    juce_win32_SystemStats.cpp,
    juce_win32_Windowing.cpp,
    juce_win32_Files.cpp,
    all of them is under juce\build\win32\platform_specific_code directory.

    Just add one line:
    #include “win32_win9x.h”

  3. open this file:
    juce\src\juce_appframework\gui\graphics\contexts\juce_LowLevelGraphicsSoftwareRenderer.cpp
    replace the statement “prefetchnta [edx]” with the following code segment:

#if _MSC_VER > 1200 // vc6 = 1200, vc7 = 1300, vc7.1 = 1310, vc8 = 1400
prefetchnta [edx]
#else
_emit 0fh
_emit 18h
_emit 02h
#endif

4. compile JUCE with VC6.

The step 3 is needed because the assembler of VC6 did not recognize the
"prefetchnta" instruction.

You MUST compile your project with VC6, otherwise, your application can not
run on Windows 9x, because that a function named "IsDebuggerPresent" was used
by VC6+ CRT library, but that API was absent in Windows 95.

Remember:
1. If you want to use socket functionality on Windows 95, you should install
   W95ws2setup.exe package:
   http://download.microsoft.com/download/0/e/0/0e05231b-6bd1-4def-a216-c656fbd22b4e/W95ws2setup.exe
2. If you want to use SHGetSpecialFolderPath()/SHGetFolderPath() API, you should
   install shfinst.exe package:
   http://download.microsoft.com/download/platformsdk/Redist/5.50.4027.300/W9XNT4/EN-US/shfinst.EXE

If you have any comment or want to report a bug, contact dandycheung@21cn.com.

==============================================================================
*/

#ifndef WIN32_WIN9X_H
#define WIN32_WIN9X_H

// Kernel32.dll
typedef BOOL (WINAPI *fnIsDebuggerPresent)(void);
typedef BOOL (WINAPI *fnIsProcessorFeaturePresent)(DWORD ProcessorFeature);
typedef BOOL (WINAPI *fnSetProcessAffinityMask)(HANDLE hProcess, DWORD_PTR dwProcessAffinityMask);

// User32.dll
typedef BOOL (WINAPI *fnGetWindowInfo)(HWND hwnd, PWINDOWINFO pwi);

// Our proxy functions
__inline BOOL WINAPI _IsDebuggerPresent(void)
{
static fnIsDebuggerPresent __IsDebuggerPresent = (fnIsDebuggerPresent)1;
if(__IsDebuggerPresent == (fnIsDebuggerPresent)1)
__IsDebuggerPresent = (fnIsDebuggerPresent)GetProcAddress(GetModuleHandle(TEXT(“kernel32.dll”)), “IsDebuggerPresent”);

if(__IsDebuggerPresent)
	return __IsDebuggerPresent();

return FALSE;

}

__inline BOOL WINAPI _IsProcessorFeaturePresent(DWORD ProcessorFeature)
{
static fnIsProcessorFeaturePresent __IsProcessorFeaturePresent = (fnIsProcessorFeaturePresent)1;
if(__IsProcessorFeaturePresent == (fnIsProcessorFeaturePresent)1)
__IsProcessorFeaturePresent = (fnIsProcessorFeaturePresent)GetProcAddress(GetModuleHandle(TEXT(“kernel32.dll”)), “IsProcessorFeaturePresent”);

if(__IsProcessorFeaturePresent)
	return __IsProcessorFeaturePresent(ProcessorFeature);

return FALSE;

}

__inline BOOL WINAPI _SetProcessAffinityMask(HANDLE hProcess, DWORD_PTR dwProcessAffinityMask)
{
static fnSetProcessAffinityMask __SetProcessAffinityMask = (fnSetProcessAffinityMask)1;
if(__SetProcessAffinityMask == (fnSetProcessAffinityMask)1)
__SetProcessAffinityMask = (fnSetProcessAffinityMask)GetProcAddress(GetModuleHandle(TEXT(“kernel32.dll”)), “SetProcessAffinityMask”);

if(__SetProcessAffinityMask)
	return __SetProcessAffinityMask(hProcess, dwProcessAffinityMask);

return FALSE;

}

__inline BOOL WINAPI _GetWindowInfo(HWND hwnd, PWINDOWINFO pwi)
{
static fnGetWindowInfo __GetWindowInfo = (fnGetWindowInfo)1;
if(__GetWindowInfo == (fnGetWindowInfo)1)
__GetWindowInfo = (fnGetWindowInfo)GetProcAddress(GetModuleHandle(TEXT(“user32.dll”)), “GetWindowInfo”);

if(__GetWindowInfo)
	return __GetWindowInfo(hwnd, pwi);

if(pwi == NULL || pwi->cbSize != sizeof(WINDOWINFO))
	return FALSE;

GetWindowRect(hwnd, &pwi->rcWindow);
GetClientRect(hwnd, &pwi->rcClient);
MapWindowPoints(hwnd, HWND_DESKTOP, (LPPOINT)&pwi->rcClient, 2);

return TRUE;

}

#define IsDebuggerPresent _IsDebuggerPresent
#define IsProcessorFeaturePresent _IsProcessorFeaturePresent
#define SetProcessAffinityMask _SetProcessAffinityMask

#define GetWindowInfo _GetWindowInfo

// #ifdef USE_SHELL_SUPPORT
struct CDll
{
LPCTSTR _pszDll;
mutable HMODULE _hModule;
CDll(LPCTSTR pszDll) : _hModule(NULL), _pszDll(pszDll)
{
}

~CDll()
{
	if(_hModule)
		FreeLibrary(_hModule);
}

operator HMODULE() const
{
	if(_hModule == NULL)
		_hModule = LoadLibrary(_pszDll);

	return _hModule;
}

/*
operator const HMODULE() const
{
return operator HMODULE();
}
// */
};

typedef BOOL (WINAPI *fnSHGetSpecialFolderPath)(HWND hwndOwner, LPTSTR lpszPath, int nFolder, BOOL fCreate);
typedef HRESULT (WINAPI *fnSHGetFolderPath)(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath);

__inline BOOL WINAPI _SHGetSpecialFolderPath(HWND hwndOwner, LPTSTR lpszPath, int nFolder, BOOL fCreate)
{
static CDll hShell32(TEXT(“shell32.dll”));
static fnSHGetSpecialFolderPath __SHGetSpecialFolderPath = (fnSHGetSpecialFolderPath)1;
if(__SHGetSpecialFolderPath == (fnSHGetSpecialFolderPath)1)
__SHGetSpecialFolderPath = (fnSHGetSpecialFolderPath)GetProcAddress(hShell32,
#if !defined(UNICODE)
“SHGetSpecialFolderPathA”
#else
"SHGetSpecialFolderPathW"
#endif
);

if(__SHGetSpecialFolderPath)
	return __SHGetSpecialFolderPath(hwndOwner, lpszPath, nFolder, fCreate);

static CDll hShfolder(TEXT("shfolder.dll"));
static fnSHGetFolderPath __SHGetFolderPath = (fnSHGetFolderPath)1;
if(__SHGetFolderPath == (fnSHGetFolderPath)1)
	__SHGetFolderPath = (fnSHGetFolderPath)GetProcAddress(hShfolder,

#if !defined(UNICODE)
“SHGetFolderPathA”
#else
"SHGetFolderPathW"
#endif
);

if(!__SHGetFolderPath)
	return FALSE;

HRESULT hr = __SHGetFolderPath(hwndOwner, nFolder, NULL, 0 /*SHGFP_TYPE_CURRENT*/, lpszPath);
return SUCCEEDED(hr);

}

#ifdef SHGetSpecialFolderPath
#undef SHGetSpecialFolderPath
#endif
#define SHGetSpecialFolderPath _SHGetSpecialFolderPath
// #endif // USE_SHELL_SUPPORT

#endif // WIN32_WIN9X_H
[/code][/code]

Thanks - that’s really interesting. I should really merge all those changes into the places where the functions are used, like I’ve done for a lot of the win98 workarounds. Problem is that I’ve not got a win95 installation to try it out on.

But are people still using win95 anywhere?! What are you working on that needs such a level of backwards-compatibility?

Such a compatibility is not a real requirement currently, just my custom. BTW, this custom is from my work, and I am a developer at an anti-virus software company.

In fact, I am interesting in porting your excellent(yes, excellent!) work to mobile device, on both Windows Mobile and Symbian. I am trying to find a proper start point for that, can you give me any suggestion?

Sounds like fun! Porting it to windows mobile is probably fairly easy, I’d start by copying the win32 platform specific stuff and changing whatever is necessary to get it to build.

Porting to Symbian OS is a challange, since there were many limitations on it. No API(just tons of classes), no exception supporting, many odd types. and so on.

yes, that sounds like it could be quite messy!