技术宅的结界

 找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 10879|回复: 20
收起左侧

【VB6】glew 2.0的VB6版本的DLL以及TLB

[复制链接]

1094

主题

2671

帖子

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
238
威望
616 点
宅币
22347 个
贡献
46089 次
宅之契约
0 份
在线时间
2138 小时
注册时间
2014-1-26
发表于 2017-2-25 17:51:43 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

x
用了它,VB6就能直接使用OpenGL的最新功能,以及各种扩展功能了。
20170225161000.png
20170225161123.png
实例(含源码)下载:
demo.7z (265.91 KB, 下载次数: 69)

glew32vb.dll工程和源码下载:
glew32vb.7z (365.14 KB, 下载次数: 14, 售价: 2 个宅币)

其中,glew32vb.dll是怎么制作的呢?
    首先我发现VB6不能直接用glew32.dll是因为它用函数指针记录opengl特性函数的地址,导出dll时直接导出这个函数指针的符号,VB6是不能直接调用DLL里面的函数指针指向的函数的。这些函数都是由驱动提供,glew在Windows下都是通过调用wglGetProcAddress取得的,因此glew32.dll不能直接静态地导出这些函数的地址。
    怎么办呢,我的做法是直接写个汇编的跳转表,自己导出这些函数的符号,当VB6调用我的汇编写的DLL导出的符号的时候,我一个jmp就能直接跳到函数指针指向的函数的入口处。这样我既有静态的导出函数的地址,又能帮VB跳到函数指针的位置。
    OpenGL支持的函数很多,如果要手动写这个汇编的话,效率非常低。这肯定要自动化的,也不难,直接用exescope看glew32.dll的导出表,然后把它存储为txt,就能得到这些符号了。
20170225174928.png
20170225175031.png
exescope导出的txt非常整齐,直接用notepad++打开,Alt+左键,一个列编辑操作,直接就可以把左边两列没用的东西都删了,得到纯粹的符号表。
20170225175223.png
那,这些就是我们想要导出的符号了吗?当然,但这里面并不全是函数,从第1行到第604行结尾,全是变量符号导出,VB6是不能直接从DLL读取变量的,到时候我们写个汇编的函数,自动用MOV读变量(反正不需要写)。

我们导出的函数不能和glew库导出的函数重名,而且我们不打算使用动态链接的glew32.dll,多余。到时候直接把glew自己的静态库glew32s.lib静态链接到自己的dll里面就行。

解决函数重名的方法,其实很简单,glew.h其实也是用宏,把所有的__glew开头的函数,改名为gl开头。我们也一样,汇编部分用gl开头代替原先的__glew开头。

先复制一份这个符号列表到另一个notepad++窗口,第一行前面插入一个空行,然后在窗口里打开查找替换,打开匹配大小写,查找模式设为扩展,然后把“\n___GLEW”替换成“\nglobal _GL”,把“\n___glew”替换为“\nglobal _gl”,保存为“exp_todll.inc”。这个文件是干啥的呢,其实就是给我们接下来汇编文件正文部分用的,%include"exp_todll.inc",包含它后,我们就在自己的汇编obj声明了自己的导出函数。

也许你会注意到,我们用查找替换的时候,查找的符号有三个下划线,“___”,自己的符号则有一个下划线“_”,这个下划线是哪来的呢?这是C语言的特性,目标平台为x86的情况下C编译器会自动给符号添加“_”下划线,以免和其它语言生成的符号混淆。8086时代过来的习惯,为了能和pascal一起编译而设计的特性。现在amd64平台的情况下这个下划线已经不再被添加了。

有了导出函数,我们还得从glew32s.lib导入它原先的符号,同样像刚才那样复制符号列表到新的窗口,然后用查找替换,把“\n”替换为“\nextern ”,保存为“imp_fromlib.inc”。这就是咱这个obj的导入表了。

然后,接下来是重点,两部分,静态符号跳转到函数指针,以及,自己的读导出变量的函数。

继续复制符号列表,然后,这次是一边用查找替换,一边用列编辑,具体的我就不细说了,大家自己悟吧,非常简单。简而言之,就是把符号列表,变成下面这个样子的玩意儿:
20170225181703.png
记住先把从第1行到第604行结尾的内容删掉,因为这些并不是函数。
现在你就能看到跳转表是怎么做的了。把它保存为funcjump.inc,到时候我们在汇编的主程序里面包含它。

接下来还有另一个部分,glew32s.lib导出的变量的符号,我们是需要让VB能读取这些变量的数值的。所以我们给每一个变量写一个函数,能读取这个变量的值,并且返回给VB。
这些变量都是什么呢?这些都是glew库检测的显卡驱动对特定特性的支持与否的判断,非零时表示支持某个特定功能,零,则表示不支持。

我们先取第1行到第604行结尾的内容,如图:
20170225181256.png
然后,把它们做成这样:
20170225182141.png
这样就可以了,都是自动化处理的,或者说半自动化,偶尔还是需要用一下列编辑的。

现在我们有了导入表,导出表,跳转表,读变量的表,最后把这些表组装一下,就可以得到我们想要的dll了。
20170225182518.png
这就是主程序了。不用多说,大家一看就能明白。

哦对了我们还需要一个def文件来定义我们的dll要导出的符号。
还是老样子,复制一份符号表,然后,这次用查找替换把“__glew”替换为“gl”,然后把“__GLEW”替换为“GL”,前面再写个经典的“LIBRARY”换行“EXPORTS”换行,就行了。
20170225182819.png

嗯,差不多了?其实还没完,我们干脆把opengl32.dll的导出函数也复制一份到我们的def里面。操作还是一样,用exescope取导出表符号,然后列编辑,复制粘贴,完事儿。
搞定后就可以编译了。
20170225183152.png
不保证大家和我一样用VS2012,所以前面干脆把vs各个版本的环境变量设置脚本都call一遍,然后用nasm编译主程序,用link链接obj、lib和def,得到dll,搞定。
我编译的这个版本自己顺手做了个资源文件,弄了个版本资源,写了作者信息。
20170225183516.png

这样glew32vb.dll就做好了,当时我还自己写VB的Declare Sub之类的玩意儿测试了一下,无BUG完美运行。但如果我要顺畅地使用它,我肯定要做TLB的。因为VB一个bas文件里面能声明的API和常量的个数有限,真不想搞一大堆bas拖着工程,干脆做个TLB。

TLB是用MIDL编译IDL语言,得到的类型库,VB的工程引用了这个类型库以后,就能得到它声明的各种常数、函数了。

其中制作TLB文件时,我从OpenGL EW的源码中找到了OpenGL扩展定义文件(下图)
20170225172540.png

我发现OpenGL EW是用一系列perl脚本来将这些扩展定义文件解析为OpenGL EW的头文件和源码。因此我也用相似的方法来让它生成IDL脚本,我写了一个VB工程专门用来转换这个,vbgldef。
工程下载:
vbParseOpenGLDef.7z (148.19 KB, 下载次数: 11, 售价: 8 个宅币)
其中我在调试的过程中发现了用MIDL生成TLB的一些特性:
1、MIDL不支持函数指针。
2、所有的typedef都必须写在module的前面。
3、VB6不认char*, 各种**, 各种int, unsigned long, unsigned short, signed char等各种类型。
为了解决这些特性,我的这个工程具有以下功能:
1、两遍pass,把typedef和常量、函数分开。
2、避开重复定义,遇到重复定义的常量,直接注释掉。
3、遇到定义常量别名的情况:自动将第一次pass时记录的常量值展开。
4、遇到函数的参数列表里有函数指针时:强行换成void*
5、遇到char*时:强行换成LPSTR
6、VB6不支持函数返回void*,我强行把它改成long(然而我依然要吐槽:不要把指针当成long,除非现在这种情况)
另外我手动把那些和VB6无关的玩意儿,比如安卓的EGL、Unix的GLX等特性文件,都移到了别的文件夹。

这样,运行一次vbgldef后,它就能读取ext文件夹里面的那些文本,然后,把所有的typedef写到typedefs.h里面,把所有的常量和函数都写到cnstfunc.h里面。
而我所需要做的,就是在idl文件里面包含它们。为了保证我得到的TLB能够被VB6使用,我的IDL文件这样写:
[C++] 纯文本查看 复制代码
#define APIENTRY _stdcall
#define GLVER(x) [entry(#x), helpstring("Returns non-zero if you have "#x" supports")]int APIENTRY x()
#define ptrdiff_t int
#define VOID void
#define HGLRC int

[uuid(CB8F22FC-668D-440C-B538-B4D030ED7905)] library glew32vb
{
	struct __GLsync{int __unused;};
	struct _cl_context{int __unused;};
	struct _cl_event{int __unused;};
	
	#define WINAPI _stdcall
	#define PROC void*
	#define GLEWAPIENTRY WINAPI
	
	// VB6 don't have unsigned short and unsigned long
	#define WORD short
	#define DWORD long
	#define unsigned
	#define HDC long
	#define int long
	
	typedef struct
	{
		WORD  nSize;
		WORD  nVersion;
		DWORD dwFlags;
		BYTE  iPixelType;
		BYTE  cColorBits;
		BYTE  cRedBits;
		BYTE  cRedShift;
		BYTE  cGreenBits;
		BYTE  cGreenShift;
		BYTE  cBlueBits;
		BYTE  cBlueShift;
		BYTE  cAlphaBits;
		BYTE  cAlphaShift;
		BYTE  cAccumBits;
		BYTE  cAccumRedBits;
		BYTE  cAccumGreenBits;
		BYTE  cAccumBlueBits;
		BYTE  cAccumAlphaBits;
		BYTE  cDepthBits;
		BYTE  cStencilBits;
		BYTE  cAuxBuffers;
		BYTE  iLayerType;
		BYTE  bReserved;
		DWORD dwLayerMask;
		DWORD dwVisibleMask;
		DWORD dwDamageMask;
	} PIXELFORMATDESCRIPTOR;
	
	#define GLAPIENTRY APIENTRY
	
	#include"typedefs.h"
	
	#define GLboolean long
	
	[dllname("gdi32")]
	module gdi32
	{
		/* pixel types */
		const DWORD PFD_TYPE_RGBA        = 0;
		const DWORD PFD_TYPE_COLORINDEX  = 1;

		/* layer types */
		const DWORD PFD_MAIN_PLANE       = 0;
		const DWORD PFD_OVERLAY_PLANE    = 1;
		const DWORD PFD_UNDERLAY_PLANE   = (-1);

		/* PIXELFORMATDESCRIPTOR flags */
		const DWORD PFD_DOUBLEBUFFER            = 0x00000001;
		const DWORD PFD_STEREO                  = 0x00000002;
		const DWORD PFD_DRAW_TO_WINDOW          = 0x00000004;
		const DWORD PFD_DRAW_TO_BITMAP          = 0x00000008;
		const DWORD PFD_SUPPORT_GDI             = 0x00000010;
		const DWORD PFD_SUPPORT_OPENGL          = 0x00000020;
		const DWORD PFD_GENERIC_FORMAT          = 0x00000040;
		const DWORD PFD_NEED_PALETTE            = 0x00000080;
		const DWORD PFD_NEED_SYSTEM_PALETTE     = 0x00000100;
		const DWORD PFD_SWAP_EXCHANGE           = 0x00000200;
		const DWORD PFD_SWAP_COPY               = 0x00000400;
		const DWORD PFD_SWAP_LAYER_BUFFERS      = 0x00000800;
		const DWORD PFD_GENERIC_ACCELERATED     = 0x00001000;
		const DWORD PFD_SUPPORT_DIRECTDRAW      = 0x00002000;
		const DWORD PFD_DIRECT3D_ACCELERATED    = 0x00004000;
		const DWORD PFD_SUPPORT_COMPOSITION     = 0x00008000;

		/* PIXELFORMATDESCRIPTOR flags for use in ChoosePixelFormat only */
		const DWORD PFD_DEPTH_DONTCARE          = 0x20000000;
		const DWORD PFD_DOUBLEBUFFER_DONTCARE   = 0x40000000;
		const DWORD PFD_STEREO_DONTCARE         = 0x80000000;
		
		[entry("ChoosePixelFormat")]
		int WINAPI ChoosePixelFormat( [in] HDC hdc, [in] const PIXELFORMATDESCRIPTOR *ppfd);
		[entry("SetPixelFormat")]
		BOOL WINAPI SetPixelFormat( [in] HDC hdc, [in] int format, [in] const PIXELFORMATDESCRIPTOR * ppfd);
		[entry("SwapBuffers")]
		BOOL  WINAPI SwapBuffers(HDC);
	};
	
	[dllname("opengl32")]
	module opengl32
	{
		[entry("wglCopyContext")]
		BOOL  WINAPI wglCopyContext(HGLRC, HGLRC, UINT);
		[entry("wglCreateContext")]
		HGLRC WINAPI wglCreateContext(HDC);
		[entry("wglCreateLayerContext")]
		HGLRC WINAPI wglCreateLayerContext(HDC, int);
		[entry("wglDeleteContext")]
		BOOL  WINAPI wglDeleteContext(HGLRC);
		[entry("wglGetCurrentContext")]
		HGLRC WINAPI wglGetCurrentContext(VOID);
		[entry("wglGetCurrentDC")]
		HDC   WINAPI wglGetCurrentDC(VOID);
		[entry("wglGetProcAddress")]
		PROC  WINAPI wglGetProcAddress(LPCSTR);
		[entry("wglMakeCurrent")]
		BOOL  WINAPI wglMakeCurrent(HDC, HGLRC);
		[entry("wglShareLists")]
		BOOL  WINAPI wglShareLists(HGLRC, HGLRC);
		[entry("wglUseFontBitmapsA")]
		BOOL  WINAPI wglUseFontBitmaps(HDC, DWORD, DWORD, DWORD);
		[entry("wglUseFontBitmapsA")]
		BOOL  WINAPI wglUseFontBitmapsA(HDC, DWORD, DWORD, DWORD);
		[entry("wglUseFontBitmapsW")]
		BOOL  WINAPI wglUseFontBitmapsW(HDC, DWORD, DWORD, DWORD);
	};
	
	[dllname("glew32vb")]
	module glew32
	{
		[entry("glewGetErrorString")]
		long GLEWAPIENTRY glewGetErrorString (GLenum error);
		[entry("glewGetExtension")]
		GLboolean GLEWAPIENTRY glewGetExtension (void *name);
		[entry("glewGetString")]
		long GLEWAPIENTRY glewGetString (GLenum name);
		[entry("glewInit")]
		GLenum GLEWAPIENTRY glewInit (void);
		[entry("glewIsSupported")]
		GLboolean GLEWAPIENTRY glewIsSupported (void *name);
		[entry("wglewGetExtension")]
		GLboolean GLEWAPIENTRY wglewGetExtension (void *name);
		[entry("wglewInit")]
		GLenum GLEWAPIENTRY wglewInit ();
		[entry("wglewIsSupported")]
		GLboolean GLEWAPIENTRY wglewIsSupported (void *name);
		#include"cnstfunc.h"
	};
	
	// Debug functions, can be removed now.
	[dllname("user32")]
	module user32
	{
		[entry("MessageBoxA")]
		long WINAPI MessageBoxA(long hWnd, LPSTR lpText, LPSTR lpCaption, long uType);
		[entry("MessageBoxW")]
		long WINAPI MessageBoxW(long hWnd, void *lpText, void *lpCaption, long uType);
	};
};
其中的MessageBoxA之类的,是当时调试的时候写的声明,留着无用,可删。
编译调试这玩意儿挺费劲的。

整个tlb工程下载:
glewtlb.7z (302.19 KB, 下载次数: 9, 售价: 10 个宅币)

参考资料:
https://msdn.microsoft.com/en-us ... 93359(v=vs.85).aspx
https://msdn.microsoft.com/en-us ... 67091(v=vs.85).aspx
https://www.microsoft.com/msj/0898/idl/idl.aspx
http://glew.sourceforge.net/
https://github.com/nigels-com/glew/tree/master/auto/core/gl

本帖被以下淘专辑推荐:

回复

使用道具 举报

0

主题

5

帖子

31

积分

用户组: 初·技术宅

UID
2280
精华
0
威望
0 点
宅币
26 个
贡献
0 次
宅之契约
0 份
在线时间
2 小时
注册时间
2017-2-25
发表于 2017-2-25 18:13:12 | 显示全部楼层
还在坚守VB6!顶一个.

0

主题

5

帖子

26

积分

用户组: 初·技术宅

UID
2284
精华
0
威望
2 点
宅币
17 个
贡献
0 次
宅之契约
0 份
在线时间
0 小时
注册时间
2017-2-25
发表于 2017-2-25 22:47:52 | 显示全部楼层
好贴必须顶~~

2

主题

61

帖子

458

积分

用户组: 中·技术宅

UID
2364
精华
0
威望
0 点
宅币
397 个
贡献
0 次
宅之契约
0 份
在线时间
53 小时
注册时间
2017-3-30
发表于 2017-4-17 03:19:24 | 显示全部楼层
谢谢分享
回复

使用道具 举报

2

主题

10

帖子

81

积分

用户组: 小·技术宅

UID
2644
精华
0
威望
12 点
宅币
47 个
贡献
0 次
宅之契约
0 份
在线时间
3 小时
注册时间
2017-7-3

最佳新人

发表于 2017-7-3 17:07:36 | 显示全部楼层
为什么不能下载呢?求解

2

主题

10

帖子

81

积分

用户组: 小·技术宅

UID
2644
精华
0
威望
12 点
宅币
47 个
贡献
0 次
宅之契约
0 份
在线时间
3 小时
注册时间
2017-7-3

最佳新人

发表于 2017-7-3 17:37:22 | 显示全部楼层
这个帖子含金量很高,因为下载不了附件,不清楚demo中的实现程度到什么境界了,期待ing

1094

主题

2671

帖子

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
238
威望
616 点
宅币
22347 个
贡献
46089 次
宅之契约
0 份
在线时间
2138 小时
注册时间
2014-1-26
 楼主| 发表于 2017-9-16 01:31:46 | 显示全部楼层
nickdu 发表于 2017-7-3 17:37
这个帖子含金量很高,因为下载不了附件,不清楚demo中的实现程度到什么境界了,期待ing ...

现在你的宅币应该足够购买这个附件了。

1

主题

15

帖子

15

积分

用户组: 初·技术宅

UID
2735
精华
0
威望
0 点
宅币
0 个
贡献
0 次
宅之契约
0 份
在线时间
6 小时
注册时间
2017-7-28
发表于 2017-10-8 20:23:20 | 显示全部楼层
现在你的宅币应该足够购买这个附件了。

评分

参与人数 1宅币 -49 收起 理由
0xAA55 -49 灌水惩罚

查看全部评分

0

主题

5

帖子

15

积分

用户组: 初·技术宅

UID
2980
精华
0
威望
0 点
宅币
10 个
贡献
0 次
宅之契约
0 份
在线时间
2 小时
注册时间
2017-10-19
发表于 2017-10-19 12:43:44 | 显示全部楼层
有两个帖子提到了glew32vb.dll,这两个有什么区别吗?

0

主题

11

帖子

28

积分

用户组: 初·技术宅

UID
3034
精华
0
威望
1 点
宅币
15 个
贡献
0 次
宅之契约
0 份
在线时间
1 小时
注册时间
2017-11-2
发表于 2017-11-2 18:49:29 | 显示全部楼层
正需要这方面的,多谢多谢

1

主题

84

帖子

89

积分

用户组: 小·技术宅

UID
3026
精华
0
威望
1 点
宅币
3 个
贡献
0 次
宅之契约
0 份
在线时间
6 小时
注册时间
2017-10-31
发表于 2017-11-7 08:03:45 | 显示全部楼层
不错,学习了。谢谢

1094

主题

2671

帖子

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
238
威望
616 点
宅币
22347 个
贡献
46089 次
宅之契约
0 份
在线时间
2138 小时
注册时间
2014-1-26
 楼主| 发表于 2018-2-18 11:43:07 | 显示全部楼层
已更新:
1、修复了demo里面的着色器用了varying in和varying out导致AMD显卡不兼容的问题。
2、demo现在会把编译输出打印到log文件了。
3、修复了无法调用glMapBuffer等各种返回void*的函数的无法被VB6调用的问题。因为VB6不支持从TLB调用返回void*类型的函数,我把它强行改成了long。

1094

主题

2671

帖子

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
238
威望
616 点
宅币
22347 个
贡献
46089 次
宅之契约
0 份
在线时间
2138 小时
注册时间
2014-1-26
 楼主| 发表于 2019-5-1 09:38:32 | 显示全部楼层
wnglng2 发表于 2017-10-19 12:43
有两个帖子提到了glew32vb.dll,这两个有什么区别吗?

新旧的区别,建议用新的

1

主题

61

帖子

189

积分

用户组: 小·技术宅

UID
4683
精华
0
威望
0 点
宅币
128 个
贡献
0 次
宅之契约
0 份
在线时间
30 小时
注册时间
2019-2-11
发表于 2019-5-10 19:55:26 | 显示全部楼层
好神奇,收藏。

0

主题

4

帖子

5049

积分

用户组: 技术宅的结界VIP成员

UID
5581
精华
0
威望
6 点
宅币
5033 个
贡献
0 次
宅之契约
0 份
在线时间
7 小时
注册时间
2020-2-4
发表于 2020-2-5 22:11:39 | 显示全部楼层
正需要,请问如何下载?

2

主题

21

帖子

81

积分

用户组: 小·技术宅

UID
5625
精华
0
威望
2 点
宅币
56 个
贡献
0 次
宅之契约
0 份
在线时间
3 小时
注册时间
2020-2-18
发表于 2020-2-18 09:26:59 | 显示全部楼层
给力!!但是下载不了啊!

2

主题

21

帖子

81

积分

用户组: 小·技术宅

UID
5625
精华
0
威望
2 点
宅币
56 个
贡献
0 次
宅之契约
0 份
在线时间
3 小时
注册时间
2020-2-18
发表于 2020-2-24 17:14:39 | 显示全部楼层
无法下载是啥子原因?

1

主题

63

帖子

333

积分

用户组: 中·技术宅

UID
6035
精华
0
威望
2 点
宅币
266 个
贡献
0 次
宅之契约
0 份
在线时间
29 小时
注册时间
2020-7-7
发表于 2020-7-8 10:14:26 | 显示全部楼层
本帖最后由 china_shy_wzb 于 2020-7-20 13:51 编辑

又一个VB6编写DLL的例子

0

主题

4

帖子

17

积分

用户组: 初·技术宅

UID
7725
精华
0
威望
2 点
宅币
9 个
贡献
0 次
宅之契约
0 份
在线时间
2 小时
注册时间
2022-3-9
发表于 2022-3-10 10:31:49 | 显示全部楼层
谢谢分享
回复

使用道具 举报

0

主题

1

帖子

17

积分

用户组: 初·技术宅

UID
8001
精华
0
威望
2 点
宅币
12 个
贡献
0 次
宅之契约
0 份
在线时间
2 小时
注册时间
2022-8-1
发表于 3 天前 | 显示全部楼层
请教一个问题,一个模拟器用普通窗口句柄截图得不到正确结果,经过询问,大佬说需要用openGL绑定截图,他们不是用的VB,是易语言,请问vb6怎么弄?

本版积分规则

QQ|申请友链||Archiver|手机版|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2022-8-9 16:10 , Processed in 0.057166 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表