Closed ugksoft closed 6 years ago
典型的不懂装懂。学了半瓶子c++就出来晃了 1,用cdecl还是stdcall是我自己的事情。调用者声明跟着一样申明就行了。出错的全是不看头文件的人。我又不是微软的官方dll,你管我用什么?世界上这么多大型开源项目,尤其是纯C的,基本都是cdecl,例如curl。 2,说什么用内部类,说明一你没看mb代码,二你代码写的少。我导出的wkeString只是个指针,需要操作则只能调用提供的wkeGetString之类的api。你管我导出什么内部类?你看看微软的头文件里,HWND是不是也你说的内部类? 3,结构体对齐这个,按照vs的默认设置就行了。别的编译器设置成vs默认对齐方式。这点下次我在文档里申明下。又不是什么错误,你激动什么? 4,这年头,还有人用两次申明内存的方式传数据我也是醉了。这是最傻逼的设计。别人只是需要几个字符串而已,你还要搞个这么复杂的获取方式。假如需要获取2个字符串,就要new四次,还要2个循环,麻烦的不行。现在mb返回的字符串如果是const char*,表示下一帧回收。不需要你回收,你也不能保存成持久化字符串,也不存在什么用到一半内容被改。这点看源码就知道了。当然,也怪我文档没写,等下我加上。 5,导出C++类, 一堆的??xxxxxxxx@!$#@!$@#$!。这些我让你用了吗?我文档和头文件里完全没提这些类,这是给我的electron模式内部用的。你管我导出什么?我有让别人调用吗 6,“wke.dll中, 画屏,居然要用户自己实现,自己去申请bmp区域,自己去计算鼠标位置等, 超级变态,浪费内存,浪费IO,”,这个叫离屏渲染,是给需要画在游戏等地方(例如D3D需要bitmap)。虽然繁琐,但能控制的更详细。如果不需要,就用简单的wkeCreateWebWindow。两种方式都有用途,不存在对错的问题。你在激动什么? 7,你居然还要我导出com。这都什么年代了,谁还想用这么繁琐的导出方式。现在统一成纯C接口,有问题吗?
楼主的文字,写的太情绪化了,而且幼稚,而且情绪化,我反正是没耐心看完,太喜欢碎碎念了,又臭又长。。。 @weolar 扫地,这些 issue 你就把它们直接 close 了吧 :sunny:
说别人不懂装懂, 我摸电脑都20年了, 本想用一下,发现越来越乱,花了几小时翻译了你的头文件,最后调用,还报错,恨的牙痒痒的,所以才有这文 (我用Delphi7)
1. 用cdecl还是stdcll本理是你的事, 便你这个放在github上,目的是让大家用的, 自然是要按标准的 就算你喜欢cdcell,那你至少显式写一句吧, 一般二次开发文档,SDK等,都是stdcall的 因为标准是stdcall, 我遇到过一些,刚开始用cdcel,后来偷偷改成stdcall的情况所以才提的
2. HWND什么时候是类? 明明是个DWORD, wkestring是你内部的,还让用户调wkeGetString,这不是麻烦吗, 反正用户注册了回调,必然是要使用这个数据的,还让用户多调一次wkeGetString
3.结体体对齐,大家都知道按默认设置,但是你确认用户肯定是VS用户?,用户的程序肯定纯Web应用?复杂应用,通常定义会很乱的,还是显式指定的好 对于自己的dll/exe 这种肯定不能说错,但是跨用户,跨语种,绝对是个错
4.显式调用, 这是在不清楚内存大小的情况下(复杂应用,结体体很乱时,数据可能超大,可能超小时) 但一般应用,大家清楚时,直接申请个足够内存就是了, 这样模块内部的内存区域,不会暴露给外部 假设void *v =GetData(); 代码多了,用户不注意,去对v写操作了, 就死翘翘了(const只是告诉编译器编译时检查语法,而不是真的只读) 你自己回收,但用户并不清楚的, 多线程环境下,是不安全的
5.??XXX??Xx的, 一般开发人员不会去直接写的, 特殊跨语种时会使用(我不用), 我只是说这种不是很好,应该避免, 你的用户应该不会是用gcc之类的极端情况, 所以不用考虑
你干嘛老说激动, 这种渲染 虽然简单的解决了很多问题,但太费IO, 我只是说原wke的方式,不是很好 大多数人不用, 对你有wkeCreateWebWindow表示认可, 表扬你,你还要说我坏?
导出com,只是导出类的一种偷懒方式, 我是不太喜欢com的,只是想到那么乱,给你一个想法而以
另外,我 wkeInit; wkeCreateWebWindow; wkeResize; (...一些注册,可有可无,都一样) wkeLoadURL(htttp://aaa.com/phpinfo.php) wkeLoadURL('http://github.com/weolar/miniblink49'); 静态简单的页面,都OK 但是 wkeLoadURL('www.163.com') 报除0错误 "floating point division by zero" 怀疑是弹窗原因,去注册他弹窗回调,但没有回调, 所以这个原因排除
为是什么原因?
算了,不想说了, 你说我典型不懂装懂, 经验积累超级多,自然会超级乱,方方面面都要说到,但太多了,又会给人感觉说不清楚
那我说你,典型的小孩子, 刚出来混,没经验,只不过,年经人精力不错,所以才会去鼓捣个代码放github之类 (后面半句,语义 中性,)
不想说了.88 close
哎呀,乖啦, @ugksoft
1,stdcall什么时候是标准了?是什么的标准?微软用stdcall就是标准?微软有文档规定所有在他机器上跑的dll都必须的stdcall?我的wke.h显式写了#define WKE_CALL_TYPE cdecl,所有导出函数都是cdecl,有问题? 2,HWND在微软的实现里就是typedef struct HWND *HWND;至于你在外部使用就可以当成DWORD。我导出的wkeString也是一模一样的用法。 3,字节对齐这个我下个版本会写清楚。 4,??XXX??Xx这种是给我自己用的。而且那玩意都是v8的东西,其实是给调用nodejs的人用的。当然只能用这种形式。你要喷,就喷nodejs吧。 5,你说有报错,那就检查下调用方式、调用参数是否正确。如果都没问题可以反馈bug给我。但我相信这么简单的调用不会是mb的问题。
哎呀,乖啦,扫地, @weolar
好吧,大家心平气和点。目前你说的有两个问题确实mb的文档和头文件没写清楚。一个是没写明字节对齐方式,而是枚举的字节大小。下个版本加上显式申明
除了字节对齐和枚举的问题,其他的喷点一概不接受
不要乱喷,还摸电脑20年,这都搞不定还好意思说出来。 无条件支持神僧。
reopen后回复前面几个人
我上面的内容里,可能不知不觉中有喷的意思,但是含量非常非常非常非常的少的, 主要是发现作者没有遵守 还担心误会, 故意加了一句, 不要吵架
一些DLL的江湖规矩,不规范,所以来发表一下, 目的是希望作者下次注意, 现在已经不能改,但是显写定义一下,或是文档说明一下, 维护一个代码,工作量实际很大, 我并没有怪作者,包括偷懒,或是经验不足,弄错,或是其它,都没有怪的意思
可是,作者自尊心爆棚, 反过来欺负人
摸电脑20年,这和搞定搞不定无关,只是说经验很多,五味杂陈,人老话多, 或是不者说不太会犯新手的错误,互相考虑问题可以了眼于简单但冷门问题上,或是深层可能性上 DLL目的是 1.多程序共享时,在内存中只有一块,省内存.多个进程共享时,内核只有一块,只是映射一下 2.模块化,多用户独立分工开发,可以不关是别人怎么实现,只做自己的事 做成 DLL后,调用者不需要了解内部情况,并且随便折腾都行,不知道DLL内部某个东西内存真实地址,DLL提供的所有数值,随便折腾都不会破坏DLL空间,代码安全,
如果花N多时间去折腾才把dll调起来,那失去了用成品模块的意义了, 一些莫名其妙的错误,可能就是定义不标准,在跨用户/语种/环境时出错,这些莫名其秒的错误,可能几天也不一定找的到原因, 还有一些Linux/Windows/固件不同开发者,对于架构的不理解, 照成问题
硬件开发,通常没有多线程概念,更没有数据安全意识,在他眼中,所有代码都是顺序执行的,所有变量,内存地址都没有共享冲突概念的
Linux通常没有多用户合作,前后兼容等意思, 因为Linux程序各自为政,不考虑前后兼容问题,Linux也没有操作友好度,操作安全意识 ,什么都是文件, 资源也拼命使用,所以通常做的东西比较单板,好在人多,大家把某个exe模块拼成一个功能,像IOS,那样,限制一下,不能这么操作不能那么操作,单一性的功能,可以使用了
Windows,问题也很严重, 不过一下子不好举例
挑这些剌,不要喷我怎么不去做一个系统, 做个系统是简单的,但是你根本不可能去运营的 驱动程序,必须开发,但厂家都倒毕了,文档也找不到了(比如 PS2键盘接口,IBM推出的,但是连个标准文档都没,大家都是看示波器,分析出信号格式,然后去写固件的) Windows右键菜单, 专利现在还没到期(好像还有半年), Apple当年和微次打了一架,没淡拢, Apple多年来,一直是单键鼠标,还吹说单键的好处, 后来卖iphone赚到钱了,专利也快到期了,才和微软互换了专利(好像还交了钱)现在的ocx里,才渐渐有了很多右键菜单
一些话比较啰嗦,也是怕很多人不明白,所以才故意多写的, 现在很多新人,大多会web,py,java等,低层原理的都没概念,也不愿意去学 ("很多新人", 并不一定说是楼上几位, 不要对号入除,然后乱喷)
stdcall, 我记的微信在9x年代时,官方出的书或是文里,是做为推荐方式的, 这不能说是绝对是标准,但是这么多年下来,大家都是按这个方式去做dll的,不管是不是,都是显式写明的,保护任何情况下都不出错,保证向前前后兼容,早就不成文的标准/规矩了
具体你可以搜索,所有像样的公司提供的SDK包,比如海康,大华,这些硬件厂家的SDK,所有微软的H文件,所有的跨语种Windows工具等 原本是Linux下的代码移值的除外,像opencv,ffmpeg,x264.faac等,就比较乱了,具体由编译工具默认值决定, 甚至opencv因为从api上,完全看不出retrun值是个什么东西,要不要去释放之类(返回值在实际可能是个内存块,但返回值,给用户的h文件中,被定义成int了,而不是void *), ffmpeg,不定时,结构体都有乱序改动(定义ab成员,后来想增加了,随手插上一个,变成acb),就算同是C开发,直接引用,也不能通过拷DLL/so方式来升级模块/功能
说HWND是DWORD,因为对于外部用户来说,他就是个DWORD,不需要释放,用户以标准int32方式取值赋值,,不用关心内部怎么实现,类似 作者wkeCreateWebView返回的void *, 写成DWORD/Handle也没关系,反正用户不可能操作这个数据的,用户知道"Create"这词的 ,那肯定是要手工去释放的就行, 外部用户在重新定义API时,可以指鹿为马,只要保证API在交换数据时里内容和方式一样就行
补一下 wkeLoadURL 这个,好像没有自动补http://的功能吧, 需要提供完整地址,才可以 可考虑判断一下,有没有 '://'字符串,确实要不要补头, 如果说错,当我没说
重申,跨语种时,发现莫名其妙问题,很可能是作者经验不足,一些地方不按行例定义,产生的问题 所以,我不打算使用, 只不过这贴子,开了头,所以才有这个回复, 这是最后一次回复了.,请作者也把这个关了,大家都不要回复了,删贴也随你 还是删了吧, 很多内容扯的太远
1,微软用stdcall的原因是因为在那个年代,内存硬盘资源非常珍贵,stdcal可以让dll省几个字节。但现在早就不在乎这几个字节了,而且微软也绝对不会说stdcall才是标准。我用cdecl是考虑到这个可以支持不定参数,而且是纯C接口用的比较多的调用方式。现在开源库curl,libuv之类的,全都是cdecl。并没什么所谓的行规要用stdcall。 2,你说的我导出内部类,这个完全没道理。我导出的wkeString对外部调用者来说只是个DWORD而已,和HWND之类没任何区别。微软也是直接把user32.dll内部的struct __HWND导出来。 3,从你提的几个建议来看,你既没有认真看我的头文件也没认真看文档。否则就不会说出我没明确申明cdecl这种话来。 4,目前miniblink都已经商用了,delphi的封装也有很多人用。莫名其妙的问题很大可能是你没按文档封装而已,不要怪在miniblink头上。我研究windows内核和win泄漏代码的时间不比你少。大家心平气和的提意见就行了。你说的对的地方我自然会采纳。
没认真看头文件? 我都翻译你头文件到Delphi(pascal语言)了 ,还说没认真看?, 没看完到是真的,内容太多,有些项并不一定需要,优先翻译重要的的,先跑起来,后面需要哪个加哪个
curl,libuv,这些原本是linux下的,移值出来的, 并不是windows开发者写的, 他不使用stdcall是否gcc能省几个字节我不知道,但怎么可以用于判定cdecl好,所以在windows中也用这种呢!!! 而且linux的行规原因,我是win为主的开发,如果我写个linux模块,我也会按linux方式去走,不会去考虑win的stdcall, 除非我打算写成跨平台模块,为了以后省事,提前写成stdcall,因为win下环境复杂,linxu下相对单一,都是gcc就算不是gcc的编译器,大家都去按gcc方式走(比如freepascal编译器算是另类,不像objC那样集成在gcc中,但是也编译成obj文件,再连接成elf,从模块接口,调试方式(gdb),全部按gcc方式走) Go编译器,单独编译器,也跨平台的,但原生也是linux开发的,作者也是linux开发者等等.所以除非指定,否则也是按linux方式调用
windows是stdcall,一般二次开发包都是stdcall, 这已经是惯例,那么尽管优点很少,甚至有点缺点,为了兼容性,习惯性,应该考虑stdcall stdcall和cdecel都是从右到左的,所以都支持不定长参数!!!!!, 区别是干完活了,谁打扫战场
fastcall是放参数放在寄存器中, 超频繁调用的函数,可以加快速度,循环类,加密类等 pascal/fastcall,是从左往右存放参数,所以不支持不定长函数
无参数api stdcall/pascal写反了 ,正常使用, 有参数的,写错了,有时数据错乱,有时参数顺序反过来,fun(a,b)变成fun(b,a),肯定不能正常执行,而且返回时,通常报错 stdcall/cdcel写反了, api功能正常执行,但返回时,不一定马上报错,多调几次后,肯定报错,或是后面连续几行代码里报无理头错误(连续几行的意思是只在附近行报错,不在其它异步线程中,或是很远的地方报错)
不清楚你说的省几个字节的问题,可能理解差异,或是表达上差异, 但居握我所知, 汇编代码层面上, 这stdcall/cdcell,两者 99%是一样的,不方便贴个OllyDbg图,所以专门给你找了个url,有汇编代码 https://blog.csdn.net/jqsad/article/details/51670826
有些话,不清楚是你用词不当,还是不懂, 比如纯C接口比较多的调用方式, 纯C接口调用的多, 感觉多少有点 纯C所以才cdcel的意思在内, 同一个程序,内部如何调用可以编译器,编译参数,强行指定等决定 同个编译器,默认情况下相同调用方式, 偷懒,少打字,所以连显式定义也省了,这话才说的过去 我对这有异意, 你回复一句,懒的写文档,,懒的显示指定, 才比较让人接受+认可
不清楚你所谓的商业应用, 这个根本拿不到台面上来说的, 本身是开源的,国内偷用开源的去卖钱,注册专利等多了(联想把 cat /proc/cpuinfo, 查看系统信息,都注册成专利了,脸皮厚的可以 大约七八年前看到) 而小应用,小单位使用你的代码, 那就算给你钱了,哪怕是给你个几百几千万,但用户量不多,拿这来说商用,有点自抬身份,不够谦虚吧的感觉吧
我的代码: 一个空窗体一下, 放个按钮,按钮点击事件下,下面的代码 wkeInitialize; 初始化 obj=wkeCreateWebWindow(2,pnl1.Handle,0,0,pnl1.Width,pnl1.Height); //创建个对象 // 这里2改成0弹出窗口,但改成1, 会在一个不着边际的地方显示个没边框的webFrame // 我需要的2的应用,在一个窗口一个区域里显示个Web控件 // 一些回调设置, 全部取消,和加上, 没区别,要报错的还是报错 所以省略, // wkeResize(obj,pnl1.Width,pnl1.Height); 调整大小 wkeShowWindow(obj,True); 显示 wkeSetUserAgent(obj, '......'); 设置代理字符串,设不设没区别
再放几个按钮,分别是下面的一行代码 wkeLoadURL(obj, 'http://abc.com/phpinfo.php'); 显示正常不报错, 鼠标可以在web区拖动选择块等 wkeLoadURL(obj, 'http://abc.com/index.html'); 显示正常不报错 ... wkeLoadURL(obj, 'https://github.com/weolar/miniblink49/'); 显示正常不报错 ... wkeLoadURL(obj, 'https://abc,com/a.jpg'); 显示正常不报错.....
wkeLoadURL(obj, 'http://www.163.com/'); 报除zero错误 wkeLoadURL(obj, 'http://www.baidu.com/'); 报除zero错误 只要报错后, web区,绘屏死掉了,后面再也不会更新,比如调用loadurl(http://abc.com/index.html'); 不会再更新
------------------除上以上代码外,还有头文件翻译外,没有其它了多余的代码了------------ 文件使用miniblink-180716.rar中node_v8_4_8.dll或是node.dll. 单独绿色型一个dll, 和exe文件 (即总共2个文件)或是连同压缩包中resources/plugins/front_end目录丢进去 同样,没区别
支持rar中的wkexe.exe却能正常显示163,baidu
在http://www.163.com时,回调顺序
wkeNavigationCallback http://www.163.com/
wkeNavigationCallback http://3g.163.com/
wkeURLChangedCallback https://3g.163.com/touch/
到这里,后面再也没有回调,开发环境中,侦测到除0错误,单独运行不报错,但web区停留在上次成功的页面上,再也不会更新了, 重复访问163.com 除了回调一次wkeNavigationCallback http://www.163.com/外,不会再有新动作
因为上面几个api,太过简单, 原定义stdcall出错,全改成cdecl后, 其它就算是新手也不太可能翻译错头文件 或是写错代码等, 但我跑不正常, 还以为,有些看上去可选函数一定要调用, 所以按照wkeBrowser.cpp大部分都抄了个遍, 但要报错的还是报错 最后,只好到这里发贴,然后放弃
关于字节对齐的 typedef struct { wkeProxyType type; char hostname[100]; unsigned short port; 这里方要加2个byte手工对齐,防止被编译器欺负 char username[50]; char password[50]; } wkeProxy;
另外100,50这样的值不好,会照成非int32对齐, 这样影响执行效率,编译器不得已只好拆成解成32bit+int16+int8 这样的零碎指令
而且50,100这样大小计算上不好内存错位,其它人想翻译代码,或是只想copy半个结构体(比如上只想拷proxtype+hostname这部分数据)
应该是写成hostname[128], username[64]之类
总之,习惯不好,以后要改掉, 现在这代码已经成型,不方便改了, sizeof(wkeProxy)一下看看 默认被压缩了,就加一下pack(1)/pack(2) 没压缩,赶紧插个char Res[2]上去
你DLL参数是enum的, 应该定义成int的, gcc不清楚, windows上的编译器,默认会int32对齐的 参数是1-4byte的类型,都会强制成4byte,目的是效率,防止xx个参数,前面一个byte,后面拆解成(xx-1)*N倍的指令量, 但是编译器手贱去设定了参数不对齐,就惨了
1,是你自己说“个别因效率原因,或是开发方便等原因,不按上面的来,也要书面写明”。我里面清清楚楚写明了是cdecl!你自己说你到底翻译了半天有没看到我申明所有调用都是cdecl?? 2,再次重申根本没什么行规要用stdcall!!用什么协议是库开发者自己的事情,使用者按照约定调用就完事了。 我说的几个开源库都是cdecl,是不是linux移植的有什么关系?你需要管这个库是哪里移植的吗?这几个库都是安装量过亿的东西,有出什么问题吗?是什么约定就遵守约定,这么简单的事情说这么多。 我举这些例子不是说cdecl有多好,是想说用cdecl的成功案例也有很多! 我用cdecl到底有什么兼容性??我需要兼容谁了?那些不按规定就调用的,才是有兼容问题
@ugksoft 敢问您老是哪个大学的教授??
你们这些在windows下用cdecl,都是异教徒,都是叛贼, 都是罪犯...O(∩_∩)O哈哈~
感觉是在win开发久了的锅吧,类unix系统下有这些问题么?,实在觉得这样不行可以自己改呀,mit又没限制你修改的自由.
有这牛逼码字的精神,还不如去码代码?,手底下才见真招
还没写完吗,等了好久了
是幼稚还是调侃?,如果真的是大学教授,就不可能这样的经验积累, 大学授权,一般是骗经费,或是骗学生去给他白打工之类,,根本没功夫来和你扯这嘴皮
你们打拼音居多, 打五笔的,打字快,所以打的东西多,不过质量不高,打的多了,有时条件反射,打错了自己都没发现, 开发久了才有这个锅之类的
在windows下给其它人用的DLL,我会显式指定各种,并且直观清单工的h文件 在linux下,我没有给别人二次开发包的经历,不过我单独开发过嵌入式(海思的arm,从移值内核,打包rootfs到app完工,板子也是自己画的,官方有demopcb文件,所以做软件的去做硬件也没有难到天上的地步, 参照着画精简掉不需要的模块,换掉官方例子中的高价芯片等,然后,最后连到铁皮外壳选型等,全部完工, 交工,所有东西, 即就是别人项目外包,或一条龙代工, 我的主要收入,都是给一些外表很有钱的公司做技术枪手
其它单片机(类似stm32这样无系统应用),也做过点,不过单片机太过简单,没什么经济意义
毕业以后,一直是做底层,算法类的,windows平台, 以D7为主, 开发效率高, vs太过臃肿,码字速度也快不上去, 其它平台下,自然是C或C++了
C/C++下面,define效率严重拖慢编译速度,现在cpu下,代码量不大时,这种定义拖慢的不严重,但 你非要大量的define,连导出函数都这样另类方式写,好像有点,,,,, 不是常规h文件方式,这样的写法,并不能让你省下多少代码量,反而语法不能亮量,不易发现错误
你确实写了cdecl,我回头看了,我用notepad++打开的h文件,专心翻译头文件,找参数返回值等定义 所以,只有个别几个函数和回调函数是就近有cdecl值,大多数,因为你的#define方式 不直观,没看到cdecl ,所以,需要显式申请这条,我收回, 但是stdcall是发布dll的规范/主流或之类的意思这条,我绝对坚持
你用到的库,用的什么方式的调用,那是库的,和你无关,这些库也是linux上的 本身chrome开发,也是在linux上开发的, 而大多数网络方向的公司,都是linux上弄东西的工作, 这些库都是linux下的,如果我想用linux下的库, 导出一下,肯定会使用linux下的,或是编译器默认的方式 为了安全不出意外,也因为去改动工作量太大,没意义
但是,每个api都是自己写的,那用别人的东西,肯定是要按目标平台来做了 你在无理取闹,非要扯子库是这种,你的库就一定要用这种方式,
我并没有说cdecl好,或是stdcall好, 哪个更成功, 只是习惯,或是约定,俗成,或是队伍太过强大,少数跟随多数(windows上开发,自然跟着winapi的走)等原因,应该stdcall 你非要东拉西扯的, 把一个常例的事,硬去找反对理由, 只能证明你工作经验不足,接的活非常少,非常单一 所以才会硬磕这事
亲你你互联网上的人儿么,锅这个梗你都不知道么?
你在搞笑吧,到底谁在无理取闹。我哪句话说什么子库用这种,就必须用这种? 我明确写着,讨论curl那种是为了证明cdecl的库也很常见,别人用的好好的,我怎么就不能用了? 我每句话都是回复你的问题,你写了几千字,扯些乱七八糟的,还说我东拉西扯?你工作了20几年,都是在写低端代码吧,硬磕cdecl的人是你,我早说明了,用哪个方式都可以,调用者按照声明去用就行了。 你自己看看你第一个回复,好像我用cdecl是多么罪恶似得,这不是在搞笑吗?windows上用cdecl的多了去了,你少见多怪而已
你自己看看新建一个vs工程,默认是不是cdecl?
自己看下吧,微软是怎么说明的。这里也解释了我说的会多几个字节的问题。不知道你有什么好坚持的。好好按照微软的说明做吧
“你这是DLL的全部是默认的cdecl!!! ,在Windows中,标准规则是stdcall!!!!!!!,包括回调都是stdcall, 现在要去改cdecl, 别人的程序,必然报错, 你看看你的用户量,量小,能够保证通知到的,或是产生的问题不大的,那修正为stdcall, 具体酌情考虑吧” —————— 我又不是windows api,为什么要非要改成stdcall?哪里有什么标准规则?微软自己都说了c++默认是cdecl。我只是用了vs默认推荐的调用方式而已。 而且谁会报错?只有不看调用方式就瞎调用的人才会报错。
说句不好听的话,作为一个开源库,有强迫你使用么?有收了你一分钱么?既然你是20年的老码农,经验技术又这么牛逼,你大可以自己撸一个啊,别说用stdcall,用开了花都可以!既然要用mb,你就得遵守mb的规则,就像你用win一样,你就得遵守win的规则!20年!先做人在做事,别说你做20年,做到死估计也就这个样了!
教授就是教授啊, 太能扯了, 搞软件的 你 去搞硬件都这么牛, 这在儿闹腾啥呢?! 还扯输入法 神经反射了,牛人
爱用不用啊, 有问题 提 issue 不就行了吗????
另外微软MSDN清楚的说明了,stdcall不支持不定参数。不知道你搞了20年,连stdcall不支持可变参都不知道是什么情况。如果你说你手动嵌入汇编在stdcall里清理堆栈,那我真是无话可说。
看完日报来围观
@ugksoft x64 全是 fastcall,包括所有 DLL,M$ 自己都不要了还有人舔?我们只用 C++,只从头文件用,有什么不行的?你要 stdcall 要 COM 自己封装去,大可以给完整 Chromium 贡献去,我们只要一个开箱即用的东西。
咦,这位也是D7时代穿越过来的人嘛……我记得那时候大家火气没那么大的呀
楼主太年轻,碰到这样的大牛,直接一句"您说的对"
只能证明你工作经验不足,接的活非常少
一个底层劳动力还把自己给感动了
typedef struct { wkeProxyType type; char hostname[100]; unsigned short port; //这里方要加2个byte手工对齐,防止被编译器欺负 char username[50]; char password[50]; } wkeProxy;
这怕不是还要写packed
2333
@ugksoft 行家啊。 Don't BB, show your code
Re:
Linux通常没有多用户合作,前后兼容等意思, 因为Linux程序各自为政,不考虑前后兼容问题,Linux也没有操作友好度,操作安全意识 ,什么都是文件, 资源也拼命使用,所以通常做的东西比较单板,好在人多,大家把某个exe模块拼成一个功能,像IOS,那样,限制一下,不能这么操作不能那么操作,单一性的功能,可以使用了
某些人用了20年电脑,难道对 Linux 一点都不了解么? 对 Unix 世界的文化、编程哲学一无所知么? 在知乎上面实在是看不下去了。
Linux通常没有多用户合作,前后兼容等意思, 因为Linux程序各自为政,不考虑前后兼容问题,Linux也没有操作友好度,操作安全意识 ,什么都是文件, 资源也拼命使用,所以通常做的东西比较单板,好在人多,大家把某个exe模块拼成一个功能,像IOS,那样,限制一下,不能这么操作不能那么操作,单一性的功能,可以使用了
Linux的世界是对geek友好的,而Windows是对最终用户友好的。两者互不相容。
作为一个Linux的程序员,他是不怎么需要管其他“用户”的用户体验的,这里的“用户”也包括了自己的SDK的使用者——他们认为,我的所有特性,所有命令,所有版本变更,都是你需要学习的东西,如果你学不会,说明你不是我的用户。
而作为一个Windows程序员,如果他只会写命令行程序,这程序还需要复杂的辅助依赖、管道组合才能用,那他基本上就是自绝于大部分最终用户的。我们可以看到很多Windows程序员的Windows编程之旅都是从窗口界面开始的。
那么在Windows下写SDK的程序员,又应该遵循什么样的设计哲学呢?
我觉得应该还是要属于Windows的,尽可能多地考虑用户体验、兼容性等的思路。调用约定不是什么大事,但是暴露给外部的接口,在可以使用常用类型(const char)的情况下,使用自定义类型(等同于void)我觉得还是不大好的。
知乎观光团
没写过c/cpp,过来围观一下。
知乎观光团
hahahahahaha, zhe ye neng si bi?????
我提个建议啊,关于dll的函数导出,最推崇的方式。大致这样 -- 整个dll就一个导出函数,叫做 void *getFunctionList(); 这个函数返回一个结构体的指针 --
struct FunctionList {
int (*getVersion)();
void (*func1)(int a, int b);
int (*func2)(int a, int b, int c);
char (*func3)(int a, int b);
...
};
结构体的第一个函数固定,返回版本号;其他函数以后随便改。 将结构体做成头文件,和dll一起发布。
以后可以畅快的版本升级,头文件写好就行了。C/C++外其他语言想调用,你们自己想办法。 这是在做IAR编译器的某个驱动时看到的做法。
异不异类?好用就行。
@xhawk18 你这方式我想过,不过有几个问题所以没采用。 一个是如果接口变化了,就不兼容以前的老版本了。这个对用户来说特别不友好。像我这种每天换个版本的,用户需要不停的编译再发布。 二是无法在导出表里看到有哪些函数。很多时候还是需要知道某个出问题的用户的dll是不是采用了某个新接口导致。虽然可以通过查询版本号,但毕竟很麻烦。 综上,这种方式几乎没啥优点,简易性不如现在直接用c接口导出。
知乎观光团
歪个楼问一下楼上上的问题,接口变化如何保持兼容?感觉只要一变内存结构,就会导致不兼容,有什么办法可以做到兼容?
@leozzyzheng @xhawk18 这种方式无法做到兼容,除非每次只在最后追加接口,不改原有接口。所以这也是我不采用的原因。其实这种方式就是COM嘛。
@weolar 我也是想到了COM。 不过做兼容总是会需要新老接口全在导出列表上吧?只不过可以不需要强制末尾加?
@leozzyzheng 这个方式不解决兼容问题,只是接口变化时比较好处理。 每一版的接口,都有固定的结构体描述,不容易搞错,更不会冲突。 实在要兼容,调用dll的人根据版本号做处理。
windows api一直是stdcall吗?还真没注意过,再说了别的语言不支持cdecl?秀自己的无知吗?用别人的东西,本来就要遵守别人的规则。@ugksoft
年龄高不代表技术如何,我司也有一个老大哥,四五十的人了,走不出自己的思维,于是一个月被开了 @ugksoft
主要是看不下去了,才写的, 有些太常识了,我扯这些常识,反而显示的我小孩子, 可能你也明白的,只是因为偷懒,才不去那样做, 并不是你菜, 为避免误会,吵架等,特意说明一下
你这是DLL的全部是默认的cdecl!!! ,在Windows中,标准规则是stdcall!!!!!!!,包括回调都是stdcall, 现在要去改cdecl, 别人的程序,必然报错, 你看看你的用户量,量小,能够保证通知到的,或是产生的问题不大的,那修正为stdcall, 具体酌情考虑吧 DWORD stdcall GetTickCount(); DWORD stdcall Sleep(dwMilliseconds:DWORD);
常见的有stdcall/pascal/fastcall/cdecl 这4种,总的来说是,API的参数寄存器存放顺序,从左到右,从右到左, 临时堆栈谁释放问题, stdcall是从右往左(目的是format(xxx,a,b.c...)可变长度时.. VC内部,或是默认 cdecll, 不加修饰符时,默认也是cdecll
给你找的,你可以看看 https://www.linuxidc.com/Linux/2010-04/25290.htm http://www.3scard.com/index.php?m=blog&f=view&id=10 ( 没有BS你的意思,纯好意, 你的代码中,没有注意到强制stdcall,可能这方便面意识淡薄,所以才强调一下)
这辈子第一次见到有人写dll,居然使用内部类做为回调参数的的 string是C++内置类型,实际上,也算是一个类(类实际在编译中,一般都处理成record/struct形式存放在编译后的bin中的) 不同的版本,不同的编译器(vc,bcb,或其它c++的编译器),对于这类非直接内存数据,都有自己的处理方式 除非是你强制要求用户和你使用同一版本的vc(如果微软对这个vc打个补丁涉及到string,那么甚至需要大家连补丁都一样),或是dll的和exe都由用户自己同一个编译器编译,或是直接把dll的代码包含在exe中,不使用dll了, 否则,内存中数据必然不一样, 不可能让exe正常调用这个dll,到时出现各种无理头问题,又找不到原因 修正方法, 全部改成 char (可以考虑wchar,不过一般以char为主)
作为一个dll,需要按Windows的标准规范,那么所有的编译器,都能很好的支持的 常见的delphi7/DelphiXE, VC, BorandC++,Java, gcc(MinGW/Cygwin)... 这个规范简单来说, A.stdcall (个别因效率原因,或是开发方便等原因,不按上面的来,也要书面写明) B. API交换数据时,要32bit对齐, 一些枚举,bool或其它,都要显式申明,防止不同编译参数影响到内存对齐 参数要尽可能是内存本质的,一般以 ansiChar为主, 个别可以是 WideChar,但大多数是* ansichar 这和utf8兼容,和gbk也兼容 WideChar,最多只有65535个字符,实际没这么多, 在处理新字码时,必然有损,所以widechar不应该使用 因为 windows当初设计时,9x年代,,想着65535总够了,现在utf8里一堆垃圾,说不定哪天4byte 都不一定够用,所以还是ansichar/utf8/gbk为主吧!!!,至少不会有错 C.所有枚举,需要强制指定开始点和结束点,即 enum_start=0, enum_MAX=0x7fffffff, 这样避免编译器,自作主张,一看没超过255,就用一个byte来存储,一个程序中没事,跨文件交换数据 就成问题了 D.所有结构,要强制指定对齐方式. 通常是4byte为单位对齐,
pragma pack(4) //强制4byte对齐
struct { //DWORD dwsize 复杂数据,可考虑添加dwsize, 这样dll可以根据dwsize判断exe是哪个SDK版本开发的, // 同时也可以用于操作时的越界判断, windows大多数结构,都有这样的大小,值, char ver; char flag; char res1[2]; 这里少了2个,所以故意添加2个(也可用于将来扩展功能预留), 以防止编译器收缩,不使用时,一律填0, 将来要用时,知道0是不使用的,非0才是有效数据 char X; char Y; char X; char res2[1]; 结束时,防止编译器收缩,所以故意对齐 }
pragma pack() //恢复编译器默认对齐方式
这样故意添加res成员,占位置,一般情况下32位系统是正常了, 万一64bit编译器,将来编译器开发人员一时想不开,64bit默认8byte对齐, 或是编译器因为需要其它数据需要参数设成8byte对齐, 这时必然出错 所以最好再加上pragma pack 显式指定一下
这些大小值,全部设置后,由于结构成员很多,可能会弄错,比如,res[xx]算错了等 全部弄完后,需要printf("Name=%s, sizeof=%d",xxx sizeof(xxx));一下, 全部确认一一下
不过,总的来说,只需要修改h文件, 改动量并不大, 只是你的老用户,兼容性可能有问题 (他们需要拿了这个头文件,重新编译一下自己的程序,代码上,一行也不用改)
一些函数, 比如wkeGetUserAgent,返回是一个 ansichar的指针, 正常,应该是,让用户给定一个内存空间, dll负责填充数据, 通常还会是二次调用 第一次调用时,buff=null,*size返回大小 第二次根据size申请内存size,然后get(buff,size) 如果是字符串数据,防止意外,及兼容性,通常size+1多申请一个数据, (或是用户知道这个数据也就是4K长撑死了, 直接一次调用,给出4K内存, DLL调用后更新size,告有效长度 这样,用户也不用怀疑这个返回内存块要不要外部exe去释放的问题 不管什么语言,默认都是谁调用,谁申请内存(exe调API_Filldata(xxx),那么xxx由exe申请,也由exe去释放,)
但是,图方便,可以直接流氓式,返回 char的数据,大多数不会出问题,不过: char p=GetCurUrl; //返回www.xxx.com int Len=strlen(p); 用户一堆后续操作,可能浪费了很多时间,也可能是用户电脑太卡或其它原因,,同时web的的线程,js倒计后,指向 www.newurl.com CPU时间片,代码块间轮循时,不可能保证大家都是平等的,有的多轮到些,有的少些,多核下,优明显,进程卡时,优明显 用户再对p进行调用, 这时p的值已经变成newurl了,也可能被你释放了,也可能不安全了(结尾问题) for (int i=0... i<Len) { ..... } 为了解决这种问题,需要书面写明, 告诉用户,这个结果值是安全的,是常量的,是...的等等才行 但终归不是正常调用方式 用户无奈解决方法,要可能是 GetCurURL后, 马上newmem块内存,把结果拷进去, 以防止web核心对数据改动 但总归不如用户自己申请的方案 称妥
5.你的DLL导出了C++类, 一堆的??xxxxxxxx@!$#@!$@#$!导出名,实际并不安全,而且开发并不方便的 好的做法是模仿COM,导出一个进程COM接口(比如wmp.dll就是这样的) 比如定义一个 wkeCreateWebCore(); 返回接口 接口如下: Interface Ixxxxxxx; function setpos(L,T,W,H,isshow); function LoadUrl(url ) function .... .... (详细,你可以vc随便打开一个例子,或是用exescope打开c:\windows\system32\wmp.dll
用户在使用时,不需要创建任何类,只需要 web=wkeCreateWebCore(); web.setpos(...) web.loadurl(...) function regcallback(CB callback,void user); 这和标准的类代码,完全一样
不过com方式缺点时,有些地方让用户不清楚本质,比如指针的指针,最后这个内存要不要释放(比如DirecShow->mediatype.format数据),调用顺序等,有点糊, 所以, 在使用时,尽量按标准的,原始的数据类型, 可能有内存释放问题时,文字写明 在处理回调,事件类时,不要用COM的方式,而是标准的C/C++方式
不要使用进程以外的COM(比如开机时,开始菜单按钮卡着了,或是一些程序操作时,开始菜单卡了,IE卡了,操作一下,结果会是影响到资源管理器之类,.都是跨进程COM的,不建议这样搞)
太多了.不想说了, 不是一句话两句话说的清楚的,