swift编程开发

基础特性

可空类型的操作符

左边
右边
返回
使用示例及场景
可空实例绑定
if let va = vb, vc=va{
}
可空链式调用
va?.uppercased()
va?.append()—原地修改
隐式展开可空类型(是可空类型的一种)
??(nil合并运算符)
可空类型
对应的非可空类型
nil返回右边,否则左边的展开值

数组:

声明方式一:

var alist: Array<String>

声明方式二:

var alist: [String] = ["q","p","r"]

数据比较时,注意是有序的。

字典:

var dict1:Dictionary<String, Double> = [:]

var dict2 = Dictionary<String, Double>()

var dict3:[String:Double] = [:]

var dict4 = [String:Double]()

要点:

当用key去获取value时,如果没有值则返回的是value类型的可空类型。

技巧一:循环

for (key,value) in movieRatings{

}

技巧二:转换到数组

let va = Array(movieRatings.keys)

集合:

var groceryBag = Set<String>()

groceryBag.insert("qifwef")

for food in groceryBag{

print(food)

}

要点:不会重名,相当于distinct

有uion的方法针对两个set的取交集

有contain的方法针对set来判断元素存在

有intersection(_:)来找出两个set的都存在的元素set

有isDisjoint方法来判断两个set是否存在交集

函数:

func fname(外部参数名 内部参数名:[inout]类型)->(返回)类型{

return 返回值

}

注意:内部参数名就已经是显示参数名了,即在没有外部参数名时,使用函数时可以带着。而外部参数名更多是用于介词的辅助。当参数列表中有任一参数提升了层次,即用上了外部参数名,那么,有一个_符号是用来应付无关紧要的那个参数的外部参数名。如果要熟练玩味这两类参数名,一定是在使用中玩味出应用场景的概念。内部是函数微观算法层。外部是类型和指代层。

  • 变长参数

上面的变成<类型…>

  • 默认参数

直接用="defaultvalue"即可

  • in-out参数

调用时实参要加&修饰,以示要在函数内修改。

  • 多个返回值时

-> (returnvalue1: [Int], returnvalue2:[String])

  • guard语句

func …

{

guard let mv = name.middle else{

print("out func here.")

return

}

print(mv)

}

gurard守护的条件不足时提前返回。mv的可空类型没有值,或者为nil时,执行打印out func here.和返回。

如果守护的条件“不尴尬”时,就后面用其值了,print(mv)。

  • 闭包(高阶函数)

闭包通俗来说就是{},有时是嵌套在函数内的函数。但更多的指把函数为参数传值给函数和从函数内返回函数类型,注意返回是引用类型,传入可以匿名技巧。

高阶函数是至少要接受一个函数作为输入的。如:

数组的sorted(),map(),filter(),reduce()方法。在swift中sorted既可以用传入参数的语法:

vv.sorted(by: sortAscending)

也可以使用匿名函数法。即闭包表达式的应用:

vv.sorted(by:{(i:Int,j:Int)->Bool in

return i<j

})

利用类型推断,再进化一下:

vv.sorted(by:{(i,j in i<j})

最终版本:

vv.sorted(by:{$0 < $1})

因为数组的元素类型是默认的了。

对象特性/技术

枚举:

要点:第一次创建枚举的变量就必须要初始化。

枚举类型可以没有原始值,即一定要归成Int类型。当然也可以用原始值,并指定初始值。不局限成Int类型的。

细分应用场景:

有限的

计算的,可修改

技巧:

mutation func XXX…

说明这个函数会修改对象中的值。

结构:

细分应用场景

无限的

计算的,要修改,简单继承扩展

无复杂关联操作的

技巧:

mutation func XXX…

说明这个函数会修改对象中的值。

static func XXX…

说明这个函数是类型方法

类:

细分应用场景

无限的

计算的,要修改,要控制继承及可见性

复杂关联,可见性的

总之,继承,封闭,多态。

技巧:

[final] [override/static] [class] func XXX…

说明final class == static符号,关闭子类重写本方法的意思。所以class和static两个符号在结构和类中是不同涵义的。(结构中没有class关键字)

属性:

  • 嵌套属性

类作用域中的枚举或结构,比如某一个枚举Size(类的接下来的属性会用到。)

  • 存储属性

此类型属性必须有值,默认也可,后初始也可,这主要和下面的类型区别。只读的存储类型==常量

  • 惰性存储属性

lazy var townSize:Size = {

switch selft.population{

case 0…10_000:

return Size.small

….

}

}()

注意:后面还有一对小括号,就说明这是一个运行得出的属性。但依赖的population是一个存储属性。类一初始化就已经给定,所以,算法也是一并初始就定了。而且,后面不会重新计算了。这块取义依赖的成分大于惰性。

  • 计算属性

var townSize:Size {

get{

switch selft.population{

case 0…10_000:

return Size.small

….

}

}

set(){

}

}

  • 属性观察者

var population = 5_422 {

didSet(oldpopulation){

}

}

  • 类型属性

此类属性的值在同类型实例间共享。但必须有默认值(原因是没有初始化方法的)。

在类中的可以用class修饰来让子类继承覆盖,也可以用static来禁止覆盖。

适合将没有入参的行为改写成类型属性。

  • 访问控制

描述
对who可见
能继承使用
open
Public
internal(默认)
fileprivate
private

初始化方法

  • 结构体的默认初始化

var myTown = Town()

结构体的成员初始化

var myTown = Town(population:10_000, numberOfStoplights:6)

  • 结构体自定义初始化

委托初始化(在结构体中称为这个,在类中同义但是称为便捷初始化)

init(){

self.init()

}

  • 类的初始化(在类的继承场景中)

指定初始化

init(){

//初始化本类引入的属性

super.init()//调用父类中的初始化方法

}

便捷初始化

convenience init(){

selft.init()//本地的初始化,其中也可能调用指定的初始化,层层初始。

}

必需初始化

父类中要求

required init

子类中实现,关键字包括了Overrider的意思。

required init

反初始化方法

deinit{

}

高级特性

协议

枚举,结构体,类都可遵守协议,同时协议也可以继承,也可使用&来组合(用于传递参数)。可以理解它为是样貌。

protocol Velocity{

}

异常

func getNumber() throws -> Int{

throw 类中枚举的异常值

}

使用上面的函数时便可try getNumber()

或者在外层包裹:

do{

try get…

anotherfunc()

}catch Parse.Error.unexceptedEndOfInput{

}catch{

}

扩展

注意针对是类型,且是可以针对协议的。强大的冒汗了。可以理解成它是样式

typealias Velocity = Double

extension Velocity {

}

泛型和协议扩展的争论

泛型是固化一种模式算法,而扩展是让对象本身增量元素或行为,即样式或样貌。

所以,会用泛型,你要先具备知识,知晓有了某种前人栽的树,即知道已经有满足的可用的公共泛型函数了。

而用协议扩展,你就要自己栽树,但只给自己用在自己的地里。

有关微信小程序云开发

云开发理念

事实上测试号是不能开通云开发的,反正我本人很早开通的测试号来建立项目就没有云开发的选项,即一闪而过。然后,我就用新的邮箱来重新注册小程序的账号,注意使用新的邮箱,即未在微信平台露面过的邮箱。跃过如下的坑:1,与微信绑定的邮箱,2,公众平台的邮箱,3,开放平台的邮箱。然后,注册登录完,个人用户即可,不用缴费认证的当然有银子除外。设置云开发启用,需要立刻建立一个云环境。再用此账号来新建项目,就可以看到云开发选项了。quickstart就加载了。不得不承认,腾讯是个造生态的专家。而你要想厘清腾讯旗下生态,你要准备多个邮箱呀,至少三,四个。当你用习惯了,你就不会吐槽,反而明白,腾讯生态的用心,即独立又彼此包容。开发者有也appid,测试号也是叫appid却又分工不同。所以坑虽多,但实践更重要。倒不能称为坑,因为,刚入门时,对于场景知道的少,慢慢发现,开发者的appid偏向于项目层面运营和部署,而测试号appid应用更侧重是开发过程中编程和白盒测试。

开发小程序时,专注于业务,不用自建数据库,云函数变共享使用,图片上传API等,国内领先的思维,一站式的开发。

按流量计费的云产品,是专业的,童叟无欺。腾讯不仅懂云,也懂码仔,前端向JS看齐,进入下一代开发,即面向功能的代码片断,健全文档,即用即搬。传承着小程序的用完即走的“酷”。

上手实践

  • 本地的node环境中,需要安装几个包。小程序云开发的本地需要和远程自动默认导入的

wx-server-sdk也依赖三个包tcb-admin-node、protobuf、jstslib

  • 然后是安装CLI工具。这个最强大了,管理你腾讯云上所有资源的命令行工具,你可以想象的场景,应该有部署云函数,推拉静态文件,持续集成等,重点是结合密钥登录和shell脚本的设计,自动化运维永无止境。

npm i -g @cloudbase/cli
功能列表如下:

  • 最好的学习API方式就是读quickstart的代码和修改代码,运行看效果。

开发学习资源分享

资源一
资源二
关联资源参考
资源三

番外篇

本人原想载于知乎,不过,因为我涉嫌给腾讯广告而被禁言,看来,我的影响力已经被知乎“重视”了。同时,也试出了知乎的立场和格局。幸好,本人有个人博客,所以,真心想怼一下知乎—–“你过来呀!!!”

华山论剑之编程语言

风云再起

有人的地方,就有江湖,有码农的地方,那里就有编程语言的分争。

二十年前,中国90%的程序员=写C语言的人。编程语言三分天下。
而现在,井喷一般出现了300种编程语言。主流圈子里有一个鄙视链的。科普BSL的意思:具体是无非是看英超的瞧不起看德甲的,看德甲的看不起看意甲的,看意甲的当然受不了看中超的,也许他们都看不起中超。
所以,编程语言中搞与机器语言关系近的就看不起底层的,底层就看不起表示层的,他们也有共同点,那就是看不起用HTML开发的。
有人说“Java天下第一”就有人跳出来“PHP是最好的语言,不接受反驳!”
江湖险恶环生,你看不起kotlin吧,可是全面兼容了java这个靠山,扶摇直上三千里。
Java帝国在Web编程领域受到了PHP, Python, Ruby 持续攻击, 被搞的灰头土脸, 但是帝国的基因和运气实在是好, 竟然又搭上了手机开发和大数据快班车, 成功开辟了新战场。

C语言显然沉寂很久了,它的“徒弟”们在圈里横行霸道。
尤其是C++,python,js,java,php。割据兵器谱,叱诧TIOBE。
注:TIOBE是一种开发语言排行榜,“兵器谱”会定期更新。类似于福布斯一样。武林大会盟主之排位实在是行业的风向标。

高徒列传

如果说自古功夫出少林,那么编程语言出于C。

看过《黑客与画家》想到,如果从绘画角度来论编程语言:
C,是用点线面,黑白灰的造型能力,代表作都是素描或中国画.工具包括铅笔(笔),橡皮(墨),白纸(宣纸),简单吧.
C++,是水彩图,你可以用大小不一的毛笔,和N种颜料的调色板了.
java和c#等后续语言,让这里创作变的多元化了,油画,版画,工艺画,工具则变的有了更多种。
python的话,就打开新时代的艺术创作了,当今天的漫画家和插画家,全面应用数位板,压感笔,配合photoshop,批量引入各种素材资源。

→远去的神话–C++

学完C++的人,很少说自己精通
网友A:“吃完自己收拾的是C++程序员,留在桌子上等别人收拾的是Java程序员。”

越早的语言,对内存的使用越要严格.
举例来说,越往古代,礼法也越多.
平辈,长辈之间说话,称谓和废话很多.
会交际的人,一定说的废话是最多的.因为,交际是起于废话的.
“您吃了”,”天气不错”,”最近工作顺利吗?”
可是,这些话就像是c/C++里的,free,析构函数,*pch_XXX=NULL;或空语句等.
在编译器面前,少了如上的这些”废话”,系统就像严厉的长辈(相当于你的太爷在世),让你吃不了兜着走.
做个”懂礼貌”的程序员,会让你写的代码更安全.

→闲话python

人生苦短,我用python

足见coder对它的喜爱,现在玩点什么高大上的都需要这个“神奇胶水”。这条蟒蛇伏在系统中等着你的招呼。
他已经观察了系统很久,也观察了你很久。你准备好粮食和水(第三方模块的安装),然后,启动它,让他出洞或入地掘金或飞上九宵。python没有复杂的“礼貌”和喜欢挑细节毛病的编译器。
王朔说:

第一个人说的,叫“知识分子”。第二个,第三个,还有不知道隔了多少代隔了多少辈,俗称“八杆子打不着的”,都叫“知道分子”。

中国春秋时期的诸子百家,早已哲学过了,做人做事,出世入世。中国一部分孔子门生,一部分老子影响。自然科学发展到今天,奇点邻近,突破太难。
程序员们,扪心自问,你知道了些什么?用android开发app,用框架开发应用。你知道的是什么,只是一些工具和名词。又有多了解android的底层和框架的内部组织?又或者说,你是否有必要去知道?
软件开发中算法更是,一将功成万古枯。所以,事实上留给你的区域很有限的,可能有人认为我比较消极,但发现比发明越发重要,那么坐上python,让你随时引据经典,前人或者牛人的知识总结打包放在你面前自助pick。

→java帝国

说它不好,会被吐沫淹死。
是造生态的专家,短板很少,简直是无所不能。
排行榜几乎没跌出过前五,大厂喜欢,大牛们天天用。

本人读书时,专业课程的最高分就是java,那时做Web就是用JSP,封装就是EJB。做企业应用方向就J2EE,移动方向J2ME。
而现在你如果列java的应用框架,可以有一大箩筐。
各招聘网站上,铺天盖地的关键字与java有关。

后浪的诞生–golang

不管如何,有一款打破BSL的,把链变成环的那就是golang。
听过新闻说,golang打算用go写编译器,即“排除掉C的代码”也称为自举。而且有很大的进展。
这让C很不舒服,的确有些“欺师灭祖”之嫌。这也是我的原始想法。
golang在见过林林总总的或高级/低级,或强类型/弱类型,或表示层/后台层,或编译的/解释的的语言后出生了,老爹是google,吸引众家之长为了是取代C++。辅佐大臣是docker,以太坊。
任何的新生语言如果没有以下的特征,就没有生命力,甚至相当于直接流产:(不讨论小语种,G=golang)

  • 开源
  • 拥有GC(C的法律允许它的臣民直接操作内存,执行效率极高,但是又对内存分配回收不管不顾,全部扔给子民们去处理。人生苦短,别浪费岁月在回收内存垃圾上了)
  • unicode编码支持(G默认是UTF-8)
  • 一招鲜(如果非要让G突出一点,那么绝对是为“并发”而生)
  • 拥抱互联网以及融入现有的生态(如果互联网的安全是“地气儿”那么G可以接上,君不见,玩云的公司也都玩G)

以上几点G做的相当好,再一起简单吐槽一圈“前浪”吧:
吸收着python语法特性的营养和解释性运行的特技。python说自己性能高,G就笑了!
见过java的繁重JVM和编译器,G就有了GC和不依赖三方的开源编译器,别忘记java的编译器还在oracle的手里。
C++哈,你终于来了,python可以笑你没有语法糖,java可以笑你没有手机和移动互联网,而G不说别的,你听过协程吗?
这时台下面举手的还有一大波儿想举手发言,什么js,php……,enough!今天的发布会就到这里。

→与C互访

简单就是美

为此G不屑于C++的花式包装。让全世界的G代码,看起来都是自己写的。
就目前来讲,调用C的最简单方案绝对是G。这便是C的基因。

原理:https://www.sohu.com/a/306764682_100111840
编译的时候会在PATH中寻找gcc,这也说明G事实上可以嵌入汇编语言

G调用C实战:

→敌我不分还是反朴归真

好吧,骂声之后,冷静下来。另一个维度升起。
近十多年,从未看过在一种“徒弟”语言中那么的尊重C这位“老师”。
所以,PHP,python,java等跳出来攻击G时,是一种狭隘的自我保护。
G才是那个能让师傅荣光焕发的,误解它的原因,可能是他太过出色,光环已然超载了老师。
他更适应这个时代,是未来一段时间内开发语言的“新宠”。

python的debug方法

经过摸索在两大层面都可以进行debug调试。
一,命令行
debug是编码是非常重要的调试技巧,通过在运行过程中设置断点,帮助开发人员更好的理解运行过程。
Python中debug不像JAVA或者C++那样在IDE中设置断点那么直观。
Python的debug有两种方式: 1.在命令行中运行, 2.在脚本当中运行。两种方式都需要使用pdb模块。
方式一:在命令行中运行
$ python -m pdb my_script.py
方式二:脚本中运行

在需要设置断点的地方,插入方法 pdb.set_trace()

import pdb

def make_bread():
pdb.set_trace()
return “I don’t have time”

print(make_bread())
命令: 在进入调试状态之后,就可以输入命令进行调试了。
c: (continue)继续执行
w:(words)显示当前行的上下文信息
a:(arguments)打印当前函数的参数列表
s:(stop)执行当前行,并在顶一个可能的时机停止
n:(next)继续执行直到当前函数的下一行或者函数返回值

二,IDE中
本人使用IDLE(即python安装时带的)。
打开shell,代码窗口,和debugger。三大窗口。
第一步,在代码中可以加断点。
第二步,
在shell命令行中可以准备些环境引用,包括,
import sys
sys.path.append(“”)
当然,可以再import你写的包,或者第三方的包。
第三步,可以通过包引用来选择测试你要的任意函数。在单步调试时,可以看到所有的变量,一目了然。

对于IDE中调试,改了代码后,要重启shell,并再次引用。这一点来看不如命令行调试。

VC权威剖析:MFC原理、机制与开发实例—-读后感

基础概念和消息映射

Image
窗口:
按级别分:
桌面窗口
     顶级窗口
          子窗口
     重叠或弹出窗口
CS_PARENTDC:
     有此属性(并不是窗口风格),它可以继承父窗口的显示设备上下文。edit,button都是如此的。
WS_CHILD:
     纯子窗口,只有客户区,并且客户区的显示界面要在WM_PAINT消息处理中进行绘制。edit,button都是如此的。
WS_OVERLAPPED:
     若不同时指定WS_CHILD那么它是顶级窗口,总有标题栏WS_CAPTION和边框,并且自动设置WS_CLIPSIBLINGS。创建重叠窗口时可以指定默认大小选项CW_USEDEFAULT。
WS_POPUP:
     弹出窗口创建时,也会自动设置WS_CLIPSIBLINGS。但其它风格必须专门指定,包括WS_CAPTION,也不能指定默认大小选项。
检索窗口:可以跨进程找到窗口的句柄,因为用的是CWnd的静态函数,如下:
FindWindow()
GetWindow()
以下相对来说是内部查找了。
用于找父窗口的:
CWnd::GetParent(),可以省略CWnd
但有可能父又是别人的子,所以
CWnd::GetParentOwner()
用于找子窗口的:
CWnd::GetTopWindow()
CWnd::GetDlgItem()
CWnd::GetDescendantWindow()——–通过ID号取得窗口指针
CWnd::GetWindowFromPoint(POINT)函数取得占用父窗口客户区指定点的子窗口。实参POINT是客户区坐标。
消息:
Image
窗口消息(区别于线程消息):
     窗口消息:除了WM_COMMAND外,所有WM_开关的消息。与某类窗口紧密相关。
1,系统自动生成的窗口消息映射
2,通过类向导来生成的消息映射
3,通过宏ON_MESSAGE(message,memberFxn)
主要讲解以下三类消息,原因是类向导不能自动帮助生成,也没有系统建立好,要手工添加。包括自定义消息。
     命令消息
          菜单(工具栏,加速键)、按钮向窗口发送,要求执行某个功能操作的消息,与程序动作相关。
          用宏ON_COMMAND(id,memberFxn)来建立消息映射。加入数组的第二参数为,CN_COMMAND(内容是0,而通知消息则是非零值)
     通知消息
          MFC为每个通知消息都定义了宏,如果控件的内容变化ON_EN_CHANGE,ON_EN_UPDATE,鼠标滚动等。
          通过ON_CONTROL(wNotifyCode,id,memberFxn)来生成消息映射。其实它是ON_COMAND的重载而己。新控件都使用专门的ON_NOTIFY来建立了。它能传递更多的附加信息。如:
         纯正,新式的通知消息使用如下:
          ON_NOTIFY(TVN_KEYDOWN,IDC_TREE,OnKeydown)
          注:在两层面变化了,通知代码和处理的函数原型上,后者有实参,并引入新的结构了。
          不通过ON_CONTROL来消息映射的特殊通知消息。WM_CTLCOLOR
     反射消息
          由主窗口通过CWnd::ReflectLastMsg()发给子窗口,此函数调用了子窗口的OnChildNotify()—-ReflectChildNotify()
          在其中,就是原始的switch了。
               对旧式通知消息的反射消息和通知消息的反射消息时
               —–OnCmdMsg()
Image
命令ID:
     [0x8000,0xF000)———–全局命令,可由不同对象处理。菜单项的的ID值都在此范围内。
     小于0x8000—————-局部命令,按钮
MFC应用程序角度—-CWndApp分析

接开发者地气的些设计。它的父和子,都是一个程序从生到死的维护者。在继承的应用类实例中,把这爷仨的属性都设置了,找到相应的归宿。
有三种主窗口:单选的。事实看看MFC应用程序向导即可。
单,多文档的主窗口都是CFrameWnd(后者派生的)。而基于对话框的就不用多说了。
Image
m_pszAppName
向导中填写的工程名称,可以在CWndApp构造时传参指定。如果没有指定,会使用字符串资源“AFX_IDS_APP_TITLE”,如果还没设置这个串,将由可执行文件名代替。
属于CWndApp类
m_pszExeName
属于CWndApp类
m_pszProfileName
应用程序的INI配置文件名,在继承应用类中设置自己的配置文件 。
GetProfileString()等系列函数来配合。
属于CWndApp类(默认是执行程序.ini)
m_hInstance
模块在进程中的装入地址
属于CWndApp类
m_pMainWnd
在CSingleDocTemplate或CMultiDocTemplate构造时,就把资源文件绑定和主窗口框架类,文档类,视图类全都实例化,同时设置了此指针。基于对话框的也按其方式会设置此指针。注:没有命令行参数时,默认执行ID_FILE_NEW
文档,视图,都是MFC管理的,实例在堆上,不用手动回收。
当设置好,别忘记
ShowWindow(SW_SHOW);
UpdateWindow();
SetWindowText(“XXX程序”);
这样这个主窗口的消息循环,在Run时触发。
属于CWinThread。设置了此指针的UI窗口,在销毁时,都是安全的。
用向导也好,自己个性化改造也好,反正重载的initInstance函数至少有有模有样了。
命令行参数功能,有时在不同进程启动的相互调用时很有用。

windows核心编程(第5版)读书笔记一

第一章节 错误处理
几乎所有的windows API返回值都是下列之一:
VOID——不会失败,失败了骚扰bill gates去,
BOOL——不用说了吧,
HANDLE—失败则是NULL,当然有时是-1,
PVOID—–失败是NULL,成功就是指针喽,
LONG/DWORD—-要看具体的上下文环境了。
当调用失败,返回值会先指出已经发生错误。所以要先判断返回值。然后,使用GetLastError()来得到详细的错误提示。返回值是dword类型的,要得到描述,加入WinError.h.
技巧一:在监视中,$err,hr,就会看到调用的API错误的内容。
技巧二:使用VS的IDE小工具,error lookup
只你自己开发的模块想返回不一样的error时,可以使用SetLastError(DWORD)来写入,当然,错误代码要像点样,即32位中的29位要必须为1.而0是给系统用的。
第二章节 字符和字符串的处理
VC6——ANSI,DBCS——-/Zc:wchar_t(这个选项就会有定义wchar_t这个数据类型)
VS201X———–ANSI,UNICODE(指的是UTF-16)
事实上,typedef unsigned short wchar_t;
WinNT.h中统一了类型的名称。
TEXT(param)在unicode宏定义下,在param前加了L前缀。
所以,TCHAR也是个宏,可以配合TEXT(),_T() 来一起变脸。
unicode阵营的后缀或关键字母:
w—wide
L—-
ansi阵营的后缀或关键字母:
a—ansi
中性函数:或会变脸的,应用在两种编码下都可以编译场景,加入TChar.h配合String.h
_tcslen()会变脸成wcslen或strlen
C库的新版本的安全系列函数
1)字符串函数:加入StrSafe.h
_tcs拼加后面的选项即可cpy/cat/再拼接_s后才是安全字符串函数。第二参数为要处理的字符长度,用_countof宏(stdlib.h) 来得出字符数最好,注意不是字节数哟.
StringCch为前缀的也是安全函数。
注意:
使用微软包装的安全函数代替C库函数,好处是即时发现内存操作的异常,但有时也可能会出现“Debug Assertion Failed”对话框。当然要是debug模式下,当然也有办法屏了它,用release或定义InvailidParameterHandler函数,然后注册它,再程序运行开头加入个宏:_CrtSetReportMode(_CRT_ASSERT,0);
判断返回值必须等于宏S_OK,当不是这个值时必须要检查字符串的操作。
2)安全缓冲区函数:加入CrtDefs.h
memcpy_s——–wmemcpy_s
memmove_s——-wmemmove_s
第三章节 内核对象
有SECURITY_ATTRIBUTES结构为参数的生成才是内核对象,区别于GDI和其它的对象。
所以这也揭露了内核对象的本质是—-结构。而句柄则是—–由系统管理着的内存地址
CloseHandle()函数详析:
工作步骤:
1,验证自己主调进程中的句柄表,是否有权访问此句柄。如果有效,则获得内核对象的数据结构地址。
2,把内核对象结构使用计数减1,如果是0了,则销毁。
注意:
如果参数是无效的句柄,CloseHandle返回false,GetLastError返回ERROR_INVALD_HANDLE。如果在调试,则出现0xC0000008的异常抛出。
当函数返回前,清除当前进程的句柄表,所以以后代码不能再使用此句柄了。
当用变量保存过句柄的话,应该设置为NULL。
任务管理器是可以查看程序中的进程句柄表。
跨进程边界共享内核对象—略

windows核心编程(第5版)读书笔记二

第四章节 进程
进程内核对象在创建的时候总会处于未激发,无信号状态,但当进程终止时,系统自动会让进程对象变成激发状态,并且会永远保持这种状态。即回不到未激发状态。
C库会根据三个维度选择入口点函数:
编码,运行模式,运行环境
_tWinMain(WinMain)
wmainCRTStartup
_tmain(wMain)
_tmain(Main)
mainCRTStartup
wWinMainCRTStartup
WinMainCRTStartup
_tWinMain(wWinMain)
编码
ANSI
UNICODE
UNICODE
ANSI
ANSI
UNICODE
ANSI
UNICODE
运行模式
GUI
CUI
CUI
CUI
CUI
GUI
GUI
GUI
运行环境
WIN16
WIN32
WIN16
WIN16
WIN32
WIN32
WIN32
WIN16
在VC自有的C运行库的源代码中,crtexe.c中可以找到以上win16四个函数的源代码。
这些启动函数或者说入口函数的作用是:
1)获取指向新进程的完整命令行的一个指针
2)获取指向新进程的环境变量的一个指针
3)初始化C运行库的全局变量。如果包括了StdLib.h,就可以访问这些全局变量了。
4)初始化内存分配和IO底层
5)调用所有全局和静态C++类对象的构造函数。
系统接管,加载exe,dll到进程的一个地址空间(与链接器有关了),把这个地址返回给第一个入口函数的参数,即实例句柄。
下面可以玩这个句柄了,GetModuleFileName().
如果,你忘记实例句柄了,或没没放到全局里,不过没关系,可以用GetModuleHandle(param).参数可以是一个路径,最好是程序里用到的某个dll,要么,param就是NULL,这样就会得到运行着的当前进程的实例句柄。
命令行和环境变量,最好不要用C运行库初始化后的内容,万一时机没对,还没初始化你就读了,会出问题,所以window有厚道的API。GetCommandLine(),C运行库都在用,你凭啥找事儿,对吧。
技巧一:配合CommandLineToArgvW(GetCommandLine(),&nNum),可以得到友好的命令行参数。
这个配置和系统—》高级系统设置—》系统变量的内容是一致的。
入口点函数完后,就是进程的后事了,包括:
1)C运行库接管,调用自己的exit
2)调用_onexit()此前注册的任何一函数,假如你注册了的话。
3)调用所有全局和静态C++类对象的析构函数
4)如果有DEBUG则可以生成内存泄漏报告,可以深入去研究下。
5)C运行库来调用操作系统的ExitProcess函数,把入口点返回值以参数传入,即退出代码。这样系统就会杀死进程了,此函数返回值是void,它通知OS了,就应该无声息的over了。
注意,有时入口点返回,而有时线程可以调用ExitProcess和TerminalPorcess。
入口函数中显示使用ExitThread的函数,会让主线程退出,但如果其它线程还在工作呢?进程就不会退出,造成僵尸进程的凶手。
入口函数中显示使用ExitProcess的函数,会让C运行库函数没有执行清理资源的机会。
所以,最保险就是永远不显示的调用ExitX之类的函数。
更NB和危险的函数还有,那就是TerminalProcess,它厉害在它可以在某线程里被用,去干掉自己和别人的进程。

进程当前目录
这里要注意,因为,进程下的线程是有能力改写进程的当前目录,这也包括子进程。所以,要注意。
线程会通过GetCurrentDirectory()和SetCurrentDirectory()来存取路径。
做为进程,可以使用GetFullPathName()来看看现在的路径或者根据驱动器去环境变量里找到某路径。

windows核心编程(第5版)读书笔记三

第六章节 线程基础
创建线程,要使用_beginthreadex来代替WAPI提供的CreateThread。因为,要从编译器角度来创建。从用户角度至少看起来没有依赖OS。但事实上,里面还是用了CreateThread.
同样,杀线程,使用_endthreadex.
注:用以上两个库函数的原因是,因为,如果你用了signal函数,那么就要用_end函数来清理资源,可是那样,你就画不圆上下文了。同时使用时要注意有EX来标识的,因为存在着旧的弃用的函数。
CloseHandle是可以传已经被清理的或伪句柄的,只是它会返回false,并且对error置成ERROR_INVALID_HANDLE。
TerminalThread是异步的,只是发信号。要确定被杀的线程死了,要用WaitForSingleObject,向其传递线程句柄来守候。原理就是,线程的内核对象,当引用计数减为0时,会变成激发状态,有信号状态。
GetExitCodeThread是检查线程退出代码的。如果线程还没有退出,返回是STILL_ACTIVE宏的值。如果已经退出,返回true,并有相应值。
微软提供的C/C++库用于本机的开发。
libCMt.lib
库的静态链接发行版本
libCMtD.lib
库的静态链接调试版本
MSVCRt.lib
导入库,用于动态链接MSVCR80.dll(默认库)
MSVCRtD.lib
导入库,用于动态链接MSVCR80D.dll
MSVCMRt.lib
导入库,.net的托管/本机代码混合
MSVCURt.lib
导入库,.net的MSIL代码
线程句柄自获函数:
几乎所有的WAPI函数都要在第一参数传句柄的,所以,当你突然眼前一亮,想用WAPI了,这第一个参数必须难不住你呀。
HANDLE GetCurrentProcess();
HANDLE GetCurrentThread();
注意:以上两函数返回的是“伪句柄”
原因:
1)它们不会在进程句柄表中新建句柄,当然也不会影响引用计数。当然,CloseHandle()多释放一次,程序不死,只是它返回false。
2)它们返回的句柄要根据运行所在的进程和线程来关联。比如,在父线程中调用了,返回的句柄即使以参数传给子进程,则其指向仍然是子线程的。所以这一点有些像虚函数中的虚指针,只能意会不能言传了。
当然,有时用线程ID做些逻辑时,可以使用:
DWORD GetCurrentProcessId();
DWORD GetCurrentThreadId();
当然,如果你有了ID,你还可以换成句柄。
OpenThread(),下面示例一下转换办法并且,给出一个对进程优先级操作的技巧。
VOID SuspendProcess(DWORD dwProcessID, BOOL fSuspend)
{
     HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,dwProcessID);
     if(hSnapshot != INVALID_HANDLE_VALUE)
     {
          //walk the list of threads
          THREADENTRY32 te =  {sizeof(te)};
          BOOL fOK = Thread32First(hSnapshot, &te);
          for(; fOK; fOK = Thread32Next(hSnapshot, &te))
          {
              if(te.th32OwnerProcessID == dwProcessID)
               {
                    //主角登场
                    HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID);
                    //略过对hThread的判断
                    if(fSuspend)
                         SuspendThread(hThread);
                    else
                         ResumeThread(hThread);
                    CloseHandle(hThread);
               }
          }//endfor
          CloseHandle(hSnapshot);
     }
}
最后,再赠送两个函数用于获取进程,线程运行的时间。
GetProcessTimes(),GetThreadTimes()
第七章节 线程调度,优先级和关联性
线程可以自己挂起,但不能自己恢复,并且,挂几次要应该恢复几次(ResumeThread)。挂起可以在线程生成时以参数传入,也可以用SuspendThread来人工自由操作。
第八章节 用户模式下的线程同步
技巧:
原子操作的系列WAPI函数:InterLocked*
+ExchangeAdd
+Increment
+ExchangePointer
volatile关键字,用来声明,后面的变量不能被优化,要去不断从内存来读取。
进阶一段:CRITICAL_SECTION结构和EnterCriticalSection和LeaveCriticalSection
要声明个全局的CS变量,然后用前初始,用后删除。
TryEnterCriticalSection比较灵活,做人当如此,能锁定就锁定段,没有段可用时,就立刻通知调用者。
同时,也不要把初始化关键段看低,因为,能避免交给内核态就晚点交,不然,上下文切换的步骤很耗时,耗资源的。所以,给初始化传值或用Set来设置抢段的重试时间,InitializeCriticalSectionAndSpinCount(p1,p2),p1是句柄了,p2大约4000。
注意:
线程抢锁的顺序要一致,否则死锁,即在锁包锁的情况下。
关键段的使用只能在一个进程内来控制其中众线程的同步,并且不能根据时间来等待。
进阶二段:条件变量
线程想把锁释放并把自己阻塞,就使用条件变量。
注意,这时,你得玩两个内核对象才行,即条件变量,必须配合锁。
首先看看这个阻塞函数,我特喜欢微软用sleep来前缀,因为,可读性很高。体现了两层意思:1,这是阻塞的,2,这是有时间参数的,时间到了没拿到条件变量就是false.
SleepConditionVariableSRW或SleepConditionVariableCS看吧,后缀又说明了要配合的锁。够意思。
我不够意思了,不列参数,自己去查手册喽。
有了Sleep就得有Wake吧。它会使等待同一个条件变量被触发的线程得到锁并返回。然后就干活呗,但得到锁了就得释放它。但它不会同时唤醒其它正在等待同一个条件变量的线程。
要看自己的实际需要。反正也是有WakeAll*和共享锁和独占锁来设计。
第九章节 内核态用内核对象进行线程同步
进程和线程内核对象在操作系统的处理上一样设计的。见笔记二的进程描述。
本章节介绍了另外的内核对象来帮助我们玩转线程同步。
1,事件
2,可等待的计时器
3,信号量
4,互斥量
头大吧,不过,我们要想掌握它,必须用不同的维度和结构去3D它。
首先,了解基础,或者说这个是第一个维度。
前进了解了进程和线程,有信号和无信号的规则,那么,这四个对象呢,look
事件:
引用计数器
自动重置/手动重置———–初始参数方式,CreateEvent
是否被触发——————-函数控制,SetEvent,ResetEvent
手动重置事件:
被触发时:等待此事件的所有线程都是会变成可调度状态。
自动重置事件:
被触发时:等待此事件的一个线程,只有一个线程会变成可调度状态。
因为自动重置会在一个线程得到事件对象后,自动把自己变成未触发状态。系统代劳的。
可等待的计时器:
指定时间或每隔一定时间触发
引用计数器
自动重置/手工重置——-初始化方式,CreateWaitableTimer,和事件一样没有其它的设置方式
SetWaitTimer是生成了内核对象后,需要进一步应用时的必经之路。因为,创建后,计时器都是属于未触发状态。
信号量:
引用计数器
最大资源量————-池里的资源总数
当前资源数————-目前应用了资源的数量,用RealseSemaphore来递增
互斥量:
引用计数器
线程ID———–内部自己管理,当计数为1时,则用调用的当前线程ID来填充。
递归计数———是否要触发

windows核心编程(第5版)读书笔记四

第19–20章节 dll的基础和高级技术
入口点函数:DllMain()
一般用来执行一些进程,线程有关的初始化和清理工作。要么不实现它,要么实现正常,返回true,否则,dll可能就不能被使用。
注意:
区分大小写的,否则就是无用的。
隐式调用dll时,系统启动时就会用到DllMain(),而显式调用时,在LoadLibraryex中来调用。并且,切入点是DLL_PROCESS_ATTACH
当引用了dll的exe要建立个新线程时,会检查所以已经被调入进程空间的dll的DllMain。并传入DLL_THREAD_ATTACH。有一个例外就是主线程切入仍以process来通知dll.

VC6的环境小结

安装:
现在主要有win7,win10,但后者还没听说可以装成功。不过好在有虚机嘛。所以,只聊下win7的VC6安装。
VC6的安装源你总应该拿到,最好是SP6的。
如果是英文版本,安装会少些步骤,有一个是overwrite JIT setting的对话框,网查后我选择了否。
如果是中文版本,请寻找帖子,名为:彻底解决兼容问题:Windows 7下载安装 Visual C++ 6_0(VC6) 全程图解
一步步安装即可,VSS和MSDN都可跳过不安装。
最重要的就是插件了,这个才是彰显尊贵的手段。
filetool,wndtab,VA,VC6lineNumber
一个都不能少,全破解版(自己搜吧)。
配置:
1,用标准库,要注意<>的内容两边加空格 ,并且#pragma   warning(disable:4786)来屏闭VC6中的使用标准库的警告。
2,用C++运行程序时总是出现这个错误BSCMAKE: error BK1510 : corrupt .SBR file ‘.\Debug\StdAfx.sbr’,在C/C++—>gernal中取消生成浏览信息的选项。
3,PROJECT->SETING->C/C++->PREPROCESSOR->定义 _AFXDLL,也就是C/C++选项中定义了宏  用_AFCDLL 取代 USERDLL 能解决很多nafxcwn.lib开头的链接错误。
4,Link选项中ignore default lib,根据方式设定,手工加/NODEFAULTLIB:或者填库名。
5,VC6下导出类中的静态成员需要“壳子”才可以调用,而在VS2012中,却直接可用。当不同的环境生成的dll或客户端相互调用时,要注意字符集问题,VC6并不是unicode的。
6,要声明通用函数时,可以不加;在{}后面,但应该声明为static,这样可以避免重复定义的报错。
7,string 的split算法,replace,trim需要自己写算法,最后找到使用模板的。
8,在有unicode的项目中,在循环中使用W2A()可能会有报错,或者提示为,run-time check fail #2 stack …,内存操作越界之类,在VS2012中项目–C\C++设置中,改掉一个设置,“基本运行时检查”从“两者(/RTC1,等同于 /RTCsu) (/RTC1)”换成默认值。其实出现它的问题,还是在于使用scanf时,“%02x”的操作数组应该至少是3,要包含个’\0’的。
9,项目是要供别人调用的dll,要在配置中使用/MD.
10,要通过exe来调度dll时,要配置debug session和work directory
11,当出现外部链接错误时,要先检查link中的lib文件,是否存在于项目目录中。并不需要dll,因为只是链接步骤。
12,字符集问题,VC6是基于MBCS的(有宏定义,当然可以强制成unicode),对于中文用两字节,而字母和数字用一个字节。而VS201X,都是用unicode默认的,所以也就存在于宽字符的结构了,和一系列转来转来的操作。