Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >HGE系列之六 管中窥豹(资源管理)

HGE系列之六 管中窥豹(资源管理)

作者头像
用户2615200
发布于 2018-08-02 09:34:35
发布于 2018-08-02 09:34:35
4220
举报

HGE系列之六 管中窥豹(资源管理)

记的上次浮光掠影的讲了一些HGE中的基础类别,不知大家了解了多少,仔细看过的朋友肯定知道当时在讲述一个类别的构造函数时我打了个马虎,直接略过了,原因说的好像是比较繁琐,想起来了吗?对,就是 hgeStringTable ,为了免去“避重就轻”的嫌疑,我想这次也该好好的将他说一说了(但说实话,讲解这个函数确实比较繁琐……),而 hgeStringTable 是HGE资源管理中的一个基础(Base)类别,所以我想顺着讲述一下HGE的资源管理实现,相信这种叙述顺序还是比较符合逻辑的 :)不过在开始我们又一次HGE源码之旅时,我必须提醒一句:这次旅行可没上次那般轻松惬意了……什么,你不相信?那么不妨来看看我们旅程的“第一站”,也就是那个 hgeStringTable “神秘”的构造函数吧:

hgeStringTable::hgeStringTable(const char *filename)

{

// 一些变量声明

int i;

void *data;

DWORD size;

char *desc, *pdesc;

// 上次分析过的 NamedString 结构

NamedString *str;

char str_name[MAXSTRNAMELENGTH];

char *str_value, *pvalue;

// 创建HGE

hge=hgeCreate(HGE_VERSION);

// 设置链表头结点为空

strings=0;

// 使用HGE提供的Resource_Load接口加载文件

// 注意返回的 void* 指针所指向的便是文件中的内容

// 相关文件大小则存放在size中

data=hge->Resource_Load(filename, &size);

// 如果data为空,则加载失败,直接返回

if(!data) return;

// 将文件内容全部拷贝至动态申请的desc数组中,以进行之后的解析

desc = new char[size+1];

memcpy(desc,data,size);

desc[size]=0;

// 释放由之前Resource_Load函数分配的内存(即data所指向的区域)

hge->Resource_Free(data);

// 查看文件头(是否是“[HGESTRINGTABLE]”)

if(memcmp(desc, STRHEADERTAG, sizeof(STRHEADERTAG)-1))

{

// 如果不是则使用System_Log接口将错误记录至日志文件

// 并释放之前分配的desc资源

hge->System_Log(STRFORMATERROR, filename);

delete[] desc;

return;

}

// 将pdesc设置为desc偏移sizeof(STRHEADERTAG)位置,即实际的数据位置

pdesc=desc+sizeof(STRHEADERTAG);

// 用于存储字符串值的动态数组

str_value=new char[8192];

for(;;)

{

// 跳过空白

while(isspace(*pdesc)) pdesc++;

// 如果pdesc指向元素为空('/0'),则跳出循环

if(!*pdesc) break;

// 跳过注释,即以 ';' 开头的行

if(*pdesc==';')

{

while(*pdesc && *pdesc != '/n') pdesc++;

pdesc++;

continue;

}

// 获取字符串的名字

i=0;

// 注意循环条件

while(pdesc[i] && pdesc[i]!='=' && !isspace(pdesc[i]) && i<MAXSTRNAMELENGTH)

{

str_name[i]=pdesc[i];

i++;

}

// 设置字符串结束符

str_name[i]=0;

// 当然,不能忘了设置pdesc的偏移

pdesc+=i;

// 由于有 MAXSTRNAMELENGTH 的字符串名称长度限制,

// 所以需要处理超出的名称字符

while(*pdesc && *pdesc!='=' && !isspace(*pdesc)) pdesc++;

if(!*pdesc) break;

// 跳过 '=' 之前的空白符号

while(isspace(*pdesc)) pdesc++;

// 如果所指不是 '=' ,那么调用Sysytem_Log记录至日志文件,并跳出循环

if(*pdesc!='=') { hge->System_Log(STRFORMATERROR, filename); break; }

pdesc++;

// 跳过 ' " ' 符号之前的空格

while(isspace(*pdesc)) pdesc++;

// 如果所指不是 ' " ', 那么调用Sysytem_Log记录至日志文件,并跳出循环

if(*pdesc!='"') { hge->System_Log(STRFORMATERROR, filename); break; }

pdesc++;

// 解析字符串的实际内容(至最后的 ' " ' 符号)

// 注意一下特殊符号的处理

pvalue=str_value;

// 注意一下循环条件

while(*pdesc && *pdesc!='"')

{

// 处理 '/n' 以及 '/r'

if(*pdesc=='/n' || *pdesc=='/r')

{

while(isspace(*pdesc)) pdesc++;

pvalue--;

while(pvalue>=str_value && isspace(*pvalue)) pvalue--;

pvalue++; *pvalue=' '; pvalue++;

continue;

}

// 处理 '/' 转义字符

if(*pdesc=='//')

{

pdesc++;

if(!*pdesc) continue;

if(*pdesc=='n') *pvalue='/n';

else *pvalue=*pdesc;

pvalue++;

pdesc++;

continue;

}

// 将pdesc的内容复制入 pvalue 中

*pvalue=*pdesc; pvalue++;

pdesc++;

}

// 设置结束标志

*pvalue=0;

// 至此我们已经成功解析了一个字符串“定义”,将其添加入链表中(链表头部)

str=new NamedString;

strcpy(str->name, str_name);

str->string=new char[strlen(str_value)+1];

strcpy(str->string, str_value);

str->next=strings;

strings=str;

if(!*pdesc) break;

pdesc++;

}// end of for(;;)

// 不要忘了释放缓存资源

delete[] str_value;

delete[] desc;

}

呼,终于将这个“庞大”的构造函数注释完了,相信大家看的也是够呛,如果实在看的不是太清晰,那也没有多大关系,我再来提纲挈领的讲一讲:

一开始,构造函数调用HGE提供的资源加载接口加载文件资源,然后程序开始解析,首先他会检查该文件是否拥有名为HGESTRINGTABLE 的字段(section),接着他开始解析实际的字符串定义,相应格式为:

字符串名 = "字符串值"

然后么自然将解析的结果构造成一个NamedString,然后添加入链表。接着便是重复执行,知道内容结束。

大体流程就是这样,如果你还不满意,那就请自行研习源码吧,我的讲解便到此为止了,因为我讲述这个函数的目的并不是想细究其每个细节,然后学以致用,恰恰相反,我的目的是“学以不用”,是的,你没有看错,的确是“学以不用”:

首先,这个函数过于“庞大”,这便造成了可读性上的大打折扣(相信你已经有所体会……)以及非常差的可维护性(你可以试试走一走程序的控制流……)

再者,该函数的逻辑相对复杂,本应该将个中功能分解至单一函数来进行一一处理,然而目前的情况却是一股脑儿的凑成了一大碗意大利面条……

最后,程序的目的是解析一种相关的配置文件格式,然而这种格式是完全可以与 hgeStringTable 类相分离的,也就是说,处理这类配置文件的功能完全可以抽象出来形成另外一个辅助类(helper),大可不必写成现在的这幅模样……

所以总的说来,这个函数是一个非常鲜明生动的“反面教材” :)

至此,虽然有些不敢苟同,但hgeStringTable 终算是讲解完毕了,那么稍稍缓口气,让我们继续向 HGE 资源管理模块迈进 :

类名:ResDesc

功能:资源描述类

头文件:hge/hge181/include/hgeresource.h

实现文件:无

老方法,让我们首先来看一看他的头文件:

struct ResDesc

{

// 资源名称

char name[MAXRESCHARS];

// 所属资源的组号

int resgroup;

// 资源“句柄”

DWORD handle;

// 自向指针(看来大抵上又是用来构成单链表的)

ResDesc* next;

// 相对简易的构造函数和析构函数

ResDesc() { hge=hgeCreate(HGE_VERSION); }

~ResDesc() { hge->Release(); }

// 获取资源“句柄”,注意参数

virtual DWORD Get(hgeResourceManager *rm) = 0;

// 释放资源

virtual void Free() = 0;

protected:

// 静态的HGE指针

static HGE *hge;

};

很明显,ResDesc是一个纯虚类,程序中是不能创建该类的对象的,一般而言这种类别也仅是作为基类,然后进行派生,考虑到该类别是一个资源描述类,那么自然想到是不是HGE中的各类资源都继承于他呢?如果你也是这么考虑的,那么恭喜你,回答正确,加十分!

但就目前而言,我们对于这个类别中的一些细节还是有些模糊,譬如Get函数(或者说接口)中的 hgeResourceManager ,好吧,为了解决这些疑问,让我们继续看下去:

类名:hgeResourceManager

功能:资源管理类

头文件:hge/hge181/include/hgeresource.h

实现文件:hge/hge181/src/helpers/hgeresource.cpp

首先来看看他的头文件:

class hgeResourceManager

{

public:

hgeResourceManager(const char *scriptname=0);

~hgeResourceManager();

// 变换资源脚本

void ChangeScript(const char *scriptname=0);

// 查看给定组别资源是否已经缓存

bool Precache(int groupid=0);

// 清除指定资源号的资源

void Purge(int groupid=0);

// 通用的获取资源函数,注意返回类型为 void*

void* GetResource(const char *name, int resgroup=0);

// 获取资源句柄的函数“群”

HTEXTURE GetTexture(const char *name, int resgroup=0);

HEFFECT GetEffect(const char *name, int resgroup=0);

HMUSIC GetMusic(const char *name, int resgroup=0);

HSTREAM GetStream(const char *name, int resgroup=0);

HTARGET GetTarget(const char *name);

// 获取相关资源的函数“群”

hgeSprite* GetSprite(const char *name);

hgeAnimation* GetAnimation(const char *name);

hgeFont* GetFont(const char *name);

hgeParticleSystem* GetParticleSystem(const char *name);

hgeDistortionMesh* GetDistortionMesh(const char *name);

hgeStringTable* GetStringTable(const char *name, int resgroup=0);

// 资源描述的指针数组

ResDesc* res[RESTYPES];

private:

// 将拷贝构造函数设置为私有,以起到禁用拷贝构造的作用

hgeResourceManager(const hgeResourceManager &);

// 将 赋值 操作设置为私有,以起到“屏蔽”作用

hgeResourceManager& operator= (const hgeResourceManager&);

// 私有的辅助函数

// 移除所有资源

void _remove_all();

// 解析资源脚本

void _parse_script(const char *scriptname=0);

static HGE *hge;

};

看来hgeResourceManager的定义还是比较清晰的,让我们一次来看一看个中函数的实现方法:

首先自然是其的构造函数与析构函数:

hgeResourceManager::hgeResourceManager(const char *scriptname)

{

// 创建HGE

hge=hgeCreate(HGE_VERSION);

// 初始化res数组

for(int i=0;i<RESTYPES;i++) res[i]=0;

// 解析给定的资源脚本

_parse_script(scriptname);

}

hgeResourceManager::~hgeResourceManager()

{

// 释放所有的资源

_remove_all();

// 释放HGE

hge->Release();

}

看来这两个函数还是比较简易的,一个加载,一个释放,比较“中规中矩” :)

那么至此,对于hgeResourceManager的数据结构模型,大家应该能够想像了:

大体上便是这副样子:

接着,然我们顺着来看一看构造函数和析构函数中涉及的_parse_script和_remove_all

void hgeResourceManager::_parse_script(const char *scriptname)

{

ResDesc *rc, *rcnext;

// 如果资源脚本名不为空

if(scriptname)

{

// 使用了RScript函数的Parse函数进行解析

RScript::Parse(this, NULL, scriptname, NULL);

// 释放res[RES_SCRIPT]

rc=res[RES_SCRIPT];

while(rc)

{

rc->Free();

rcnext=rc->next;

delete rc;

rc=rcnext;

}

res[RES_SCRIPT]=0;

}

}

其中RES_SCRIPT是一个宏定义,位于hge/hge181/src/helpers/resources.h

#define RES_SCRIPT 0

另外值得一提的是,该文件中另外还定义了其他的资源类别,有兴趣的朋友可以看一看。

_parse_script函数中除了一个目前对我们来说还是“黑盒”的RScript::Parse外,对于res[RES_SCRIPT](即res[0])的处理也是有些令人费解,不过我们大可不必在此过分纠结,与其停步苦思冥想,不如继续前行,说不定马上会豁然开朗 :)

void hgeResourceManager::_remove_all()

{

int i;

ResDesc *rc, *rcnext;

// 释放从res[0] 至res[RESTYPES] 链表资源

for(i=0;i<RESTYPES;i++)

{

rc=res[i];

while(rc)

{

rc->Free();

rcnext=rc->next;

delete rc;

rc=rcnext;

}

res[i]=0;

}

}

看来 _remove_all 也是不出所料啊,依次遍历并释放资源 :)

接着让我们看看析构函数之后的三个公有函数:

// 变换资源脚本

void hgeResourceManager::ChangeScript(const char *scriptname)

{

_remove_all();

_parse_script(scriptname);

}

不出所料,首先释放,然后便是重新加载

// 查看给定的组别资源是否已经缓存(有效),如果groupid为0则检查所有组别

bool hgeResourceManager::Precache(int groupid)

{

int i;

ResDesc *rc;

bool bResult=true;

// 遍历res[0] 到 res[RESTYPES-1]

for(i=0;i<RESTYPES;i++)

{

rc=res[i];

while(rc)

{

// 注意条件的判断

if(!groupid || groupid==rc->resgroup) bResult=bResult && (rc->Get(this)!=0);

rc=rc->next;

}

}

return bResult;

}

// 清除给定组别的资源,如果groupid为0则清除所有组别

void hgeResourceManager::Purge(int groupid)

{

int i;

ResDesc *rc;

// 遍历res[0] 到 res[RESTYPES-1]

for(i=0;i<RESTYPES;i++)

{

rc=res[i];

while(rc)

{

// 注意条件判断

if(!groupid || groupid==rc->resgroup) rc->Free();

rc=rc->next;

}

}

}

好了,看来这三个函数也并不复杂,接下来剩下的便是一堆获取资源函数,让我们首先来看看其中的GetStringTable,没有错,就是获取字符串表的函数,由于目前来讲我们对于hgeStringTable这个类别比较熟悉,以此函数开始阅览,相信能让我们更快的找到关键点(key point):

hgeStringTable* hgeResourceManager::GetStringTable(const char *name, int resgroup)

{

hgeStringTable *strtable;

RStringTable *resource;

// 使用FindRes函数来查找给定的资源名称

ResDesc *Res=FindRes(this, RES_STRTABLE, name);

// 如果找到,则返回

if(Res) return (hgeStringTable*)Res->Get(this);

// 没有找到

else

{

// 以name新建一个hgeStringTable

strtable=new hgeStringTable(name);

// 如果(加载)成功

if(strtable)

{

// 新建一个RStringTable类型

resource=new RStringTable();

// 设置资源句柄

resource->handle=(DWORD)strtable;

// 设置资源组别

resource->resgroup=resgroup;

// 设置资源名称

strcpy(resource->name, name);

// 设置RStringTable的资源脚本名称,与其资源名称相同

strcpy(resource->filename, name);

// 通过AddRes函数增加资源

AddRes(this, RES_STRTABLE, resource);

return strtable;

}

}

return 0;

}

这个函数看起来有点磕碰,首先我们便遇到了一个没见过的类型:RStringTable,查看代码,其实他就是一个之前ResDesc类别的派生类:

类名:RStringTable

功能:字符串表资源类

头文件:hge/hge181/ src/helpers/resources.h

实现文件:hge/hge181/src/helpers/resources.cpp

struct RStringTable : public ResDesc

{

char filename[MAXRESCHARS];

static void Parse(hgeResourceManager *rm, RScriptParser *sp, const char *name, const char *basename);

virtual DWORD Get(hgeResourceManager *rm);

virtual void Free();

};

相当简单,实现了Get和Free两个自ResDesc继承而来的纯虚函数,并且添加了名为filename的数据成员以及一个静态的Parse函数,然我们就势来看看他们的实现:

DWORD RStringTable::Get(hgeResourceManager *rm)

{

// 如果handle为空,则直接新建返回hgeStringTable(filename)

if(!handle) handle = (DWORD)new hgeStringTable(filename);

// 否则直接返回

return handle;

}

void RStringTable::Free()

{

// 如果handle不为空,则使用delete删除

if(handle) delete (hgeStringTable *)handle;

handle=0;

}

Get和Free看来还是相当简易的,那么那个静态的Parse呢?

void RStringTable::Parse(hgeResourceManager *rm, RScriptParser *sp, const char *name, const char *basename)

{

ScriptParseFileResource(rm, sp, name, basename, new RStringTable(), RES_STRTABLE);

}

可以看到,Parse函数只是一个对ScriptParseFileResource 的简单调用,那么ScriptParseFileResource有时那个函数呢?不用急,其实他也位于hge/hge181/src/helpers/resources.cpp 中,但是对他讲解我们会一下子牵扯到其他许多我们未有接触的内容,所以我在此先暂时放一放,留作下次讲解(当然,如果你实在等不及,那还是那句老话,请打开文件自己观赏……)

好了,然我们回到GetStringTable的讲解( 是不是有点像堆栈调用:) ),现在我们已经大体上了解了一下RStringTable,但接着我们又遇到了一个没见过的函数:FindRes,他又是怎么一回事呢?其实顾名思义,我们也基本能够猜出这个函数的作用:定位资源,但是他的定义又在哪里呢?其实他也在hge/hge181/src/helpers/resources.cpp中,让我们来看一下:

ResDesc *FindRes(hgeResourceManager *rm, int type, const char *name)

{

ResDesc *rc;

// 首先定位组别资源

rc=rm->res[type];

while(rc)

{

// 比较资源名称,如果相同则返回

if(!strcmp(name, rc->name)) return rc;

rc=rc->next;

}

// 没有找到,怎返回0

return 0;

}

代码还是相当简易的,但是对于不将这个函数封装成hgeResourceManager的成员函数,我个人是不敢苟同的,相应的,虽然我们还没有遇到AddRes函数,但是也不妨碍我们来也先瞧上一瞧:

void AddRes(hgeResourceManager *rm, int type, ResDesc *resource)

{

// 将resource置于相应资源组别的链表头部

resource->next=rm->res[type];

rm->res[type]=resource;

}

同样道理,这个函数我认为也应该封装成hgeResourceManager的成员函数。

好了,至此, GetStringTable这个函数带给我们的阅读障碍应该已经基本消除,大体的流程便是:首先查找是否存在给定的资源,如果有则直接返回,否则新建相应的hgeStringTable,并根据其构造出一个RStringTable,然后加入hgeResourceManager的资源管理链表中。

不过对于GetStringTable在未有找到资源时采取的添加策略,我个人还是有些微词的,毕竟其显然违反了单一职责原则,而且也不足够灵活,试想,如果我想查找一些暂时没有加入hgeResourceManager的资源时,GetStringTable就不是那么方便了 :)最后一点就是,改函数的名字和干的事情并不匹配,GetStringTable如果可以添加资源的话,那SetStringTable又应该干什么呢……?

呼呼,至此我们终于讲解完了GetStringTable,而剩下的Get* 函数还有很多很多,但是可幸的是,其间的原理并没有多少差异,毕竟我们阅读源码的首要目的不是了解细节,而是解其原理,所以我想说的是,既然我们现在对于Get* 函数的原理有了不错的了解,那么就暂可不必急着查看其他的Get* 函数,慢慢来,相信终归有一天能够了然于胸 :)

好了,这次源码之旅我想是时候停一停了(说实话,我觉得早该停了……),大家也该好好休息整理一下了,当然,HGE的资源管理还不止这些内容(还记得那个神秘的RScript::Parse吗……?),但这些就让我们留在下次“品尝”吧,好了,就这样吧,我呢还是那句老话:下次再见吧 :)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2010年06月07日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
MCP资源管理深度实践:动态数据源集成方案
🎵 在编程的交响乐中,我既是指挥家也是演奏者。让我们一起,在技术的音乐厅里,奏响属于程序员的华美乐章。
摘星.
2025/07/28
1990
MCP资源管理深度实践:动态数据源集成方案
HGE系列之五 管中窥豹(基础类别)
继上次我们编写了那个小程序之后,想必大家对于HGE的认识都有了进一步的提高,那么现在,我想则是时候来一番“管中窥豹”,睹一睹HGE的源码实现了 :)而相应的源码文件位于一下两个文件夹下:hge/hge181/include 和 hge/hge181/src
用户2615200
2018/08/02
4010
HGE系列之五 管中窥豹(基础类别)
HGE系列之七 管中窥豹(图形界面)
这次的HGE源码之旅,让我们来看看HGE的图形用户界面(GUI)的实现,话说电脑技术发展至今,当年轰动一时的图形用户界面,而今早已司空见惯,想来不得不感叹一下技术的日新月异啊……HGE作为一款出色的2D游戏引擎,GUI方面的支持自然不在话下,并且从实现方面来说还是相当具有扩展性的 :)好了,简略的介绍就到此为止吧,就让我们马上来看看源码 :)
用户2615200
2018/08/02
6880
Postgresql源码(72)ResourceOwner资源管理器
注意申请的两个ResourceOwner会有层次关系,最外层套的是TopTransaction,内层是Portal。
mingjie
2022/09/26
9360
Postgresql源码(72)ResourceOwner资源管理器
可执行程序中嵌入资源文件(resource manager)
如图展示windows项目rc文件的编译类型,rc文件使用rc命令编译为object文件,最后linker进exe
sofu456
2022/05/06
5440
可执行程序中嵌入资源文件(resource manager)
HGE系列之十 管中窥豹(游戏字体)
对于一款游戏引擎来说,支持显示字体自然是必备的功能,HGE内建的字体功能虽然仅支持一般的位图字体,但是也算是简洁明了,这次的HGE源码之旅就让我们来看一看他的各中实现:)
用户2615200
2018/08/02
7500
别让资源泄漏拖垮你:C++中RAII资源管理实战技巧全解析
我不知道你是不是也有过这种经历:项目跑得好好的,一段时间后突然出现奇怪的崩溃,或者内存飙升,最后查来查去发现:
Echo_Wish
2025/07/14
1070
别让资源泄漏拖垮你:C++中RAII资源管理实战技巧全解析
HGE系列之三 渐入佳境
前两次“乱七八糟”的讲述了一些HGE的基础知识,不知看过的朋友有何感想,反正我自己都觉着有些不知所谓(!),但本着坚持到底的原则,今天继续献上拙文一篇,如果有朋友实在看不过去,大可不吝嘲笑、大肆放言 :)
用户2615200
2018/08/02
5750
HGE系列之三    渐入佳境
HGE系列之八管中窥豹(粒子系统)
这次的HGE系列让我们一起来学习一下HGE引擎的粒子系统部分,对于粒子系统不甚了解的朋友可以从这里开始了解。
用户2615200
2018/08/02
5850
HGE系列之管中窥豹(变形网格)
  近来实在忙了一些,一直没有时间继续这个HGE系列,但实际上,时间紧之类的说辞深究起来往往都是有些苍白无力的,尤其当你一心想做成某事时,时间总归是可以挤出来的(时间就像海绵......),所以细细想来还是自己的惰性导致了长时间的“搁笔”,应该好好反省才是啊...... :)
用户2615200
2018/08/02
4030
HGE系列之管中窥豹(变形网格)
Egret资源管理解决方案
转载于:https://www.cnblogs.com/gamedaybyday/p/6079694.html
携秋水揽星河
2021/09/03
7720
HGE系列之九 管中窥豹(精灵动画)
这次的HGE之旅,让我们来看看精灵及动画的实现,毕竟对于一款2D游戏引擎来说,恐怕精灵和动画不是最重要的,也可算是最重要之一了吧:)
用户2615200
2018/08/02
6580
免杀360火绒defender小型项目改
APC注入函数,不查杀的原因在于典型函数QueueUserAPC暴露,导入表条目过多。
白帽子安全笔记
2024/10/28
1700
免杀360火绒defender小型项目改
C++核心准则R.12:立即将显式分配的资源交给资源管理对象​
If you don't, an exception or a return may lead to a leak.
面向对象思考
2020/03/31
3030
C++核心准则R.12:立即将显式分配的资源交给资源管理对象​
深入理解php内核 编写扩展_III- 资源
原文:http://devzone.zend.com/article/1024-Extension-Writing-Part-III-Resources
黄规速
2022/04/14
6560
shellcode免杀「建议收藏」
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/171423.html原文链接:https://javaforall.cn
全栈程序员站长
2022/09/23
1.2K0
shellcode免杀「建议收藏」
嵌入式新开发模式(JavaScript)--C端与JS端方法调用
概述上一篇我们描述了为什么我们要使用胶水语言(JavaScript,PikaScript)来改变我们的嵌入式开发模式。并描述了如何在嵌入式设备拉起JavaScript应用及JavaScript应用在嵌入式设备的存在形式(字符串,文件)。打破单片机开发模式--胶水语言(JavaScript) 胶水语言可以让我们职责更加明确,可以类前后端开发模式,后端负责--硬件的适配,方法的导出;前端负责--业务逻辑的的开发。本篇文章作者来介绍JS在嵌入式设备上的如何使用,我们通过一下几点说明:C端如何导出方法提供给到JS端
Rice加饭
2023/03/24
1.5K0
嵌入式新开发模式(JavaScript)--C端与JS端方法调用
HML_FwLib系列在镜像中的使用说明
镜像预装核心功能,但支持外部扩展,如果需要外部扩展,可以将HML_FwLib或相关源码放置于windows系统盘中合适的位置即可。
zhangrelay
2021/12/02
7550
HML_FwLib系列在镜像中的使用说明
基于ffmpeg的wince版本网络收音机开发
基于FFMPEG的Wince版本网络收音机设计与开发 软件架构设计 模块依赖关系图 FFMPEG的编译移植 ./configure \ --enable-cross-compile \ --ena
雪影
2018/08/02
8530
基于ffmpeg的wince版本网络收音机开发
Android系统启动——7附录1:Android属性系统
属性系统在Android 系统中大量使用,用来保存系统级别的设置或者在进程间传递一些简单的信息。每个属性由属性名称和属性值组成,名称通常是一串‘.’分割的字符串,这些名称的前缀有特定的含义,不能随意改动,但是前缀后面的字符串可以由应用程序来制定。而且属性值只能是字符串,如果需要在程序中使用数值,需要自定完成字符串和数值之间的转换。
隔壁老李头
2018/08/30
1.7K0
Android系统启动——7附录1:Android属性系统
相关推荐
MCP资源管理深度实践:动态数据源集成方案
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档