c语言uuid
A. c语言问题
UuidGreateSequential
printMACaddress没有定义,你要看看你包含的头文件#include <Rpc.h>
#include <RpcDce.h>在不在你工程下
B. C语言 运行不出的问题
首先纠正下关于return 0;的问题,它并不是赋值语句,而是C语言语句五大分类中的控制语句,其余四个分别为表达式语句,函数调用语句,空语句,复合语句。
出现这种错误是软件安装的时候路径设置出错的问题。
在工具-》选项-》目录-》目录里面修改路径,将路径修改为你软件安装的路径。
需要修改地方比较多,建议直接卸载,然后重新安装,安装过程中使用默认路径就好了
祝你好运
C. 深入浅出MFC 基础
1.c++语法要掌握.
2.windows程序设计是必需的,特别是象单文档程序,如果不了解消息处理细节,你直接上mfc的封装类,光一个CFrameWnd就可以让你深陷其中,云里雾里.
一些简单内容,直接跳过去就是了.
3.mfc学习,一本是李久近的,还是有一个国外的<深入解析mfc>.而侯俊杰的就省省吧.
1.c++法法掌握,主要是一本书<深入探索c++对象模型>.看完这本,神马语法都是浮云.
rtti,为类维护一个static类,由于static对于类的多个实例来说仍然只有一个,这样就可以通过static记录类继承信息来判断父子关系.c++编译器自动实现,只要关心相应的函数就行了.
mfc,刚好就是明显提供了这种类似的实现,主要用于消息映射表遍历.
象com类,它是用128位数,也就是uuid用来表达一个类名称,然后通过字符串比较,来判断到底要返回嘛类,这个体会一下.
D. 怎么用codeblocks编写c语言的图形程序
在codeblocks中,可以通过集成EGE库,来实现C语言图形程序的编写,具体方式如下:
一、安装:
1、下载ege安装包;
2、将安装包解压;
3、把压缩包里include目录下所有文件,复制到编译器安装目录下的include目录内,例如D:MinGWinclude;
4、把lib目录下对应编译器名目录下的文件,复制到编译器安装目录下的lib目录内,例如D:MinGWlib。
二、建立工程:
只要第1步做好以后,其实已经安装好ege了,剩下的只是配置build option.
点击file-new-projects,选择Console application:
E. 密码那些事
之前在工作中经常用密钥,但是不知道其中的原因,现在闲下来就来看下,再看的过程发现这个随机数概念很模糊,于是就查了下,现总结如下:
0x01 随机数
概述
随机数在计算机应用中使用的比较广泛,最为熟知的便是在密码学中的应用。本文主要是讲解随机数使用导致的一些Web安全风。
我们先简单了解一下随机数
分类
随机数分为真随机数和伪随机数,我们程序使用的基本都是伪随机数,其中伪随机又分为强伪随机数和弱伪随机数。
真随机数,通过物理实验得出,比如掷钱币、骰子、转轮、使用电子元件的噪音、核裂变等
伪随机数,通过一定算法和种子得出。软件实现的是伪随机数
强伪随机数,难以预测的随机数
弱伪随机数,易于预测的随机数
特性
随机数有3个特性,具体如下:
随机性:不存在统计学偏差,是完全杂乱的数列
不可预测性:不能从过去的数列推测出下一个出现的数
不可重现性:除非将数列本身保存下来,否则不能重现相同的数列
随机数的特性和随机数的分类有一定的关系,比如,弱伪随机数只需要满足随机性即可,而强位随机数需要满足随机性和不可预测性,真随机数则需要同时满足3个特性。
引发安全问题的关键点在于不可预测性。
伪随机数的生成
我们平常软件和应用实现的都是伪随机数,所以本文的重点也就是伪随机数。
伪随机数的生成实现一般是算法+种子。
具体的伪随机数生成器PRNG一般有:
线性同余法
单向散列函数法
密码法
ANSI X9.17
比较常用的一般是线性同余法,比如我们熟知的C语言的rand库和java的java.util.Random类,都采用了线性同余法生成随机数。
应用场景
随机数的应用场景比较广泛,以下是随机数常见的应用场景:
验证码生成
抽奖活动
UUID生成
SessionID生成
Token生成
CSRF Token
找回密码Token
游 戏 (随机元素的生成)
洗牌
俄罗斯方块出现特定形状的序列
游戏爆装备
密码应用场景
生成密钥:对称密码,消息认证
生成密钥对:公钥密码,数字签名
生成IV: 用于分组密码的CBC,CFB和OFB模式
生成nonce: 用于防御重放攻击; 分组密码的CTR模式
生成盐:用于基于口令的密码PBE等
0x02 随机数的安全性
相比其他密码技术,随机数很少受到关注,但随机数在密码技术和计算机应用中是非常重要的,不正确的使用随机数会导致一系列的安全问题。
随机数的安全风险
随机数导致的安全问题一般有两种
应该使用随机数,开发者并没有使用随机数;
应该使用强伪随机数,开发者使用了弱伪随机数。
第一种情况,简单来讲,就是我们需要一个随机数,但是开发者没有使用随机数,而是指定了一个常量。当然,很多人会义愤填膺的说,sb才会不用随机数。但是,请不要忽略我朝还是有很多的。主要有两个场景:
开发者缺乏基础常识不知道要用随机数;
一些应用场景和框架,接口文档不完善或者开发者没有仔细阅读等原因。
比如找回密码的token,需要一个伪随机数,很多业务直接根据用户名生成token;
比如OAuth2.0中需要第三方传递一个state参数作为CSRF Token防止CSRF攻击,很多开发者根本不使用这个参数,或者是传入一个固定的值。由于认证方无法对这个值进行业务层面有效性的校验,导致了 OAuth 的CSRF攻击。
第二种情况,主要区别就在于伪随机数的强弱了,大部分(所有?)语言的API文档中的基础库(常用库)中的random库都是弱伪随机,很多开发自然就直接使用。但是,最重要也最致命的是,弱伪随机数是不能用于密码技术的。
还是第一种情况中的找回密码场景,关于token的生成, 很多开发使用了时间戳作为随机数(md5(时间戳),md5(时间戳+用户名)),但是由于时间戳是可以预测的,很容易就被猜解。不可预测性是区分弱伪随机数和强伪随机数的关键指标。
当然,除了以上两种情况,还有一些比较特别的情况,通常情况下比较少见,但是也不排除:
种子的泄露,算法很多时候是公开的,如果种子泄露了,相当于随机数已经泄露了;
随机数池不足。这个严格来说也属于弱伪随机数,因为随机数池不足其实也导致了随机数是可预测的,攻击者可以直接暴力破解。
漏洞实例
wooyun上有很多漏洞,还蛮有意思的,都是和随机数有关的。
1.应该使用随机数而未使用随机数
Oauth2.0的这个问题特别经典,除了wooyun实例列出来的,其实很多厂商都有这个问题。
Oauth2.0中state参数要求第三方应用的开发者传入一个CSRF Token(随机数),如果没有传入或者传入的不是随机数,会导致CSRF登陆任意帐号:
唯品会账号相关漏洞可通过csrf登录任意账号
人人网 - 网络 OAuth 2.0 redirect_uir CSRF 漏洞
2.使用弱伪随机数
1) 密码取回
很多密码找回的场景,会发 送给 用户邮件一个url,中间包含一个token,这个token如果猜测,那么就可以找回其他用户的密码。
1. Shopex 4.8.5密码取回处新生成密码可预测漏洞
直接使用了时间函数microtime()作为随机数,然后获取MD5的前6位。
1. substr(md5(print_r(microtime(),true)),0,6);
php 中microtime()的值除了当前 服务器 的秒数外,还有微秒数,微妙数的变化范围在0.000000 -- 0.999999 之间,一般来说,服务器的时间可以通过HTTP返回头的DATE字段来获取,因此我们只需要遍历这1000000可能值即可。但我们要使用暴力破解的方式发起1000000次请求的话,网络请求数也会非常之大。可是shopex非常贴心的在生成密码前再次将microtime() 输出了一次:
1. $messenger = &$this->system->loadModel('system/messenger');echo microtime()."
";
2.奇虎360任意用户密码修改
直接是MD5( unix 时间戳)
3.涂鸦王国弱随机数导致任意用户劫持漏洞,附测试POC
关于找回密码随机数的问题强烈建议大家参考拓哥的11年的文章《利用系统时间可预测破解java随机数| 空虚浪子心的灵魂》
2) 其他随机数验证场景
CmsEasy最新版暴力注入(加解密缺陷/绕过防注入)
弱伪随机数被绕过
Espcms v5.6 暴力注入
Espcms中一处SQL注入漏洞的利用,利用时发现espcms对传值有加密并且随机key,但是这是一个随机数池固定的弱伪随机数,可以被攻击者遍历绕过
Destoon B2B 2014-05-21最新版绕过全局防御暴力注入(官方Demo可重现)
使用了microtime()作为随机数,可以被预测暴力破解
Android 4.4之前版本的Java加密架构(JCA)中使用的Apache Harmony 6.0M3及其之前版本的SecureRandom实现存在安全漏洞,具体位于classlib/moles/security/src/main/java/common/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java
类的engineNextBytes函数里,当用户没有提供用于产生随机数的种子时,程序不能正确调整偏移量,导致PRNG生成随机序列的过程可被预测。
Android SecureRandom漏洞详解
安全建议
上面讲的随机数基础和漏洞实例更偏重是给攻击者一些思路,这里更多的是一些防御和预防的建议。
业务场景需要使用随机数,一定要使用随机数,比如Token的生成;
随机数要足够长,避免暴力破解;
保证不同用处的随机数使用不同的种子
对安全性要求高的随机数(如密码技术相关)禁止使用的弱伪随机数:
不要使用时间函数作为随机数(很多程序员喜欢用时间戳) Java:system.currenttimemillis() php:microtime()
不要使用弱伪随机数生成器 Java: java.util.Random PHP: rand() 范围很小,32767 PHP: mt_rand() 存在缺陷
强伪随机数CSPRNG(安全可靠的伪随机数生成器(Cryptographically Secure Pseudo-Random Number Generator)的各种参考
6.强伪随机数生成(不建议开发自己实现)
产生高强度的随机数,有两个重要的因素:种子和算法。算法是可以有很多的,通常如何选择种子是非常关键的因素。 如Random,它的种子是System.currentTimeMillis(),所以它的随机数都是可预测的, 是弱伪随机数。
强伪随机数的生成思路:收集计算机的各种,键盘输入时间,内存使用状态,硬盘空闲空间,IO延时,进程数量,线程数量等信息,CPU时钟,来得到一个近似随机的种子,主要是达到不可预测性。
暂时先写到这里
F. c语言创建快捷方式
1、将C语言编辑器装在哪个文件夹下,找到那儿,应该有个比较鲜艳的图标,选中它后点右键,创建快捷方式,应该就可以了,如果找不到,那就到控制面板里面去将它卸载后重新安装的时候将它的安装路径记下来,就可以找到那儿创建快捷方式了
2、例程:
#defineSTRICT
#include<windows.h>
/*Cruntimelibraryheaders*/
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
/*COMheaders(requiresshell32.lib,ole32.lib,uuid.lib)*/
#include<objbase.h>
#include<shlobj.h>
staticHRESULTCreateShortCut(LPSTRpszTargetfile,LPSTRpszTargetargs,
LPSTRpszLinkfile,LPSTRpszDescription,
intiShowmode,LPSTRpszCurdir,
LPSTRpszIconfile,intiIconindex)
{
HRESULThRes;/*ReturnedCOMresultcode*/
IShellLink*pShellLink;/*IShellLinkobjectpointer*/
IPersistFile*pPersistFile;/*IPersistFileobjectpointer*/
WORDwszLinkfile[MAX_PATH];/*pszLinkfileasUnicodestring*/
intiWideCharsWritten;/*Numberofwidecharacterswritten*/
hRes=E_INVALIDARG;
if(
(pszTargetfile!=NULL)&&(strlen(pszTargetfile)>0)&&
(pszTargetargs!=NULL)&&
(pszLinkfile!=NULL)&&(strlen(pszLinkfile)>0)&&
(pszDescription!=NULL)&&
(iShowmode>=0)&&
(pszCurdir!=NULL)&&
(pszIconfile!=NULL)&&
(iIconindex>=0)
)
{
hRes=CoCreateInstance(&CLSID_ShellLink,/*pre-*/
NULL,/**/
CLSCTX_INPROC_SERVER,/**/
&IID_IShellLink,/*pre-*/
&pShellLink);/**/
if(SUCCEEDED(hRes))
{
/**/
hRes=pShellLink->lpVtbl->SetPath(pShellLink,pszTargetfile);
hRes=pShellLink->lpVtbl->SetArguments(pShellLink,pszTargetargs);
if(strlen(pszDescription)>0)
{
hRes=pShellLink->lpVtbl->SetDescription(pShellLink,pszDescription);
}
if(iShowmode>0)
{
hRes=pShellLink->lpVtbl->SetShowCmd(pShellLink,iShowmode);
}
if(strlen(pszCurdir)>0)
{
hRes=pShellLink->lpVtbl->SetWorkingDirectory(pShellLink,pszCurdir);
}
if(strlen(pszIconfile)>0&&iIconindex>=0)
{
hRes=pShellLink->lpVtbl->SetIconLocation(pShellLink,pszIconfile,iIconindex);
}
/**/
hRes=pShellLink->lpVtbl->QueryInterface(pShellLink,/*existingIShellLinkobject*/
&IID_IPersistFile,/*pre-*/
&pPersistFile);/**/
if(SUCCEEDED(hRes))
{
iWideCharsWritten=MultiByteToWideChar(CP_ACP,0,pszLinkfile,-1,wszLinkfile,MAX_PATH);
hRes=pPersistFile->lpVtbl->Save(pPersistFile,wszLinkfile,TRUE);
pPersistFile->lpVtbl->Release(pPersistFile);
}
pShellLink->lpVtbl->Release(pShellLink);
}
}
return(hRes);
}
intmain(intn,char**argv)
{
HRESULThRes;/*resultofcallingCOMfunctions*/
hRes=CoInitialize(NULL);
if(SUCCEEDED(hRes))
{
hRes=CreateShortCut(argv[0],
"",/*Targetarguments*/
"E:\sam.lnk",/*Short-cutfilename*/
"Samurai2",/*Short-cutdescription*/
SW_SHOW,/*Showmodeconstant*/
"",/*Workingdirectoryforlinkedfile*/
"",/*Iconfileshownforthelink*/
0);/*Indexoficoninthefile*/
}
/*callCoUninitialize()andexittheprogram.*/
CoUninitialize();
return0;
}
G. C++中怎么建立一个标准的exe文件
在COM标准中,一个组件程序也被称为一个模块,它可以是一个动态连接库(DLL), 被称为进程内组件(in-of-process component)也可以是一个可执行程序(EXE),被称为进程外组件(out-of-process component).
COM对象是建立在二进制可执行代码级的基础上,而C++等语言中的对象是建立在源代码级基础上的,因此COM对象是语言无关的。这一特性使用不同编程语言开发的组件对象进行交互成为可能。
在Microsoft Windows系统平台上,COM技术被应用于系统的各个层次,从底层的COM对象管理到上层的应用程序交互都用到了COM标准。
概述
COM既提出了组件之间进行交互的规范,也提供了实现交互的环境, 因为组件对象之间交互的规范不依赖于任何特定的语言,所以COM也可以是不同语言协作开发的一种标准。
OLE技术以COM规范为基础,OLE充分发挥了COM标准的优势,使Windows操作系统上的应用程序具有极强的可交互性。如果没有OLE的支持,Windows操作系统则会逊色很多。
但是,COM规范并不局限于OLE技术,实际上,OLE技术只是COM的一个应用而已,这几年,OLE技术在进行网络互连是显示出了很大的局限性,而COM则表现出了极强的适应能力。
COM标准包括规范和实现两大部分,规范部分定义了组件和组件之间通信的机制,这些规范不依赖于任何特定的语言和操作系统,只要按照该规范,任何语言都可以使用; COM标准的实现部分是COM库,COM库为COM规范的具体实现提供了一些核心服务。
COM是面对对象的软件模型,因而对象是他的基本要素之一。类似于C++中对象的概念,对象是某个类(class)的一个实例;而类则是一组相关的数据和功能组和在一起的一个定义。使用对象的应用(或另一个对象)成为客户,有时也成为对象的用户。
接口是一组逻辑上相关的函数集合,其函数也被称为接口成员函数。对象通过接口成员函数为客户提供各种形式的服务。
在COM模型中,对象本身对于客户来说是不可见的,客户请求服务时,只能通过接口进行。每一个接口都由一个128位的全局唯一标识符(GUID,Globally Unique Identifier)来标识。客户通过GUID获得接口的指针,在通过接口指针,客户就可以调用其相应的成员函数。
一般来说,接口是不变的,只要客户期望的接口在组建对象中还存在,它就可以继续使用该接口所提供的服务。对象可以支持多个接口,因此对组件对象的升级可通过增加接口的办法实现,这样得到的新接口可以不影响老接口的使用。
客户如何来标识COM对象呢?与接口类似,每个对象也用一个128位GUID来标识,称为CLSID(class identifier,类标识符或类ID),用CLSID标识对象可以保证(概率意义上)在全球范围内的唯一性。
只要系统中含有这类COM对象的信息,并包括COM对象所在的模块文件(DLL或EXE文件)以及COM对象在代码中的入口点,客户程序就可以由此CLSID来创建COM对象。
那么客户怎么使用COM对象所提供的服务呢?客户获得的又是什么呢?
实际上,客户成功创建对象后,它得到的是一个指向对象某个接口的指针,因为COM对象至少实现一个接口,所以客户就可以调用该接口提供的所有服务。
但是COM对象可以有自己的状态,正是这种状态才使客户感觉到COM对象的存在。如果客户同时拥有两个相同CLSID的对象,则两个对象可以有不同的状态,客户完全不必关心COM对象是怎么实现的,以及两个对象的状态数据之间有什么关系(数组或者链表)。当然,COM对象也可以是无状态的,这种COM对象以提供功能服务为主,可以用来代替传统的API函数接口,使得应用程序编程接口更为有序,组织层次性更强。
COM本身除了规范之外,也有实现的部分,其中包括一些核心的系统级代码,也正是这部分核心代码,才使得对象和客户之间可通过接口在二进制代码级进行交互 。
在Microsoft Windows操作系统环境下,这些库以.dll文件的形势存在,其中包括以下内容:
(1) 提供了少量的API函数实现客户和服务端COM应用的创建过程。在客户端,主要是一些创建函数;而在服务器端,提供一些对象的访问支持。
(2) COM通过注册表查找本地服务器即EXE程序,以及程序名与CLSID的转换等。
(3) 提供了一些标准的内存控制方法,使应用控制进程中内存的分配。
COM库一般不在应用程序层实现,而在操作系统层次上实现,因此一个操作系统只有一个COM库实现。而且COM库的实现必须依赖于具体的系统平台,尤其是系统底层的一些标准。
COM库可以保证所有的组件按照统一的方式进行交互操作,而且它使我们在编写COM应用时,可以不用编写为进行COM通信而必需的大量基础代码,而是直接利用COM库提供的API进行编程,从而大大加快了开发的速度。例如,现在COM库的版本都支持远程组件即分布式COM,我们不用编写任何网络或者RPC(remote procere call)的代码,就可以实现在网络上进行程序之间的通信。
如果我们用面向对象语言来实现COM对象,则很自然可以用类类定义对象。在C语言中,对象的概念可能变成一个逻辑概念,如果两个对象同时存在,则在接口实现中必须明确知道所进行的操作是针对哪个对象的,这个过程可由COM接口的定义保证。
COM规范使用GUID来标识COM对象的思想源于OSF(Open Software Foundation)采用的UUID(Universallz Unique Identifier), UUID被定义为DCE(Distributed Computing Environment)的一部分,主要用于表识RPC通信的双方。
除了封装性和重用性,C++对象还有一个重要特性是多态性。正是C++对象的多态性,才体现了C++语言用类描述事物的高度抽象的特征;COM对象也 具有多态性,但这种多态性需要通过COM对象所具有的接口才能体现出来,就像C++对象的多态性需要通过其(virtual)函数才能体现一样。
从API到COM接口
假如我们要实现一个字处理应用系统,它需要一个查字典的功能,按照组件化程序设计的方法,自然应该把查字典的功能放到一个组件(.dll)程序中实现。如果以后字典程序的查找算法或者字典库改变了,只要应用程序和组件之间的接口不变,则新的组件程序仍然可以被应用系统使用。这就是采用组件程序带来的灵活性。
为了把应用系统和组件程序连接起来,又能使它们协同工作,最简单的做法就是先定义一组查字典的函数,而且这组函数尽可能一般化,不要加入特定的与字典库相关的知识。
函数
功能说明
Initialize
初始化
LoadLibrary
装入字典库
InsertWord
插入一个单词
DeleteWord
删除一个单词
LookupWord
查找单词
RestoreLibrary
把内存中的字典库存入指定的文件中
FreeLibrary
释放字典库
平面型的API接口层可以很好地把两个程序连接起来,但存在以下一些问题:
(1) 当API函数非常多时,使用会非常不方便,需要对函数进行组织。
(2) API函数需要标准化,按照统一的调用方式进行处理,以适应不同的语言编程实现。参数的传递顺序,参数类型,寒暑返回处理都需要标准化。
COM定义了一套完整的接口规范,不仅可以弥补以上API作为组件借口的不足,还充分发挥了组件对象的优势,并实现了组件对象的多态性。
接口定义和标识
从技术上讲,接口是包含了一组函数的数据结构,通过这组数据结构,客户代码可以调用组件对象的功能。接口定义了一组成员函数,这组成员函数是组件对象暴露出来的所有信息,客户程序利用这些函数或的组件对象的服务。
客户程序用一个指向接口数据机构的指针来调用接口成员函数。接口指针实际上又指向另一个指针,这第二个指针指向一组函数,称为接口函数表(虚函数表),接口函数表中每一项为4个字节长的函数指针,每个函数指针与对象的具体实现连接起来。通过这种方式,客户只要获得了接口指针,就可以调用到对象的实际功能。
对于一个接口来说,他的虚函数表vtable是确定的,因此接口的成员函数个数是不变的,而且成员函数的先后顺序也是不变的;对于每个成员函数来说,其参数和返回值也是确定的。
在一个接口的定义中,所有这些信息都必须在二进制一级确定,不管什么语言,只要能支持这样的内存结构描述,也就是能够支持“structure“或“record“类型,并且这种类型能够包含双重的指向函数指针表的成员,则它就可以支持接口的描述,从而可以用于编写COM组件或者使用COM组件。
接口描述语言IDL
COM规范在采用OSF的DCE规范描述远程调用接口IDL的基础上,进行扩展形成了COM接口的描述语言。
COM规范使用的IDL接口描述语言不仅可用于定义COM接口,同时还定义了一些常用的数据类型,也可以描述自定义的数据结构,对于接口成员函数,我们可以指定每个参数的类型,输入输出特性,甚至支持可变长度的数组的描述。IDL支持指针类型,与C/C++很类似。
Microsoft Visual C++提供了MIDL工具,可以把IDL接口描述文件编译成C/C++兼容的接口描述头文件(.h)。
IUnknown的定义(IDL):
interface IUnknown
{
HRESULT QueryInterface([in] REFIID iid, [out] void **ppv);
ULONG AddRef(void);
ULONG Release(void);
}
IUnknown的定义(C++):
class IUnknown
{
Public:
virtual HRESULT _stdcall QueryInterface([in] REFIID iid, [out] void **ppv)=0;
virtual ULONG _stdcall AddRef(void)=0;
virtual ULONG _stdcall Release(void)=0;
}
进程内组件
因为进程内组件和客户程序运行在同一个进程地址空间中,所以一旦客户程序与组件程序建立起通信关系之后,客户程序得到的接口指针指向组件程序中接口的vtable,这个vtable包含了所有成员函数地址,客户代码可以直接调用这些成员函数,所以其效率非常高。
因为DLL程序是在运行时刻被客户装入到内存中的,所以DLL模块本身也是独立的,它并不依赖于客户程序。
在C++语言中,为了使编制的DLL程序更为通用,一般指定DLL的引出函数使用_stdcall调用习惯,如果使用了_cdecl调用习惯,则有些编程语言环境就不能使用这些DLL程序。C++编译器为DLL程序的每个引出函数生成了一个修饰名,这些修饰名对于不同的编译器并不兼容,因此,从通用性角度出发,我们在每个函数定义前加上extern ?C“ 说明符。在Visual C++ 开发环境中,下面的说明语句可以很好的说明一个引出函数:
extern ? C“ int _stdcall MyFunction(int n);
为了编制DLL程序,我们可以按照这样的步骤:
(1) 创建一个DLL工程
(2) 对每个引出函数,使用extern ? C“说明符,以及_stdcall修饰符,如上面对MyFunction函数的说明。
(3) 按照传统的编程方法,我们还应该编写一个DEF文件,用来描述DLL程序的模块信息。在Win32平台上,我们可以不使用DEF文件,而是直接在函数说明时使用_declspec(dllexport)说明符,例如:
extern ? C“_declspec(dllexport) int _stdcall MyFunction(int n);
按照这样的方法建立起来的DLL模块可以被其他程序调用,因为C++连接器会把所有引出函数的信息连接到最终的目标代码中。
从客户程序一方来看,有三个系统函数可用于操作DLL程序,LoadLibrary, GetProcAddress, 和FreeLibrary。
一般地,对于DLL程序的使用过程按照这样的步骤进行:
首先,客户程序使用LoadLibrary函数装入DLL,该函数返回模块的实例句柄,供以后操作该模块使用。
然后,客户程序可以调用GetProcAddress函数获得DLL中引出的函数的地址,我们既可以按函数的序号(在DEF文件中指定)也可以按函数的名字来获取引出函数的地址,因为客户程序和DLL程序在相同的内存地址空间中,所以客户程序可以直接调用这些引出函数。
最后FreeLibrary,把DLL程序卸出内存,以便释放资源。
说明:
(1) DLL程序不仅可以引出函数,也可以引出全局变量,因为客户程序和DLL程序在同一个地址空间,所以,把DLL中的全局变量引出到客户程序中是有意义的。引用的方法并不复杂,或者把变量名放到DEF文件的EXPORTS部分,并加上DATA选项; 或者在变量说明前面加上_declspec(dllexport)说明符。
(2) DumpBin 通过/Exports选项可以列出DLL程序中的所有被引出的信息。
(3) 客户程序本身也可以是一个DLL程序,但它一定先被装入到进程空间中,以便可以调用系统函数操作作为服务程序的DLL模块。
进程外组件
因为进程外组件程序和客户程序位于不同的进程空间之中,他们使用不同的地址空间,所以组件和客户之间的通信必须跨越进程边界,这就涉及到以下一些问题:
(1) 一个进程如何调用另外一个进程中的函数
(2) 参数如何从一个进程被传递到另外一个进程中
Windows平台上,在不同进程之间进行通信的办法很多,包括DDE, named pipe,或者共享内存等等,COM采用了LPC(Local Procere Call)和RPC(Remote Procere Call)
RegEdit可检查CLSID子键下的COM对象(63页)
Microsoft Visual C++提供OleView.exe,可列出当前机器上的所有类别信息,以及每一种类别下的组件对象列表。
RegSvr32 D:\DicComp\DictComp.dll
RegSvr32 /u D:\DicComp\DictComp.dll
DLL组件必须有DllRegisterServer和DllUnregisterServer两个用于注册的入口函数,才能用RegSvr32注册。
COM规定,支持自注册的进程外组件必须支持两个命令行参数/RegServer和/UnregServer,以便完成注册或注销操作。
Class Factory
实际上,客户程序并不直接调用组件程序的引出函数,它调用COM库的函数进行组件对象的创建工作,COM库的创建函数根据注册表的信息调用组件程序的入口函数来创建组件对象。组件程序需要提供一个标准的入口函数DLLGetObjectClass,用于提供本组程序的组件信息。
Class Factory和DLLGetObjectClass函数
类厂是COM对象的生产基地,COM库通过类厂创建COM对象; 对应每一个COM类,有一个类厂专门用于该COM类的对象创操作。类厂本身也是一个COM对象,它支持一个特殊的接口:IClassFactory,其定义如下:
Class IClassFactory : public IUnknown
{
virtual HRESULT _stdcall CreateInstance(IUnknown *pUnknownOuter, const IID& iid, void **ppv) = 0;
virtual HRESULT _stdcall LockServer(BOOL bLock) = 0;
};
接口IClassFactory有一个重要的成员函数CreateInstance,用于创建对应的COM对象。因为每个类厂之针对特定的COM类对象,所以CreateInstance成员函数知道该创建什么样的COM对象。在CreateInstance成员函数的参数中,第一个参数pUnknownOuter用于对象被聚合的情形,没有聚合设成NULL。IClassFactory的另一个成员函数LockServer用于控制组建的生存周期。
因为类厂本身也是个COM对象,它被用于其它COM对象的创建过程,那么类厂对象又由谁来创建呢?答案是DLLGetClassObject引出函数。DLLGetClassObject函数并不是COM库的函数,而是由组件程序实现的引出函数,我们先看一下DLLGetClassObject函数的原型:
HRESULT DLLGetClassObject(const CLSID& clsid,
Const IID& iid,
(void **) ppv
);
COM库在接到对象创建的指令后,它要调进程内组件的DLLGetClassObject函数,由该函数创类厂对象,并返回类厂对象的接口指针,COM库或者客户一旦有了类厂的接口指针,它们就可以通过类厂接口IClassFactory的成员函数CreateInstance创建相应的COM对象。
COM库与类厂的交互(67页)
在COM库中,有三个API函数可用于对象的创建,它们分别是CoGetClassObject, CoCreateInstance和CoCreateInstanceEx。通常情况下,客户程序调用其中之一完成对象的创建,并返回对象的初始接口指针。COM库与类厂也通过这三个函数进行交互。
将COM组件看成是DLL这种想法是十分肤浅的!
DLL是COM组件的一种发布形式,是一个组件服务器。
组件应看成是DLL中所实现的接口集!
DLL是一种形式,COM组件才是实质。
H. 电脑出现“不支持通用唯一标志符(uuid)类型”什么意思
英文原文:In iOS 7 and later, if you ask for the MAC address of an iOS device, the system returns the value 02:00:00:00:00:00. If you need to identify the device, use the identifierForVendor property of UIDevice instead. (Apps that need an identifier for their own advertising purposes should consider using the advertisingIdentifier property of ASIdentifierManager instead.)
翻译:从iOS7及更高版本往后,如果你向ios设备请求获取mac地址,系统将返回一个固定值“02:00:00:00:00:00”,如果你需要识别设备的 唯一性,请使用UIDevice的identifierForVendor属性。(因广告目的而需要识别设备的应用,请考虑使用 ASIdentifierManager的advertisingIdentifier属性作为替代)
这个MAC地址是指什么?有什么用?
MAC(Medium/Media Access Control)地址,用来表示互联网上每一个站点的标识符,采用十六进制数表示,共六个字节(48位)。其中,前三个字节是由IEEE的注册管理机构 RA负责给不同厂家分配的代码(高位24位),也称为“编制上唯一的标识符” (Organizationally Unique Identifier),后三个字节(低位24位)由各厂家自行指派给生产的适配器接口,称为扩展标识符(唯一性)。
MAC地址在网络上用来区分设备的唯一性,接入网络的设备都有一个MAC地址,他们肯定都是不同的,是唯一的。一部iPhone上可能有多个MAC地址,包括WIFI的、SIM的等,但是iTouch和iPad上就有一个WIFI的,因此只需获取WIFI的MAC地址就好了,也就是en0的地址。
形象的说,MAC地址就如同我们身份证上的身份证号码,具有全球唯一性。这样就可以非常好的标识设备唯一性,类似与苹果设备的UDID号,通常的用途有:1)用于一些统计与分析目的,利用用户的操作习惯和数据更好的规划产品;2)作为用户ID来唯一识别用户,可以用游客身份使用app又能在服务器端保存相应的信息,省去用户名、密码等注册过程。
那么,如何使用Mac地址生成设备的唯一标识呢?主要分三种:
直接使用“MAC Address”
使用“MD5(MAC Address)”
使用“MD5(Mac Address+bundle_id)”获得“机器+应用”的唯一标识(bundle_id 是应用的唯一标识)
iOS7之前,因为Mac地址是唯一的, 一般app开发者会采取第3种方式来识别安装对应app的设备。为什么会使用它?在iOS5之前,都是使用UDID的,后来被禁用。苹果推荐使用UUID 但是也有诸多问题,从而使用MAC地址。而MAC地址跟UDID一样,存在隐私问题,现在苹果新发布的iOS7上,如果请求Mac地址都会返回一个固定 值,那么Mac Address+bundle_id这个值大家的设备都变成一致的啦,跟UDID一样相当于被禁用。那么,要怎么标识设备唯一呢?
在iOS系统中,获取设备唯一标识的方法有很多:
一.UDID(Unique Device Identifier)
二.UUID(Universally Unique Identifier)
三.MAC Address
四.OPEN UDID
五.广告标示符(IDFA-identifierForIdentifier)
六.Vendor标示符 (IDFV-identifierForVendor)
七.推送token+bundle_id
UDID的全称是Unique Device Identifier,它就是苹果IOS设备的唯一识别码,它由40个字符的字母和数字组成(越狱的设备通过某些工具可以改变设备的UDID)。移动网络可利用UDID来识别移动设备,但是,从IOS5.0(2011年8月份)开始,苹果宣布将不再支持用uniqueIdentifier方法获取设备的UDID,iOS5以下是可以用的。在2013年3月21日苹果已经通知开发者:从2013年5月1日起,访问UIDIDs的程序将不再被审核通过,替代的方案是开发者应该使用“在iOS 6中介绍的Vendor或Advertising标示符”。所以UDID是绝对不能用啦。
OPEN UDID,没有用到MAC地址,同时能保证同一台设备上的不同应用使用同一个OpenUDID,只要用户设备上有一个使用了OpenUDID的应用存在时,其他后续安装的应用如果获取OpenUDID,都将会获得第一个应用生成的那个。但是根据贡献者的代码和方法,和一些开发者的经验,如果把使用了OpenUDID方案的应用全部都删除,再重新获取OpenUDID,此时的OpenUDID就跟以前的不一样。可见,这种方法还是不保险。
广告标示符,是iOS 6中另外一个新的方法,提供了一个方法advertisingIdentifier,通过调用该方法会返回一个NSUUID实例,最后可以获得一个UUID,由系统存储着的。不过即使这是由系统存储的,但是有几种情况下,会重新生成广告标示符。如果用户完全重置系统((设置程序 -> 通用 -> 还原 -> 还原位置与隐私) ,这个广告标示符会重新生成。另外如果用户明确的还原广告(设置程序-> 通用 -> 关于本机 -> 广告 -> 还原广告标示符) ,那么广告标示符也会重新生成。关于广告标示符的还原,有一点需要注意:如果程序在后台运行,此时用户“还原广告标示符”,然后再回到程序中,此时获取广 告标示符并不会立即获得还原后的标示符。必须要终止程序,然后再重新启动程序,才能获得还原后的广告标示符。
Vendor标示符,也是在iOS 6中新增的,跟advertisingIdentifier一样,该方法返回的是一个 NSUUID对象,可以获得一个UUID。如果满足条件“相同的一个程序里面-相同的vendor-相同的设备”,那么获取到的这个属性值就不会变。如果是“相同的程序-相同的设备-不同的vendor,或者是相同的程序-不同的设备-无论是否相同的vendor”这样的情况,那么这个值是不会相同的。
推送token+bundle_id的方法:
应用中增加推送用来获取token
获取应用bundle_id
根据token+bundle_id进行散列运算
apple push token保证设备唯一,但必须有网络情况下才能工作,该方法不依赖于设备本身,但依赖于apple push,而苹果push有时候会抽风的。
UUID是Universally Unique Identifier的缩写,中文意思是通用唯一识别码。它是让分布式系统中的所有元素,都能有唯一的辨识资讯,而不需要透过中央控制端来做辨识资讯的指定。这样,每个人都可以建立不与其它人冲突的 UUID。在此情况下,就不需考虑数据库建立时的名称重复问题。苹果公司建议使用UUID为应用生成唯一标识字符串。
iOS中获取UUID的代码如下:
-(NSString*) uuid {
CFUUIDRef puuid = CFUUIDCreate( nil );
CFStringRef uuidString = CFUUIDCreateString( nil, puuid );
NSString * result = (NSString *)CFStringCreateCopy( NULL, uuidString);
CFRelease(puuid);
CFRelease(uuidString);
return [result autorelease];
}
开发者可以在应用第一次启动时调用一 次,然后将该串存储起来,以便以后替代UDID来使用。但是,如果用户删除该应用再次安装时,又会生成新的字符串,所以不能保证唯一识别该设备。这就需要各路高手想出各种解决方案。所以,之前很多应用就采用MAC Address。但是现在如果用户升级到iOS7(及其以后的苹果系统)后,他们机子的MAC Address就是一样的,没办法做区分,只能弃用此方法,重新使用UUID来标识。如果使用UUID,就要考虑应用被删除后再重新安装时的处理。
一个解决的办法是:UUID一般只生成一次,保存在iOS系统里面,如果应用删除了,重装应用之后它的UUID还是一样的,除非系统重置 。但是不能保证在以后的系统升级后还能用(如果系统保存了该信息就能用)。
I. linux下C语言的库函数的头文件放在哪个目录下啊
一般来说是放在/usr/include目录下的;
但是这个并不局限也是可控的,如果我们进行开发过程中, 就会在内核的库函数文件目录:
例如在:/XXX/XXX/linux-X.X/include
所以根据不同的情况,头文件存放的目录也是不同的,具体需要可以根据locate和grep命令进行查询。
J. undefined reference to异常怎么解决
这是个编程链接错误,意思是说在你的程序里引用了某个函数或变量, 但是链接器找不到该变量的定义.
(1)如果报的符号是在某个第三方库里的, 比如uuid的什么什么函数, 则要检查你的libqte是不是编译得正确. 本来这些库应该正确链接到libqte.so上, 这样在qtopia链接的时候就不需要显式的加上这些库了.
有的时候libqte没有正确链接好, 但是在编译libqte阶段不会报错, 到后面qtopia或者其他应用编译的时候就出错了.
(10)c语言uuid扩展阅读:
程序错误类型
程序错误类型主要有语法错误、语义错误和逻辑错误,其中,语法错误和逻辑错误能通过编译器发现.
(1)语法错误
语法错误是因为源程序中不正确的代码产生的,即在编写程序时没有遵守语法(或词法)规则,书写了错误的语法代码,从而导致编译器无法正确解释源代码而产生的错误,通常是由于录入的错误引起的,它在词法分析或语法分析时检测出来。
(2)语义错误
语义错误是指源程序中不符合语义规则的错误,即一条语句试图执行一条不可能执行的操作而产生的错误。语义错误有的在语义分析时检测处来,有的在运行时才能检测出来。如变量声明错误、作用域错误、数据存储区的溢出等错误。
(3)逻辑错误
逻辑错误是指程序的运行结果和程序员的设想有出入时产生的错误。这类错误并不直接导致程序在编译期间和运行期间出现错误,但是程序未按预期方式执行,产生了不正确的运行结果,较难发现。这种错误只能通过分析结果,将结果与设计方案进行对比来发现。