2010年3月3日星期三

在Visual C++ 1.10/2.0环境下编译Mini vMac

Visual C++ 和微软的其他开发工具一样有很长的历史,其第一个32位版本早在NT 3.1的1993年就正式出现了。Mini vMac 是我在开放源代码的模拟器中所见过代码最为精炼、简洁的,这也使得它具有相当好的移植性。上次搞到32位版本的VC++ 1.10,于是就准备拿这个Mini vMac来玩玩。
首先使用Mini vMac的源代码镜像,在Mini vMac环境中运行Build,用-e msv -ev 6000参数生成一个适合于Visual C++6.0的完整源码zip文档。
把该zip解压开,打开Visual C++ 1.1,在这个源码所在的目录新建一个工程文件。把源码目录下src子目录下的所有.c和.rc添加到工程中。
由于Visual C++ 1.1环境出现在Windows 95之前,和VC6相比,它具有很多限制:
1.shlobj.h不存在。所有和Explorer相关API和ActiveX相关API都不可用。
2.许多Win32的常数宏定义在自带头文件中不存在。
3.OLE2相关的均不可用。
4.winmm API中的一些参数与VC6有很大差别,比如WAVEFORMATEX结构不能用等等。
5.内联函数定义只有__inline。
6.使用IDE生成的makefile中,rc编译器的路径只包括工程文件所在路径。
7.编译器只支持WinMain为Windows应用程序主函数名。
这里仅仅提到了与Mini vMac相关的一些。因此,必须进行修改,才能编译成功。
我大概具体修改了这么一些地方:
1、CNFGGLOB.h中,#define MayInline __forceinline 改为 __inline。
2、MYOSGLUE.c中

1)
必须加入常量VK_APPS、VK_LWIN、VK_RWIN、SPI_SCREENSAVERRUNNING、_MAX_PATH、等一大堆东西(记不清,自己根据错误内容去看吧。。)
2)
typedef HRESULT (WINAPI *SHGetSpecialFolderPathProcPtr) (
HWND hwndOwner,
LPTSTR lpszPath,
int nFolder,
BOOL fCreate
);
LOCALVAR SHGetSpecialFolderPathProcPtr MySHGetSpecialFolderPath = NULL;
注释掉,加一行LOCALVAR long MySHGetSpecialFolderPath = NULL;
LOCALFUNC blnr HaveMySHGetSpecialFolderPath(void)
{
下面
if (! DidSHGetSpecialFolderPath) {
HMODULE hLibModule = LoadLibrary(TEXT("shell32.dll"));
if (NULL != hLibModule) {
MySHGetSpecialFolderPath =
(SHGetSpecialFolderPathProcPtr)
GetProcAddress(hLibModule,
#if MyUseUni
TEXT("SHGetSpecialFolderPathW")
#else
TEXT("SHGetSpecialFolderPathA")
#endif
);
FreeLibrary(hLibModule);
}
DidSHGetSpecialFolderPath = trueblnr;
}
也注释掉。这是因为VC1.1不存在shlobj.h,无法使用这些API,而且也不能使用typedef HRESULT (WINAPI *SHGetSpecialFolderPathProcPtr) 这样的方法来自己定义个函数指针,只有干掉了。
3)
#ifndef EnableShellLinks
#define EnableShellLinks 1 改成 0
#endif
快捷方式相关的VC1.1不能用,没办法。
4)
LOCALPROC MySound_Start(void)
中的
WAVEFORMATEX wfex;
改成
PCMWAVEFORMAT wfex;
其初始化部分
wfex.wFormatTag = WAVE_FORMAT_PCM;
wfex.nChannels = 1;
wfex.nSamplesPerSec = SOUND_SAMPLERATE;
wfex.nAvgBytesPerSec = SOUND_SAMPLERATE;
wfex.nBlockAlign = 1;
wfex.wBitsPerSample = 8;
wfex.cbSize = 0;
改成
wfex.wf.wFormatTag = WAVE_FORMAT_PCM;
wfex.wf.nChannels = 1;
wfex.wf.nSamplesPerSec = SOUND_SAMPLERATE;
wfex.wf.nAvgBytesPerSec = SOUND_SAMPLERATE;
wfex.wf.nBlockAlign = 1;
wfex.wBitsPerSample=8;
5)
LOCALPROC MyAppendSubmenuConvertName(HMENU hMenu,
HMENU hSubMenu, char *s)
中,
MENUITEMINFO mii;
注释掉
#if 0改成1
下面的
memset(&mii, 0, sizeof(MENUITEMINFO));
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_TYPE | MIIM_SUBMENU;
mii.fType = MFT_STRING;
mii.hSubMenu = hSubMenu;
mii.dwTypeData = ts;
mii.cch = (UINT)_tcslen(ts);
(void) InsertMenuItem(hMenu, (UINT) -1, TRUE,
&mii);
注释掉
VC1.1没有InsertMenuItem这个API和MENUITEMINFO结构。
6)int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
改成
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)

3、CNFGRAPI.h的#include 注释掉。
令人惊奇的是,我们修改的仅仅是Mini vMac与系统结合的那一部分,其模拟代码根本没有必要修改。
这样修改后,工程设置把警告级别再改下,编译可以得到这样的结果。

经过我的测试,编译出的MVMAC.exe的链接器版本号为3.10,实际可以在Windows NT 3.5以上的系统运行。

VC2.0和VC1.1的SDK差不多,基本可以如法炮制。
目前还有一些问题点:
1、VC1.1(CL 8.0)、VC 2.0(CL 9.0)都不支持__int64,这是Mini vMac II浮点模拟库必须的,因此目前VC1.1无法简单地编译具有FPU模拟功能的Mini vMac II。
2、这样编译的Mini vMac关闭较慢,还没搞清楚怎么回事,
3、VC1.1的链接器在高版本NT系统(如NT4、2000、XP)下工作不正常,生成特别大的exe,需要使用2.0版本的替换。
另外,某论坛上有洋大人问是否能够把这个编译到16位的Windows平台,或者把这个在Win3.1+Win32s上运行,我只能说,前者需要进行大幅修改(程序中大量直接使用int,大量使用32位内存模型的内存分配),而后者据我的测试,连找不到ROM的错误信息都显示不出来,估计是DIB不支持之类的问题。

没有评论:

发表评论