1. 插件被激活后,会根据设置去加载游戏的loader,每个游戏都有一个对应的loader,
形式为loader.dll,需要游戏方自己开发,功能相当于原先的Launcher.exe。
2. 插件会创建好一个标准win32窗口传递给loader.dll,我们就是针对这个窗口编程,与平时开发一样,基本上就是标准的win32编程方式。
3. loader.dll 需要导出几个标准接口,供插件调用,代码实现在文件末尾。
编写loader.dll的时候,就根据这几个标准接口去实现相应功能(比如更新client、调用client,前面说了,相当于Launcher)。
4. 客户端也作为一个dll被loader加载,即client.dll,最好使用LoadLibraryEx。
5. 这个标准的win32窗口是unicode的!!!
可以使用 WINUSERAPI BOOL WINAPI IsWindowUnicode( __in HWND hWnd) 判断。
loader.dll和client.dll最好也是unicode的,不要是mbcs,这样从插件、到loader、到client,都是unicode的,不用做任何额外处理,不需要任何hack代码。
6. 一般来说,client中,自己不处理的windows消息,会调用 DefWindowProc 进行处理。
根据前一条规则,这些“自己不处理的windows消息”,一定要调用 DefWindowProcW 进行处理,因为窗口是unicode的。
如果loader.dll和client.dll是unicode的,调用 DefWindowProc 相当于调用 DefWindowProcW。
如果loader.dll和client.dll是mbcs的,在浏览器中运行时需要显示调用 DefWindowProcW,否则可能出现窗口标题栏乱码等情况;client.exe单独运行时需要调用 DefWindowProcA。
要根据窗口是否是Unicode的,来调用相应的 DefWindowProc,mbcs的窗口必须调用 DefWindowProcA,unicode的窗口必须调用 DefWindowProcW,否则出现不可预料的问题。
窗口是否是Unicode,是根据创建窗口前,调用的 RegisterClass、RegisterClassEx 版本决定的(百度百科)。
7. 插件会调用 DefWindowProc ,处理 loader.dll 和 client.dll 不处理的消息,根据接口之一 _FancyMessage 的返回值进行判断。
_FancyMessage 返回非0,则插件不调用 DefWindowProc ; _FancyMessage 返回0,则插件调用 DefWindowProc 。
一般来说,client代码中,编写WndProc时,原有的一些编程习惯是这样:自己处理的消息处理后、返回0,不处理的break,转去调用 DefWindowProc;
这种编程习惯会导致返回0的那些消息,会被插件层的 DefWindowProc 再次处理,可能导致不可预料的问题,最典型的的就是 WM_SETCURSOR 消息,你设置完返回0,
插件层的 DefWindowProc 再次处理 WM_SETCURSOR ,导致鼠标指针被系统重置为默认形状,你会看到鼠标指针不停闪烁,一会儿是游戏中的形状、一会儿是标准箭头。
疑问:client中如果调用了 DefWindowProcW ,处理了游戏逻辑不处理的消息, DefWindowProcW 的返回值是否是0,这个没有研究过,不清楚,
可以肯定的是,如果client中的 DefWindowProcW 返回了0,插件层的 DefWindowProcW 会再重复处理一遍,会产生什么问题,不得而知。
8. 游戏保存目录为C:\Users\[用户名]\fancy\[游戏名],比如黑暗之光的游戏目录为 C:\Users\admin\fancy\lost。
要获得这个目录,可以调用系统函数SHGetSpecialFolderPath,并对其结果做一定加工。
::SHGetSpecialFolderPath( 0, buffer, CSIDL_PROFILE, 0 );
9. loader.dll 需要打上青果签名,否则插件是不认的~~
10. 启动插件的页面代码,可以靠研究黑暗之光的页面获得。
跟青果对接的时候,他们会给你一个简单的示例,但光这个是远远不够的,你们还是需要去研究黑暗之光的页面机制。
11. loader.dll中加载client.dll的时候,最好使用LoadLibraryEx(szDllAbsolutePath, 0, LOAD_WITH_ALTERED_SEARCH_PATH);这样基本上所有的浏览器下都没问题。
否则,在不同浏览器下运行时,可能有些会找不到client.dll,导致无法加载。
ie、Chrome、360se还都是比较稳健的,使用LoadLibrary也没问题。
火狐、Safari、QQ浏览器都有点折腾,用LoadLibrary很容易报找不到client.dll。
12. 无插件情况下用360安全浏览器启动jzwl不能的问题,启动黑光可以。
360安全浏览器自带的插件对loader的url里的域名有检查,没在他白名单的不加载。
把loader.dll放在360cdn就可以解决问题;或者去360官网做url认证http://trust.360.cn/join.html。
13. 如果游戏中鼠标右键有操作,比如换装,在带右键手势的浏览器中运行的时候,会出现‘游戏右键操作’和‘浏览器右键手势’冲突的情况。
可以通过鼠标钩子的方式屏蔽右键消息,回调函数中返回1,浏览器就不会接收到了。然后可以通过其它的方式传递给客户端。
形式为loader.dll,需要游戏方自己开发,功能相当于原先的Launcher.exe。
2. 插件会创建好一个标准win32窗口传递给loader.dll,我们就是针对这个窗口编程,与平时开发一样,基本上就是标准的win32编程方式。
3. loader.dll 需要导出几个标准接口,供插件调用,代码实现在文件末尾。
编写loader.dll的时候,就根据这几个标准接口去实现相应功能(比如更新client、调用client,前面说了,相当于Launcher)。
4. 客户端也作为一个dll被loader加载,即client.dll,最好使用LoadLibraryEx。
5. 这个标准的win32窗口是unicode的!!!
可以使用 WINUSERAPI BOOL WINAPI IsWindowUnicode( __in HWND hWnd) 判断。
loader.dll和client.dll最好也是unicode的,不要是mbcs,这样从插件、到loader、到client,都是unicode的,不用做任何额外处理,不需要任何hack代码。
6. 一般来说,client中,自己不处理的windows消息,会调用 DefWindowProc 进行处理。
根据前一条规则,这些“自己不处理的windows消息”,一定要调用 DefWindowProcW 进行处理,因为窗口是unicode的。
如果loader.dll和client.dll是unicode的,调用 DefWindowProc 相当于调用 DefWindowProcW。
如果loader.dll和client.dll是mbcs的,在浏览器中运行时需要显示调用 DefWindowProcW,否则可能出现窗口标题栏乱码等情况;client.exe单独运行时需要调用 DefWindowProcA。
要根据窗口是否是Unicode的,来调用相应的 DefWindowProc,mbcs的窗口必须调用 DefWindowProcA,unicode的窗口必须调用 DefWindowProcW,否则出现不可预料的问题。
窗口是否是Unicode,是根据创建窗口前,调用的 RegisterClass、RegisterClassEx 版本决定的(百度百科)。
7. 插件会调用 DefWindowProc ,处理 loader.dll 和 client.dll 不处理的消息,根据接口之一 _FancyMessage 的返回值进行判断。
_FancyMessage 返回非0,则插件不调用 DefWindowProc ; _FancyMessage 返回0,则插件调用 DefWindowProc 。
一般来说,client代码中,编写WndProc时,原有的一些编程习惯是这样:自己处理的消息处理后、返回0,不处理的break,转去调用 DefWindowProc;
这种编程习惯会导致返回0的那些消息,会被插件层的 DefWindowProc 再次处理,可能导致不可预料的问题,最典型的的就是 WM_SETCURSOR 消息,你设置完返回0,
插件层的 DefWindowProc 再次处理 WM_SETCURSOR ,导致鼠标指针被系统重置为默认形状,你会看到鼠标指针不停闪烁,一会儿是游戏中的形状、一会儿是标准箭头。
疑问:client中如果调用了 DefWindowProcW ,处理了游戏逻辑不处理的消息, DefWindowProcW 的返回值是否是0,这个没有研究过,不清楚,
可以肯定的是,如果client中的 DefWindowProcW 返回了0,插件层的 DefWindowProcW 会再重复处理一遍,会产生什么问题,不得而知。
8. 游戏保存目录为C:\Users\[用户名]\fancy\[游戏名],比如黑暗之光的游戏目录为 C:\Users\admin\fancy\lost。
要获得这个目录,可以调用系统函数SHGetSpecialFolderPath,并对其结果做一定加工。
::SHGetSpecialFolderPath( 0, buffer, CSIDL_PROFILE, 0 );
9. loader.dll 需要打上青果签名,否则插件是不认的~~
10. 启动插件的页面代码,可以靠研究黑暗之光的页面获得。
跟青果对接的时候,他们会给你一个简单的示例,但光这个是远远不够的,你们还是需要去研究黑暗之光的页面机制。
11. loader.dll中加载client.dll的时候,最好使用LoadLibraryEx(szDllAbsolutePath, 0, LOAD_WITH_ALTERED_SEARCH_PATH);这样基本上所有的浏览器下都没问题。
否则,在不同浏览器下运行时,可能有些会找不到client.dll,导致无法加载。
ie、Chrome、360se还都是比较稳健的,使用LoadLibrary也没问题。
火狐、Safari、QQ浏览器都有点折腾,用LoadLibrary很容易报找不到client.dll。
12. 无插件情况下用360安全浏览器启动jzwl不能的问题,启动黑光可以。
360安全浏览器自带的插件对loader的url里的域名有检查,没在他白名单的不加载。
把loader.dll放在360cdn就可以解决问题;或者去360官网做url认证http://trust.360.cn/join.html。
13. 如果游戏中鼠标右键有操作,比如换装,在带右键手势的浏览器中运行的时候,会出现‘游戏右键操作’和‘浏览器右键手势’冲突的情况。
可以通过鼠标钩子的方式屏蔽右键消息,回调函数中返回1,浏览器就不会接收到了。然后可以通过其它的方式传递给客户端。
目前360安全浏览器手势被屏蔽了,遨游也可以,2345、搜狗等仍然不能屏蔽手势。
#include "stdafx.h"
#include "fancy.h"
unsigned long gTLS = 0;
extern "C"
{
//----------------------------------------------------------------------------
// _FancyCreate Implementation
//----------------------------------------------------------------------------
unsigned int __declspec( dllexport ) _FancyCreate( void* window, const wchar_t* game, const wchar_t* vers, const wchar_t* host, unsigned long mode )
{
::TlsSetValue( gTLS, Fancy3DLoader::CreateLoader( window, mode ) );
::SetTimer( (HWND) window, 0, 10, 0 );
return 1;
}
//----------------------------------------------------------------------------
// _FancyDelete Implementation
//----------------------------------------------------------------------------
void __declspec( dllexport ) _FancyDelete( void* window )
{
::KillTimer( (HWND) window, 0 );
Fancy3DLoader* loader = (Fancy3DLoader*) ::TlsGetValue( gTLS );
if ( loader )
delete loader;
::TlsSetValue( gTLS, 0 );
}
//----------------------------------------------------------------------------
// _FancySetup Implementation
//----------------------------------------------------------------------------
void __declspec( dllexport ) _FancySetup( const wchar_t* name, const wchar_t* value )
{
Fancy3DLoader* loader = (Fancy3DLoader*) ::TlsGetValue( gTLS );
if ( loader )
loader->Setup( name, value );
}
//----------------------------------------------------------------------------
// _FancyUpdate Implementation
//----------------------------------------------------------------------------
unsigned int __declspec( dllexport ) _FancyUpdate( void* window, unsigned long elapse )
{
Fancy3DLoader* loader = (Fancy3DLoader*) ::TlsGetValue( gTLS );
if ( loader )
loader->Update( elapse );
return 1;
}
//----------------------------------------------------------------------------
// _FancyRender Implementation
//----------------------------------------------------------------------------
void __declspec( dllexport ) _FancyRender( void* window )
{
Fancy3DLoader* loader = (Fancy3DLoader*) ::TlsGetValue( gTLS );
if ( loader )
loader->Render( );
}
//----------------------------------------------------------------------------
// _FancyMessage Implementation
//----------------------------------------------------------------------------
unsigned int __declspec( dllexport ) _FancyMessage( void* window, unsigned long msgid, unsigned long wparam, unsigned long lparam )
{
Fancy3DLoader* loader = (Fancy3DLoader*) ::TlsGetValue( gTLS );
if ( loader )
return loader->Message( msgid, wparam, lparam );
return 1;
}
//----------------------------------------------------------------------------
// _FancyProgress Implementation
//----------------------------------------------------------------------------
float __declspec( dllexport ) _FancyProgress( )
{
// For backwards compatibility.
Fancy3DLoader* loader = (Fancy3DLoader*) ::TlsGetValue( gTLS );
if ( loader )
return loader->GetProgress( );
return 0.0f;
}
}
#include "fancy.h"
这里就是实现了这个类Fancy3DLoader,通过该类的静态函数Fancy3DLoader::CreateLoader创建,
这个类随便你定义,类的主要职责就是下载游戏、加载游戏