MFC工程中无法使用cygwin64的库
文章目录
MFC工程中无法使用cygwin64的库
概述
开始想在MFC程序中使用cygwin64的库(静态库, 动态库(静态包含), 动态库(动态调用)).
做实验之前, 想想只要将gnu的功能封装成库(只需要封装成接口, 逻辑部分可以不动或轻微修改), 给自己工程用, 前景多美好.
现实很骨感. 试过了, 都不行, 走弯路了.
cygwin64官方文档上, 关于DLL这块, 也是给可以替换CRTinit这种VS工程用的. 如果像MFC这种框架型的工程, 根本没办法替换CRTInit的操作.
总之, 想将gnu实现包进自己工程用, 和cygwin64官方的思路就相违背. 做这种实验, 吃苦头也就是水到渠成的了.
网上关于cygwin64DLL给VS工程的资料不多, 说来说去, 都是围着官方文档在转.
在MFC中使用cygwin64的静态库
这个根本就编译不过, 因为编译出来的cygwin64库还有依赖的cygwin64底层实现, 各种编译报错.
在MFC中使用cygwin64的DLL进行静态包含
这个可以编译过, 但是运行时, 如果在DLL函数中使用了cygwin64的函数(e.g. fopen), 虽然不报错, 可是直接不好使, 文件都打不开(文件句柄为空). 原因是, cygwindll初始化无效引起的.
在MFC中使用cygwin64的DLL进行动态调用
在LoadLIbrary()就会报错, LoadLibrary都没执行完.
无源码调试看了一下调用链.
可以看到, LoadLibray()时, 会进入DLL入口函数, 然后会调用cywin1_cygwin_dll_init(), 这个初始化函数会失败, 然后走到assert报错
唯一可以使用cygwin64的方法是进程隔离来通讯
- 调用cygwin64的exe来干活
- 和cygwin64做成的exe通过本地socket来通讯, 委托cygwin64的程序实现功能.
我开始要做cygwin64DLL的原因: 因为调用批处理时候, 总是会出dos窗口. 因为这个程序是基于以前的实现堆出来的. 以前那个程序就在调用批处理时, 会不断的弹dos窗口. 这次功能行代码写完了, 就想将这个问题搞掉, 要不不像个程序啊(用户都会说这个dos弹窗问题).
然后去做cygwin64的DLL(顺便学了一下CMake的初级用法[CMake官方前4课], 用CMake来做linux程序构建的脚本, 不用自己去写Makefile了), 尝试给MFC-EXE用. 用了一个星期, 怎么玩cygwin64工程, 已经清楚了.
但是做好的cygnwin64DLL无法给MFC用.
然后思路又回到隐藏dos窗口上, 看了一些资料, 人家说确实可以调用批处理(.bat)时隐藏dos窗口, 那我的实现咋不行呢?
对了一下, 自己改了参数, CreateProcess()的参数5, 加了CREATE_NEW_CONSOLE, 有了这个参数, 就无法隐藏dos窗口.去掉这个就好了.
用了一个星期, 没有搞出新解决方法, 然后发现自己实现写错了, 还是挺难受的. 这不被自己玩了么?
cygwin64的官方用途
毕竟cygwin64官方的目的是为了将linux/gnu工程移植到window, 让linux/gnu工程代码不改或少改.
如果主程序(非cygwin64工程)想用cygwin64工程的功能, 还是进行进程隔离来使用cygwin64工程输出, 这个也是最简单的方法.
毕竟大多数人的主程序也不可能是cygwin64的工程.
cygwin64官方也没考虑让cygwin64的工程输出能包含进其他程序.
修正后的启动进程隐藏dos窗口的函数
BOOL COrderProcBase::executeCommandLine(CString cmdLine, DWORD& exitCode)
{
PROCESS_INFORMATION processInformation = { 0 };
STARTUPINFO startupInfo = { 0 };
memset(&startupInfo, 0, sizeof(STARTUPINFO));
GetStartupInfo(&startupInfo); // 可以得到以下3个信息, .cb不用自己填写了, .lpDesktop可以得到主程序的桌面位置
/*
cb 104 unsigned long
+ lpReserved 0x0000016952ea535c L"" wchar_t *
+ lpDesktop 0x0000016952ea533c L"Winsta0\\Default" wchar_t *
+ lpTitle 0x0000016952ea5212 L"D:\\...\\xParser.exe" wchar_t *
其他值还是0
*/
startupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
startupInfo.wShowWindow = SW_HIDE;
startupInfo.lpReserved = NULL;
startupInfo.cbReserved2 = 0;
startupInfo.lpReserved2 = NULL;
// startupInfo.cb = sizeof(startupInfo);
int nStrBuffer = cmdLine.GetLength();
// printf("%ws\n", cmdLine.GetString());
// !!! 如果参数5加了 CREATE_NEW_CONSOLE, 就会出现dos窗口
// cmdLine.GetBuffer(), cmdLine.GetBuffer(nStrBuffer) 返回的指针地址都一样
BOOL result = CreateProcess(NULL, cmdLine.GetBuffer(nStrBuffer),
NULL, NULL, FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW /* | CREATE_NEW_CONSOLE */,
NULL, NULL, &startupInfo, &processInformation);
cmdLine.ReleaseBuffer();
if (!result) {
// CreateProcess() failed
// Get the error from the system
LPVOID lpMsgBuf;
DWORD dw = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);
// Display the error
CString strError = (LPTSTR)lpMsgBuf;
TRACE(_T("::executeCommandLine() failed at CreateProcess()\nCommand=%s\nMessage=%s\n\n"), cmdLine, strError);
// Free resources created by the system
LocalFree(lpMsgBuf);
// We failed.
return FALSE;
}
else {
// Successfully created the process. Wait for it to finish.
WaitForSingleObject(processInformation.hProcess, INFINITE);
// Get the exit code.
result = GetExitCodeProcess(processInformation.hProcess, &exitCode);
// Close the handles.
CloseHandle(processInformation.hProcess);
CloseHandle(processInformation.hThread);
if (!result) {
// Could not get exit code.
TRACE(_T("Executed command but couldn't get exit code.\nCommand=%s\n"), cmdLine);
return FALSE;
}
// We succeeded.
return TRUE;
}
}
动态载入DLL的实现 - LateLoad.h
在做动态载入DLL时, 翻出以前在开源工程基础上改的实现, 还是那么好用.
作为研发, 平时做些奇怪没用的小实验, 只要归档了, 以后还是能用上的. 力气不白费.
修正了原版9个参数的动态调用函数定义.
增加了10~12个参数的动态函数定义.
#ifndef __LATE_LOAD__H__
#define __LATE_LOAD__H__
#if _MSC_VER > 1000
#pragma once
#endif
#include <windows.h>
#include <crtdbg.h>
/**
* @note LostSpeed modify at 2011_1127_0327
* update to fit unicode
* fix error on LATELOAD_FUNC_9_VOID
* add LATELOAD_FUNC_10, LATELOAD_FUNC_11, LATELOAD_FUNC_12
* add LATELOAD_FUNC_11_VOID, LATELOAD_FUNC_11_VOID, LATELOAD_FUNC_12_VOID
*/
/*
Module : LateLoad.h
Purpose: I was tired of constantly re-writing LoadLibrary & GetProcAddress code,
over & over & over again. So I created a series of macros that will
define & create a wrapper class to do it all for me.
This is NOT an end-all-be-all solution for loading DLLs. This is just a
handy lightweight helper when you would use LoadLibrary/GetProcAddress.
For more information on DLLs, check out MSDN.
This was inspired by my own need, as well as a nice little MSDN article
titled "DLLs the Dynamic Way" by "MicHael Galkovsky"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndllpro/html/dlldynamic.asp
Unfortunatly, there was no source to go with the article. So, I wrote this
version quite a bit differently.
Author : Copyright (c) 2004 by Jason De Arte, All Rights Reserved.
Site : http://1001010.com/code/
License: Use it however you like as a compiled portion of your product(s).
Don't be a jerk by claiming the it as your own.
Usage : The following will declare the class "CUser32Wrapper" that will load
function pointer(s) from USER32.DLL. Those function names will become
member function(s) of the newly created class.
LATELOAD_BEGIN_CLASS(CUser32Wrapper,user32,FALSE)
LATELOAD_FUNC_0(NULL,HCURSOR,WINAPI,GetCursor)
LATELOAD_FUNC_1(NULL,HANDLE,WINAPI,NonExistantFunction,BOOL)
LATELOAD_END_CLASS()
// The above statements will auto-generate a class that functionaly equivalent to...
class CUser32Wrapper : public CLateLoadBase
{
public:
BOOL Is_GetCursor();
HCURSOR WINAPI GetCursor();
BOOL Is_NonExistantFunction();
HANDLE WINAPI NonExistantFunction();
};
// And usage is even easier
CUser32Wrapper uw;
HCURSOR h = uw.GetCursor();
// And for DLLs missing a function export, you can still use the member function!
uw.NonExistantFunction(true);
// It will just return the default non-existant value in the definition
// To determine if the funtion was imported, use the "BOOL Is_<FunctionName>();" member
Is_NonExistantFunction();
// If it exists, it will return TRUE. False if it does not exist
-------------------------------------------
Let's look at the various defines that are used...
LATELOAD_BEGIN_CLASS(CUser32Wrapper,user32,FALSE)
CUser32Wrapper - the class that will be created
user32 - the library that will be loaded
FALSE - determines if "FreeLibrary()" will be called in the destructor.
LATELOAD_FUNC_0(NULL,HCURSOR,WINAPI,GetCursor)
NULL - if the ProcAddress was not loaded, this value is returned in the call to that func
HCURSOR - the return type for the function
WINAPI - function calling convention
GetCursor - the exported function
LATELOAD_FUNC_1 (up to _9)
Identical to LATELOAD_FUNC_0, except it allows 1-9 parameters to the function
LATELOAD_FUNC_0_ (up to _9)
Same as before, but for use with NULL return types
LATELOAD_END_CLASS()
finalizes the class declaration
-------------------------------------------
History:
2004.Feb.29.JED - Created
*/
//
// Used for keeping track
//
enum ImportedProcState
{
ipsUnknown = 0, // No attempts to load the Proc have been made yet
ipsMissing, // GetProcAddress failed to find the exported function
ipsAvailable, // the Proc is Ready & Available for use
ips_MAX
};
#ifndef NO_VTABLE
# if _MSC_VER > 1000
# define NO_VTABLE __declspec(novtable)
# else
// 2004.Feb.29.JED - Note to self, find out what is appropriate under non-msvc compilers
//# define NO_VTABLE
# endif //_MSC_VER
#endif
//
// Declaration for the utility base class, not intended for non-inherited use.
//
class NO_VTABLE CLateLoadBase
{
//
// Why no v-table?
// 1) not needed
// 2) reduces code size
// 3) LATELOAD_BEGIN_CLASS calls ZeroMemory to blank out all the derived function
// pointers & ImportedProcState memeber variables - in the process the vtable
// will get blanked out.
// 4) This class is not intended to be instantiated on its own.
// 5) Makes it so that using this class on its own will cause an Access Violation
//
protected:
HMODULE m_module; // Handle to the DLL
DWORD m_dwLoadLibError; // If there was an error from LoadLibrary
BOOL m_bManaged; // FreeLibrary in the destructor?
LPTSTR m_pszModule; // The name of the module, handy for first-use loading
/*****************************************************************************
* NAME:
* CLateLoadBase::dll_LoadLibrary
*
* DESCRIPTION:
* Loads the dll.
*
*******************************************************************************/
protected:
BOOL dll_LoadLibrary(LPCTSTR pszLibrary, BOOL bDoItNow)
{
//
// Make a record of the DLL name
//
if( !m_pszModule )
{
if( pszLibrary && *pszLibrary)
{
int nLen = lstrlen(pszLibrary);
m_pszModule = new TCHAR[nLen+2];
if( m_pszModule )
{
ZeroMemory( m_pszModule, sizeof(TCHAR)*(nLen+2) );
lstrcpy(m_pszModule,pszLibrary);
}
else
{
_ASSERT(!"CLateLoadBase::dll_LoadLibrary - Unable to allocate memory for a string!");
}
}
else
{
_ASSERT(!"CLateLoadBase::dll_LoadLibrary - We need a valid pszLibrary string");
}
}
// Nothing to do?
if( m_module )
return TRUE;
// Should we do this later?
if( !bDoItNow )
return FALSE;
// Load the DLL
m_dwLoadLibError = 0;
m_module = ::LoadLibrary(pszLibrary);
if( m_module )
return TRUE;
// Unable to load it, find out why
m_dwLoadLibError = GetLastError();
// We rely on the last error being not equal to zero on LoadLibrary failure.
// So, in the off chance it IS zero, we set it to a non-zero value.
// Tip: According to MSDN, Bit 29 in Get/SetLastError logic is reserved for Application
// defined error codes. No system level error codes should have this bit set.
if( !m_dwLoadLibError )
{
_ASSERT(!"Wow, that should NOT have happened! Could you tell JED how you did it?");
m_dwLoadLibError = 0x20000000;
}
return FALSE;
}
/*****************************************************************************
* NAME:
* CLateLoadBase::dll_GetProcAddress
*
* DESCRIPTION:
* Loads the function pointer from the DLL
*
*******************************************************************************/
protected:
FARPROC dll_GetProcAddress(LPCSTR pszFunctionName, ImportedProcState& ips)
{
FARPROC pfn = NULL;
ips = ipsUnknown;
// Does the DLL still need to be loaded?
if( !m_module && m_pszModule && *m_pszModule &&
0 == m_dwLoadLibError // There is no reason to attempt to load the DLL more than once
)
{
dll_LoadLibrary(m_pszModule,TRUE);
}
if( m_module )
{
pfn = ::GetProcAddress(m_module,pszFunctionName);
if( pfn )
ips = ipsAvailable;
else
ips = ipsMissing;
}
return pfn;
}
/*****************************************************************************
* NAME:
* CLateLoadBase::~CLateLoadBase
*
* DESCRIPTION:
* Description goes here...
*
*******************************************************************************/
public:
~CLateLoadBase()
{
if( m_bManaged && m_module )
::FreeLibrary(m_module);
m_module = NULL;
m_bManaged = FALSE;
if( m_pszModule )
delete m_pszModule;
m_pszModule = NULL;
}
/*****************************************************************************
* NAME:
* CLateLoadBase::dll_GetLoadError
*
* DESCRIPTION:
* If LoadLibrary failed, returns the error code.
* If there was no error, returns zero
*
*******************************************************************************/
public:
DWORD dll_GetLoadError()
{
return m_dwLoadLibError;
}
/*****************************************************************************
* NAME:
* CLateLoadBase::dll_IsLoaded
*
* DESCRIPTION:
* Is the DLL loaded?
*
*******************************************************************************/
public:
BOOL dll_IsLoaded()
{
return NULL!=m_module;
}
/*****************************************************************************
* NAME:
* CLateLoadBase::dll_GetModuleName
*
* DESCRIPTION:
* return the name of the module loaded
*
*******************************************************************************/
public:
LPCTSTR dll_GetModuleName()
{
return (LPCTSTR)m_pszModule;
}
};
//--------------------------------------------------------------------------------------
//
// Start of macros
//
//--------------------------------------------------------------------------------------
//
// Start, Declares the name of the class
//
// ClassName = the name of the class
// ModuleName = the DLL name
// bLoadDllNow = if true, the DLL will be loaded in the constructor.
// if false, it will ONLY be loaded when any bound function is first used
// bManaged = if true, FreeLibrary will be called in the destructor
//
#define LATELOAD_BEGIN_CLASS(ClassName,ModuleName,bLoadDllNow,bManaged) \
class ClassName : public CLateLoadBase \
{ \
public:\
ClassName()\
{\
/*Automagicaly blank out all the function pointers and ImportedProcState member vars*/ \
/*that will be declared in following LATELOAD_FUNC_* declarations, very handy. */ \
ZeroMemory(static_cast<ClassName*>(this),sizeof(ClassName)); \
m_bManaged = bManaged; \
/*and load the DLL*/ \
dll_LoadLibrary(_T(#ModuleName),bLoadDllNow); \
}
//
// Function Declaration, Zero Parameters, returns a value
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType, type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName, Name of the function
//
// A function prototype that looked like...
// typedef BOOL (CALLBACK* SOMETHING)();
// or
// BOOL CALLBACK Something();
//
// Would be changed to...
// LATELOAD_FUNC_0(0,BOOL,CALLBACK,Something)
//
// If "Something" could not be loaded, and it was called - it would return 0
//
#define LATELOAD_FUNC_0(ErrorResult,ReturnType,CallingConv,FuncName) \
protected: \
typedef ReturnType(CallingConv * TYPE_##FuncName)(); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
ReturnType FuncName() \
{\
if( !Is_##FuncName() ) \
return ErrorResult; \
return m_pf##FuncName(); \
}
//
// Function Declaration, One Parameter, returns a value
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType, type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
// A function prototype that looked like...
// typedef BOOL (CALLBACK* SOMETHING)(BOOL);
// or
// BOOL CALLBACK Something(BOOL bEnable);
//
// Would be changed to...
// LATELOAD_FUNC_1(0,BOOL,CALLBACK,Something,BOOL)
//
// If "Something" could not be loaded, and it was called - it would return 0
//
#define LATELOAD_FUNC_1(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1) \
protected: \
typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
ReturnType FuncName(ParamType1 p1) \
{\
if( !Is_##FuncName() ) \
return ErrorResult; \
return m_pf##FuncName(p1); \
}
//
// Function Declaration, Two Parameters, returns a value
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType, type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
// A function prototype that looked like...
// typedef BOOL (CALLBACK* SOMETHING)(BOOL,INT);
// or
// BOOL CALLBACK Something(BOOL bEnable, INT nNum);
//
// Would be changed to...
// LATELOAD_FUNC_2(0,BOOL,CALLBACK,Something,BOOL,INT)
//
// If "Something" could not be loaded, and it was called - it would return 0
//
#define LATELOAD_FUNC_2(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2) \
protected: \
typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
ReturnType FuncName(ParamType1 p1,ParamType2 p2) \
{\
if( !Is_##FuncName() ) \
return ErrorResult; \
return m_pf##FuncName(p1,p2); \
}
//
// Function Declaration, Three Parameters, returns a value
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType, type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
#define LATELOAD_FUNC_3(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3) \
protected: \
typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3) \
{\
if( !Is_##FuncName() ) \
return ErrorResult; \
return m_pf##FuncName(p1,p2,p3); \
}
//
// Function Declaration, Four Parameters, returns a value
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType, type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
#define LATELOAD_FUNC_4(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4) \
protected: \
typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4) \
{\
if( !Is_##FuncName() ) \
return ErrorResult; \
return m_pf##FuncName(p1,p2,p3,p4); \
}
//
// Function Declaration, Five Parameters, returns a value
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType, type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
#define LATELOAD_FUNC_5(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5) \
protected: \
typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5) \
{\
if( !Is_##FuncName() ) \
return ErrorResult; \
return m_pf##FuncName(p1,p2,p3,p4,p5); \
}
//
// Function Declaration, Six Parameters, returns a value
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType, type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
#define LATELOAD_FUNC_6(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6) \
protected: \
typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6) \
{\
if( !Is_##FuncName() ) \
return ErrorResult; \
return m_pf##FuncName(p1,p2,p3,p4,p5,p6); \
}
//
// Function Declaration, Seven Parameters, returns a value
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType, type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
#define LATELOAD_FUNC_7(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7) \
protected: \
typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7) \
{\
if( !Is_##FuncName() ) \
return ErrorResult; \
return m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7); \
}
//
// Function Declaration, Eight Parameters, returns a value
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType, type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
#define LATELOAD_FUNC_8(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8) \
protected: \
typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7,ParamType8 p8) \
{\
if( !Is_##FuncName() ) \
return ErrorResult; \
return m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7,p8); \
}
//
// Function Declaration, Nine Parameters, returns a value
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType, type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
#define LATELOAD_FUNC_9(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9) \
protected: \
typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7,ParamType8 p8,ParamType9 p9) \
{\
if( !Is_##FuncName() ) \
return ErrorResult; \
return m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7,p8,p9); \
}
#define LATELOAD_FUNC_10(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9,ParamType10) \
protected: \
typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9,ParamType10); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7,ParamType8 p8,ParamType9 p9,ParamType10 p10) \
{\
if( !Is_##FuncName() ) \
return ErrorResult; \
return m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10); \
}
#define LATELOAD_FUNC_11(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9,ParamType10,ParamType11) \
protected: \
typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9,ParamType10,ParamType11); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7,ParamType8 p8,ParamType9 p9,ParamType10 p10,ParamType11 p11) \
{\
if( !Is_##FuncName() ) \
return ErrorResult; \
return m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11); \
}
#define LATELOAD_FUNC_12(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9,ParamType10,ParamType11,ParamType12) \
protected: \
typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9,ParamType10,ParamType11,ParamType12); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7,ParamType8 p8,ParamType9 p9,ParamType10 p10,ParamType11 p11,ParamType12 p12) \
{\
if( !Is_##FuncName() ) \
return ErrorResult; \
return m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12); \
}
//
// Function Declaration, Zero Parameters, returns nothing
//
// CallingConv, Calling convention of the function
// FuncName, Name of the function
//
// A function prototype that looked like...
// typedef VOID (CALLBACK* SOMETHING)();
// or
// VOID CALLBACK Something();
//
// Would be changed to...
// LATELOAD_FUNC_0_VOID(CALLBACK,Something)
//
#define LATELOAD_FUNC_0_VOID(CallingConv,FuncName) \
protected: \
typedef void(CallingConv * TYPE_##FuncName)(); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
void FuncName() \
{\
if( Is_##FuncName() ) \
m_pf##FuncName(); \
}
//
// Function Declaration, One Parameters, returns nothing
//
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
// A function prototype that looked like...
// typedef VOID (CALLBACK* SOMETHING)(BOOL);
// or
// VOID CALLBACK Something(BOOL bEnable);
//
// Would be changed to...
// LATELOAD_FUNC_1_VOID(CALLBACK,Something,BOOL)
//
#define LATELOAD_FUNC_1_VOID(CallingConv,FuncName,ParamType1) \
protected: \
typedef void(CallingConv * TYPE_##FuncName)(ParamType1); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
void FuncName(ParamType1 p1) \
{\
if( Is_##FuncName() ) \
m_pf##FuncName(p1); \
}
//
// Function Declaration, Two Parameters, returns nothing
//
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
// A function prototype that looked like...
// typedef VOID (CALLBACK* SOMETHING)(BOOL,INT);
// or
// VOID CALLBACK Something(BOOL bEnable, INT nNumber);
//
// Would be changed to...
// LATELOAD_FUNC_2_VOID(CALLBACK,Something,BOOL,INT)
//
#define LATELOAD_FUNC_2_VOID(CallingConv,FuncName,ParamType1,ParamType2) \
protected: \
typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
void FuncName(ParamType1 p1,ParamType2 p2) \
{\
if( Is_##FuncName() ) \
m_pf##FuncName(p1,p2); \
}
//
// Function Declaration, Three Parameters, returns nothing
//
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
#define LATELOAD_FUNC_3_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3) \
protected: \
typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3) \
{\
if( Is_##FuncName() ) \
m_pf##FuncName(p1,p2,p3); \
}
//
// Function Declaration, Four Parameters, returns nothing
//
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
#define LATELOAD_FUNC_4_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4) \
protected: \
typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4) \
{\
if( Is_##FuncName() ) \
m_pf##FuncName(p1,p2,p3,p4); \
}
//
// Function Declaration, Five Parameters, returns nothing
//
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
#define LATELOAD_FUNC_5_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5) \
protected: \
typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5) \
{\
if( Is_##FuncName() ) \
m_pf##FuncName(p1,p2,p3,p4,p5); \
}
//
// Function Declaration, Six Parameters, returns nothing
//
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
#define LATELOAD_FUNC_6_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6) \
protected: \
typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6) \
{\
if( Is_##FuncName() ) \
m_pf##FuncName(p1,p2,p3,p4,p5,p6); \
}
//
// Function Declaration, Seven Parameters, returns nothing
//
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
#define LATELOAD_FUNC_7_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7) \
protected: \
typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7) \
{\
if( Is_##FuncName() ) \
m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7); \
}
//
// Function Declaration, Eight Parameters, returns nothing
//
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
#define LATELOAD_FUNC_8_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8) \
protected: \
typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7,ParamType8 p8) \
{\
if( Is_##FuncName() ) \
m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7,p8); \
}
//
// Function Declaration, Nine Parameters, returns nothing
//
// CallingConv, Calling convention of the function
// FuncName, Name of the function
// ParamN types of the function parameters
//
#define LATELOAD_FUNC_9_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9) \
protected: \
typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7,ParamType8 p8,ParamType9 p9) \
{\
if( Is_##FuncName() ) \
m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7,p8,p9); \
}
#define LATELOAD_FUNC_10_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9,ParamType10) \
protected: \
typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9,ParamType10); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7,ParamType8 p8,ParamType9 p9,ParamType10 p10) \
{\
if( Is_##FuncName() ) \
m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10); \
}
#define LATELOAD_FUNC_11_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9,ParamType10,ParamType11) \
protected: \
typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9,ParamType10,ParamType11); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7,ParamType8 p8,ParamType9 p9,ParamType10 p10,ParamType11 p11) \
{\
if( Is_##FuncName() ) \
m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11); \
}
#define LATELOAD_FUNC_12_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9,ParamType10,ParamType11,ParamType12) \
protected: \
typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9,ParamType10,ParamType11,ParamType12); \
TYPE_##FuncName m_pf##FuncName; \
ImportedProcState m_ips##FuncName;\
public: \
BOOL Is_##FuncName() \
{ \
if(ipsUnknown == m_ips##FuncName) \
m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
return(ipsAvailable == m_ips##FuncName); \
} \
void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7,ParamType8 p8,ParamType9 p9,ParamType10 p10,ParamType11 p11,ParamType12 p12) \
{\
if( Is_##FuncName() ) \
m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12); \
}
//
// End of the class
//
#define LATELOAD_END_CLASS() };
#endif //__LATE_LOAD__H__
END
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!