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)邏輯錯誤
邏輯錯誤是指程序的運行結果和程序員的設想有出入時產生的錯誤。這類錯誤並不直接導致程序在編譯期間和運行期間出現錯誤,但是程序未按預期方式執行,產生了不正確的運行結果,較難發現。這種錯誤只能通過分析結果,將結果與設計方案進行對比來發現。