2019年8月

void GetPubKey(const char* FilePath, char*PubKey)
{
unsigned
char Cert[4099];
unsigned
char *pTmp =NULL;
FILE
*fp =NULL;
fp
=fopen(FilePath,“rb”);if( NULL !=fp)
{
X509
*usrCert = NULL; //X509证书结构体,保存用户证书 unsigned long Certlen = 0;
Certlen
=fread(Cert,1,4096,fp);
fclose(fp);
//判断是否为DER编码的用户证书,并转化为X509结构体 pTmp =Cert;//usrCert = d2i_X509(NULL,(const unsigned char ** )&pTmp,Certlen);//if( NULL == usrCert) {
BIO b;
/ 判断是否为PEM格式的数字证书 */b=BIO_new_file(FilePath,“r”);
PEM_read_bio_X509(b,
&usrCert, NULL, NULL);
BIO_free(b);
if(usrCert==NULL)
{
return;
}
}
//保存证书公钥 int derpubkeyLen = 0;
EVP_PKEY pubKeytemp
=NULL;
pTmp
=NULL;char HexKey =NULL;//获取证书公钥 pubKeytemp =X509_get_pubkey(usrCert);if (!pubKeytemp)return;

X509_PUBKEY
*pubKeytempss;
pubKeytempss
=X509_get_X509_PUBKEY(usrCert);
derpubkeyLen
=i2d_PublicKey(pubKeytemp, NULL);if(derpubkeyLen < 1)return;

unsigned
char* buf =NULL;
buf
= (unsigned char*)malloc(derpubkeyLen);
i2d_PublicKey(pubKeytemp,
&buf);

EC_KEY ec_key
=EVP_PKEY_get0_EC_KEY(pubKeytemp);if (!ec_key)return;int buflen = EC_KEY_key2buf(ec_key, EC_KEY_get_conv_form(ec_key),(unsigned char)&pTmp, NULL);*BIGNUM*pub_key_BIGNUM;
pub_key_BIGNUM
=BN_new();
BN_bin2bn(pTmp, buflen, pub_key_BIGNUM);
HexKey
=BN_bn2hex(pub_key_BIGNUM);
strcpy(PubKey,HexKey);

EVP_PKEY_free(pubKeytemp);
X509_free(usrCert);

}

}

其中斜体部分也可以利用如下代码替换
EC_POINT pub_key;
unsigned char pubbuf[1024] = { 0 };//公钥数据
pub_key = (EC_POINT)EC_KEY_get0_public_key(ec_key);
EC_GROUP* group = (EC_GROUP*)EC_KEY_get0_group(ec_key);
int buflen = EC_POINT_point2oct(group, pub_key, EC_KEY_get_conv_form(ec_key), pubbuf, sizeof(pubbuf), NULL);

还有另外一种如下:
ASN1_BIT_STRING * pubkey;
pubkey = X509_get0_pubkey_bitstr(usrCert);
int nlen = pubkey->length;
pubkey->data

 

即为其公钥数据。

原文链接:https://blog.csdn.net/Elsa_Zhang/article/details/88190769

 

原地址:https://blog.csdn.net/anddy926/article/details/8940377

由于项目需要,我计划利用openssl开发一个基本的CA,实现证书的发放等功能。在项目模型中公私钥对是用户自己产生的,并且以16进制数的形似提交给CA。我们知道,通常利用openssl颁发证书时,公私钥对往往也是由openssl产生的,比如利用以下三个函数RSA_generate_key
EVP_PKEY_assign_RSA
X509_set_pubkey
便可以轻松搞定从密钥产生到载入证书的过程,而提取证书公钥只需
X509_get_pubkey
如何将16进制形式的rsa公钥载证书的却没有相关介绍,经过几天的研究终于搞定了,贴出来与大家分享,我们可以利用下面的函数
RSA* d2i_RSAPublicKey(NULL,(const unsigned **) pp,int len)
其中*pp指向存储公钥的内存单元,len指公钥的长度,请注意这里的公钥是指经过ASN.1编码的公钥,关于此编码方法,要想全面阐述是相当复杂的,但如果仅限于编rsa公钥,则会简单很多,以下是1024位rsa公钥的ASN.1编码的十六进制描述,共占据140bytes:
30 81 89 02 81 81 00 e3 8d 99 06 9f bd 9a c0 e5 
6a 5d 03 b3 cf 09 ca 8e c1 4a 6c f9 90 c2 46 e0 
89 44 69 cd a5 62 91 42 8a 5f e5 8f d3 fb 93 3f 
bc d7 6e 5e f2 80 41 a6 79 78 8e 4d 1d 3d 65 ad 
d4 36 9c c5 83 55 9d f1 bb 20 4c b7 6c 95 37 b0 
37 06 e3 40 fb 8f 74 c3 59 91 a2 bf a2 e1 db 99 
54 29 5f 9b a5 57 f5 40 7a 54 82 9c 84 d4 35 86 
14 38 69 14 60 f3 c6 c7 11 75 f2 43 2c 34 ed 89 
4a ae e1 9d 57 3e a1 02 03 01 00 01ASN.1采用Tag,Lenth,Value,编码方式,在此将整个编为一个sequence,可以理解为结构体,以30作为开始标志,第二位81代表后面有1字节代表长度,即89代表长度(若为82则代表后面有两字节代表长度,依次类推),转化成十进制为137,正好与后面的字节数吻合,从第四位02开始便是此sequence的内涵,相当于结构体的元素,一般来说sequence往往需要嵌套,相当于结构体嵌结构体,但对公钥的sequence来说,此处仅有一层。第四位02代表一下的内容为bit流,同样紧随其后的81代表有一字节代表长度,第六位的81代表长度为129,即从00开始直到最后一行a1此为129字节,去掉前面的00,余下128位便是rsa公钥的N值,最后5个字节同样是bit流,以02开始,03表示长度为3,最后的01 00 01 便是rsa公钥的E值。关于为什么要在N值前补00,这可能是ASN.1的规定,若bit流的前四bit十六进制值小于8就要在在最前补零,看下面的例子30 81 88 02 81 80 32 8d 99 06 9f bd 9a c0 e5 6a 
5d 03 b3 cf 09 ca 8e c1 4a 6c f9 90 c2 46 e0 89 
44 69 cd a5 62 91 42 8a 5f e5 8f d3 fb 93 3f bc 
d7 6e 5e f2 80 41 a6 79 78 8e 4d 1d 3d 65 ad d4 
36 9c c5 83 55 9d f1 bb 20 4c b7 6c 95 37 b0 37 
06 e3 40 fb 8f 74 c3 59 91 a2 bf a2 e1 db 99 54 
29 5f 9b a5 57 f5 40 7a 54 82 9c 84 d4 35 86 14 
38 69 14 60 f3 c6 c7 11 75 f2 43 2c 34 ed 89 4a 
ae e1 9d 57 3e a1 02 03 01 00 01N的前四bit为0x3小于8,因此无需补零。关于什么情况下要在tag值之后用8X标明有几位代表length,我的理解是,如果length的前四bit大于8或超过一字节,则必需用8X标明,否则不用。言规正传,了解了rsa公钥的编码规则,我们便可以方便的将用其他工具产生的rsa公钥编为openssl可接受的码型,从而完成公钥的导入,对于公钥的提取,同样有函数int i2d_RSAPublicKey(RSA *,(const char **))返回值为公钥的长度,当然是经ASN.1编码后的。完成了bit流与RSA的转化,剩下的工作便有很轻松了,在此在介绍几种简便方法,可以直接在bit与EVP_PKEY之间转化:导出:len=i2d_RSAPublicKey(pkey->pkey.rsa,(const char**)pp);导入要多几步:pkey->save_type=6;
pkey->type=EVP_PKEY_type(6);
pkey->pkey.rsa=d2i_RSAPublicKey(NULL,(const char**)pp,len);其中pkey的定义为EVP_PKEY *pkey;导入过程中前两行的作用是设定采用的密码算法为rsa,若采用bit-〉rsa-〉pkey模式,这个工作由EVP_PKEY_assign_RSA替我们做了。

我接触openssl4个月了,以上我的经验总结,欢迎大家批评指正。

 

 

PEM文件格式详细解析 收藏 
PEM文件格式存档

Author:Roson sun

Time:2006-4-11

1. 描述:

Openssl使用PEM(RFC 1421-1424)文档格式,如果使用其他语言包,则需要将此格式进行解码并将各个私公钥加入。

2. 说明:

a)         首先使用BASE64解码,如果是非ANSI TXT格式,需要做转换。

b)        一个RSA私钥包含一下信息(1024位):

>openssl rsa -in key.pem -noout -text

modulus:

00:d5:00:b2:18:c3:04:d1:ac:80:c6:22:a0:cc:5c:

f1:c0:4a:83:95:e5:c9:88:ae:31:64:ab:e1:15:42:

de:1a:da:bc:f5:d2:05:05:74:9d:d3:86:94:9b:9d:

74:bb:e5:72:a4:b8:40:27:61:88:d4:ac:20:b0:2b:

1c:1e:d7:9b:43:c5:06:b6:3a:b4:42:f0:5a:22:38:

23:74:99:4a:50:f1:f1:54:11:5a:44:0b:40:cf:83:

8a:73:6c:34:15:98:0a:7d:cf:0e:e5:00:8d:07:40:

f7:7d:fb:3f:64:35:1b:5d:a3:40:a9:51:fa:92:7d:

34:ef:03:fe:e0:59:56:31:25                  

数量:128

 

publicExponent:

01:00:01

数量:3

 

privateExponent:

11:e2:a8:11:ba:36:6a:60:c0:c3:62:5e:fc:2a:05:           

c6:ae:bb:13:d8:22:af:0e:69:69:59:a1:61:c6:a6:           

9d:bc:a6:47:41:e6:58:09:ed:c2:b8:37:3c:45:e1:           

6a:71:9e:c9:c4:0a:e7:03:a2:98:b1:07:61:a3:8d:           

0d:ed:ee:c4:7f:ca:fe:7d:c1:2e:2f:ca:3d:16:81:           

4f:bf:ad:6a:03:ca:d7:80:dc:57:03:fe:cf:1f:37:           

05:8d:58:79:14:01:1f:66:42:e4:f1:b6:9d:f1:01:           

37:12:f4:d8:15:c0:cc:9b:fc:ea:55:cb:2f:ba:46:           

fd:17:11:7e:43:b5:d1:15                                 

数量:128

 

prime1:

00:ed:a0:e8:25:cc:1c:aa:f5:44:e2:78:9e:54:2c:

1d:60:cb:8f:32:b3:68:6d:b3:1d:cd:a9:8c:2a:ca:

02:bc:7b:a7:8b:06:1d:fa:af:4f:8c:26:81:54:12:

ec:7d:92:20:77:85:ef:6e:06:a6:8b:9c:eb:ab:6a:

e6:a1:83:6d:a3                              

数量:64(去掉开头的0)

 

prime2:

00:e5:78:66:5a:84:22:51:78:2d:14:fc:5f:f8:4e:

45:5f:e3:b2:5e:5b:50:a4:f5:55:e0:f3:0e:98:2c:

52:61:c2:50:df:f4:b7:bc:6e:69:3e:99:ff:1c:50:

a8:89:05:7a:2b:25:91:56:a5:a6:8f:8a:ec:80:82:

fa:eb:09:c2:97                              

数量:64(去掉开头的0)

 

exponent1:

00:89:e6:26:d2:48:71:1a:84:db:44:d1:da:8f:de:

49:ee:32:33:17:a9:25:a1:03:a0:f8:08:bc:5e:d8:

7c:5e:05:24:65:79:57:4c:73:10:26:b4:f1:b8:68:

82:f5:1c:27:db:34:ce:8d:7b:2e:8b:36:b5:4c:f4:

ec:82:2e:53:21                              

数量:64(去掉开头的0)

 

exponent2:

6a:16:a6:e3:74:31:55:8f:04:f0:ad:d9:44:b8:13:

14:c8:f5:5e:f0:42:b1:71:07:5a:2f:a4:f0:af:95:

0a:c3:46:96:b3:d1:fa:58:e5:69:5e:d2:f5:e9:48:

71:c8:c9:79:87:2d:d1:6c:56:3c:08:d3:5c:7a:b1:

bc:d6:4f:53                                 

数量:64

 

coefficient:

62:dd:3f:f4:c7:30:c7:77:5e:8c:ae:c8:11:c1:23:

b0:6d:7d:07:54:8f:e7:12:1d:e1:00:ad:70:55:12:

43:f6:6f:a9:d7:94:9d:33:15:66:16:2d:d1:76:13:

33:0d:ae:6f:e3:3f:46:4b:4a:78:14:02:2e:72:66:

59:0c:2d:6a                                 

数量:64

c)        与C#中RSAParameter结构体对应表:

说明
PEM
RSAParameter


Modulus
modulus


Exponent
Exponent


prime1
P


exponent1
Q


prime2
DP


exponent2
DQ


coefficient
InverseQ


privateExponent
D

 

d)        PEM偏移(1024位,以0为开始字符,十进制)

说明
PEM私钥
PEM公钥
长度

Modulus
11
29
128

PublicExponent
141
159
3

PrivateExponent
147
×
128

Prime1
278
×
64

Prime2
345
×
64

Exponent1
412
×
64

Exponent2
478
×
64

Coefficient
545
×
64

; Generated by AutoGUI 2.6.0#SingleInstance Force
#NoEnv
SetWorkingDir
%A_ScriptDir%SetBatchLines-1#Include%A_ScriptDir%\AutoXYWH.ahk

Gui
+Resize +AlwaysOnTop +ToolWindow
Gui Add, Edit, hWndhEdtValue x0 y0 w551 h104
+Multi +0x300000Gui Show, w551 h104, 简易文本框
Return

GuiSize:
If (A_EventInfo
== 1) {
Return
}

AutoXYWH(
"wh", hEdtValue)
Return

GuiEscape:
GuiClose:
ExitApp

 

orig url: https://accu.org/index.php/journals/255

 

roperties are a feature of a number of programming languages - Visual Basic and C# are two of them. While they are not part of standard C++, they have been implemented in C++ for the CLI (popularly known as .Net) environment and Borland C++ Builder, which comes with a library of useful components which make heavy use of properties in their interfaces. And when programmers are asked their ideas for extensions to C++, properties are a popular request. [Wiegley,Vandevoorde]

So what is a property? The C++/CLI draft spec says, "A property is a member that behaves as if it were a field... Properties are used to implement data hiding within the class itself." In the class declaration, properties must be declared with a special keyword so the compiler knows to add appropriate magic:

class point {
private:
  int Xor;
  int Yor;
public:
  property int X {
    int get() {
      return Xor;
    }
    void set(int value) {
      Xor = value;
    }
  }
  ...
};

point p; p.X = 25;

In application code, properties look like ordinary data members of a class; their value can be read from and assigned to with a simple = sign. But in fact they are only pseudo-data members. Any such reference implicitly invokes an accessor function call "under the covers" and certain language features don't work with properties. One example is taking the address of a data member and assigning it to a pointer-to-member.

Let me say up front that I dislike this style of programming with properties. The subtle advantage of "hiding" a private data member by treating it as a public data member escapes me. And from the object-oriented-design point of view, I think they are highly suspect. One of the fundamental principles of OO design is that behaviour should be visible; state should not. To conceal behaviour by masquerading it as a data member is just encouraging bad habits.

Properties are syntactic saccharine for getter and setter member functions for individual fields in a class. Of course, in the quest for good design, replacing a public data member with simple get/set functions for that data member does not achieve a large increase in abstraction. A function-call syntax which does not overtly refer to manipulating data members may lead to a cleaner interface. It allows the possibility that some "data members" may be computed at runtime rather than stored. An overwhelming majority of books on OO design recommend thinking in terms of objects' behaviour, while hiding their state. Let us encourage good habits, not bad ones.

UK C++ panel member Alisdair Meredith, with almost a decade's daily experience using the Borland VCL properties, had these comments:

Properties work fantastically well in RAD development where you want interactive tools beyond a simple source code editor. For all they appear glorified get/set syntax, they make the life of the component writer much simpler. There are no strange coding conventions to follow so that things magically work, and a lot of boilerplate code vanishes. From this perspective they are most definitely A Good Thing™.

Of course the property concept goes way beyond simply supporting GUI tools, and that is where the slippery slope begins...

If functional programming is 'programming without side effects', property oriented programming is the other extreme. Everything relies on side effects that occur as you update state. For example: you have a Leftproperty in your GUI editor to determine position of a control. How would you move this control at runtime? Traditionally we might write some kind of Move() function, but now we can set the Left property instead and that will somehow magically move the control on the form as a side-effect, and maybe trigger other events with callbacks into user code as a consequence.

Experience shows that people prefer to update the Left property rather than look for some other function. After all, that is how you would perform the same task at design/compile time. Generally, code becomes manipulating properties (and expecting the side effects) rather than making explicit function calls. Again, this is the 'minimum interface' principle so that there is one and only one simple way of achieving a given result. Typically, the Move() function is never written, and this reinforces the programming style.

As we move beyond the GUI-tools arena, I find the property syntax becomes more and more confusing. I can no longer know by simple inspection of a function implementation if I can take the address of everything used as a variable, or even pass them by reference. This only gets worse when templates enter the mix.

And the problem becomes worse yet when developers become fond of using write-only properties - values which can be set to achieve the side effect, but can never be queried.

The one-sentence summary of his experience is that using properties in non-GUI classes did not help productivity: "Properties made our code easier to write, but immensely more difficult to maintain." My own experience in trying to debug code with properties bears this out. While stepping through some code to look for leaks of memory and COM interfaces, I was examining all variables by hovering the mouse over them. Multiple hovers over the same variable (or what appeared to be a simple variable) showed up a data structure with different values each time, because the underlying property function was creating an additional COM interface with each access.

My impression is that the main benefit envisioned for properties is not their syntactic sleight-of-hand but (1) their ability to be discovered through introspection/reflection and manipulated non-programmatically by some sort of Rapid Application Development tool, and (2) their ability to be stored (I think "pickled" is the term used with Java Beans) in this configured state, so that they can be loaded at runtime, already configured. [1] appears to take for granted that these features should come as a package, if standard C++ were to be extended to embrace properties.

However I might feel about using properties, I have to recognise that many people do find them useful, at least for certain types of applications. For people who do like this style of programming, at least some of the benefits can be achieved through library classes without changing the C++ language and compilers. The accompanying sample code defines some utility class templates which may be used as members of domain classes:

Property

a read-write property with data store and automatically generated get/set functions. This is what C++/CLI calls a trivial scalar property.

ROProperty

a read-only property calling a user-defined getter.

WOProperty

a write-only property calling a user-defined setter.

RWProperty

a read-write property which invokes user-defined functions.

IndexedProperty

a read-write named property with indexed access to own data store.

For programmer convenience these classes offer three redundant syntaxes for accessing their data members (or apparent data members - properties need not have real storage behind them):

  • function call syntax

  • get/set functions

  • operator = (T) and operator T() for assignment to and from properties.

The read-only and write-only property classes implement only the accessors appropriate to their semantics, but for compatibility with C++/CLI they do reserve (unimplemented) the unnecessary get or set identifier.

Instances of the utility templates as outlined in this paper do have an address, they have a type for template deduction, and they can be used in a chain of assignments. They can also be used with today's compilers and debuggers. If someone brings forward a RAD tool to read and manipulate properties through metadata, then a "property" modifier or some other marker for the tool could be added to their declaration to help in generating the metadata.

This technique, described in its basic form in C++ Report back in 1995[1], seems at least as convenient, and produces as economical source code, as most uses of properties. The basic assignment and return functions can be inlined, and therefore should be efficient. In order to support chaining, the setter functions return their new value, but for complete compatibility with C++/CLI they should have a void return type.

One objection to these that has been raised is that CLI properties allegedly take up no space inside a class, whereas a C++ subobject cannot have a size of 0 (ignoring certain clever optimizations). On the other hand, I expect that most useful properties will need some way to preserve state between set and get, and that has to take up space somewhere. The size of Property<T> takes up as much space as a single object of its template parameter, while the other three hold only a single pointer to an implementation object. Note that the Object and member function template parameters do not have to refer to the containing object, though that is likely to be the most common usage. They could delegate the processing to an external or nested helper class. The choice of implementation object (though not its type or member functions) can even be changed dynamically, and several objects could share a single implementation object.

The biggest inconvenience to these classes that I perceive is that all but the simplest Property<T> instances need to be initialized at runtime with the address of their implementation object (usually the containing class). A smaller inconvenience is that using them on the right hand side of an assignment invokes a user-defined conversion, which could affect overload resolution and a sequence of conversions.

One of the features of C++/CLI properties is that they can be declared as virtual or pure virtual, for polymorphic overriding by derived classes. This obviously is not possible with data member declarations. But if the implementation object (which usually means the containing object) is itself polymorphic and the designated member functions are virtual, then the property will behave in a polymorphic fashion.

The C++/CLI feature of default (nameless) indexed properties can be simulated with a member operator [] (except that in C++/CLI indexes can take multiple arguments, but there is a separate proposal for C++ to allow comma-separated arguments inside square brackets).

Aside from matters of stylistic preference, I can see two possible scenarios in which these classes might be useful. One scenario would be in source code which needs to be portable between C++/CLI and standard C++ environments. Using the Property<T> templates on the standard C++ side could compensate for a lack of compiler support for properties.

The second scenario would be for migrating code which uses public data members to a more encapsulated style. The class definitions could be rewritten to use the Property<T> templates, while client code need not be rewritten, only recompiled.

A brief sample program (at the end of this article) shows the utility classes in use. As it illustrates three different styles of setting and getting a property value, the expected output is this:

Name = Pinkie Platypus
Name = Kuddly Koala
Name = Willie Wombat

ID = 12345678
ID = 9999
ID = 42

Children = 42
Children = 42
Children = 42

WO function myClass::addWeight called with
                                value 2.71828
WO function myClass::addWeight called with
                                value 3.14159
WO function myClass::addWeight called with
                                value 1.61803
Secretkey = *****
Secretkey = !!!!!
Secretkey = ?????

Convenor = Herb
Minutes = Daveed
Coffee = Francis
// Some utility templates for emulating
// properties - preferring a library solution
// to a new language feature
// Each property has three sets of redundant
// acccessors:
// 1. function call syntax
// 2. get() and set() functions
// 3. overloaded operator =

// a read-write property with data store and
// automatically generated get/set functions.
// this is what C++/CLI calls a trivial scalar
// property
template <class T>
class Property {
  T data;
public:

  // access with function call syntax
  Property() : data() { }
  T operator()() const {
    return data;
  }
  T operator()(T const & value) {
    data = value;
    return data;
  }

  // access with get()/set() syntax
  T get() const {
    return data;
  }
  T set(T const & value) {
    data = value;
    return data;
  }

  // access with '=' sign
  // in an industrial-strength library,
  // specializations for appropriate types
  // might choose to add combined operators
  // like +=, etc.
  operator T() const {
    return data;
  }
  T operator=(T const & value) {
    data = value;
    return data;
  }
  typedef T value_type;
            // might be useful for template
            // deductions
};

// a read-only property calling a
// user-defined getter
template <typename T, typename Object,
          T (Object::*real_getter)()>
class ROProperty {
  Object * my_object;
public:
  ROProperty() : my_object(0) {}
  ROProperty(Object * me = 0)
               : my_object(me) {}

  // this function must be called by the
  // containing class, normally in a
  // constructor, to initialize the
  // ROProperty so it knows where its
  // real implementation code can be
  // found.
  // obj is usually the containing
  // class, but need not be; it could be a
  // special implementation object.
  void operator()(Object * obj) {
    my_object = obj;
  }

  // function call syntax
  T operator()() const {
    return (my_object->*real_getter)();
  }

  // get/set syntax
  T get() const {
    return (my_object->*real_getter)();
  }
  void set(T const & value);
            // reserved but not implemented,
            // per C++/CLI

  // use on rhs of '='
  operator T() const {
    return (my_object->*real_getter)();
  }

  typedef T value_type;
            // might be useful for template
            // deductions
};

// a write-only property calling a
// user-defined setter
template <class T, class Object,
          T (Object::*real_setter)(T const &)>
class WOProperty {
  Object * my_object;
public:
  WOProperty() : my_object(0) {}
  WOProperty(Object * me = 0)
               : my_object(me) {}

  // this function must be called by the
  // containing class, normally in a
  // constructor, to initialize the
  // WOProperty so it knows where its real
  // implementation code can be found
  void operator()(Object * obj) {
    my_object = obj;
  }
  // function call syntax
  T operator()(T const & value) {
    return (my_object->*real_setter)(value);
  }
  // get/set syntax
  T get() const;
            // reserved but not implemented,
            // per C++/CLI
  T set(T const & value) {
    return (my_object->*real_setter)(value);
  }

  // access with '=' sign
  T operator=(T const & value) {
    return (my_object->*real_setter)(value);
  }

  typedef T value_type;
            // might be useful for template
            // deductions
};

// a read-write property which invokes
// user-defined functions
template <class T,
          class Object,
          T (Object::*real_getter)(),
          T (Object::*real_setter)(T const &)>
class RWProperty {
  Object * my_object;
public:
  RWProperty() : my_object(0) {}
  RWProperty(Object * me = 0)
               : my_object(me) {}

  // this function must be called by the
  // containing class, normally in a
  // constructor, to initialize the
  // ROProperty so it knows where its
  // real implementation code can be
  // found
  void operator()(Object * obj) {
    my_object = obj;
  }

  // function call syntax
  T operator()() const {
    return (my_object->*real_getter)();
  }
  T operator()(T const & value) {
    return (my_object->*real_setter)(value);
  }

  // get/set syntax
  T get() const {
    return (my_object->*real_getter)();
  }
  T set(T const & value) {
    return (my_object->*real_setter)(value);
  }
  // access with '=' sign
  operator T() const {
    return (my_object->*real_getter)();
  }
  T operator=(T const & value) {
    return (my_object->*real_setter)(value);
  }

  typedef T value_type;
            // might be useful for template
            // deductions
};

// a read/write property providing indexed
// access.
// this class simply encapsulates a std::map
// and changes its interface to functions
// consistent with the other property<>
// classes.
// note that the interface combines certain
// limitations of std::map with
// some others from indexed properties as
// I understand them.
// an example of the first is that
// operator[] on a map will insert a
// key/value pair if it isn't already there.
// A consequence of this is that it can't
// be a const member function (and therefore
// you cannot access a const map using
// operator [].)
// an example of the second is that indexed
// properties do not appear to have any
// facility for erasing key/value pairs
// from the container.
// C++/CLI properties can have
// multi-dimensional indexes: prop[2,3].
// This is not allowed by the current rules
// of standard C++
#include <map>
template <class Key,
          class T,
          class Compare = std::less<Key>,
          class Allocator
               = std::allocator<std::pair<
                           const Key, T> > >
class IndexedProperty {
  std::map<Key, T, Compare,
           Allocator> data;
  typedef typename std::map<Key, T, Compare,
                        Allocator>::iterator
          map_iterator;
public:

  // function call syntax
  T operator()(Key const & key) {
    std::pair<map_iterator, bool> result;
    result
      = data.insert(std::make_pair(key, T()));
    return (*result.first).second;
  }
  T operator()(Key const & key,
               T const & t) {
    std::pair<map_iterator, bool> result;
    result
      = data.insert(std::make_pair(key, t));
    return (*result.first).second;
  }

  // get/set syntax
  T get_Item(Key const & key) {
    std::pair<map_iterator, bool> result;
    result
      = data.insert(std::make_pair(key, T()));
    return (*result.first).second;
  }
  T set_Item(Key const & key,
             T const & t) {
    std::pair<map_iterator, bool> result;
    result
      = data.insert(std::make_pair(key, t));
    return (*result.first).second;
  }

  // operator [] syntax
  T& operator[](Key const & key) {
    return (*((data.insert(make_pair(
                   key, T()))).first)).second;
  }
};


// =================================
// and this shows how Properties are
// accessed:
// =================================

#include <string>
#include <iostream>

class myClass {
private:
  Property<std::string> secretkey_;

  // --user-defined implementation functions--
  // in order to use these as parameters,
  // the compiler needs to see them
  // before they are used as template
  // arguments. It is possible to get rid
  // of this order dependency by writing
  // the templates with slight
  // differences, but then the program
  // must initialize them with the
  // function addresses at run time.

  // myKids is the real get function
  // supporting NumberOfChildren
  // property
  int myKids() {
    return 42;
  }
  // addWeight is the real set function
  // supporting WeightedValue property
  float addWeight(float const & value) {
    std::cout << "WO function "
              << "myClass::addWeight "
              << "called with value "
              << value
              << std::endl;
    return value;
  }
  // setSecretkey and getSecretkey support
  // the Secretkey property
  std::string setSecretkey(
                     const std::string& key) {

    // extra processing steps here

    return secretkey_(key);
  }
  std::string getSecretkey() {

    // extra processing steps here

    return secretkey_();
  }

public:
  // Name and ID are read-write properties
  // with automatic data store
  Property<std::string> Name;
  Property<long> ID;

  // Number_of_children is a read-only
  // property
  ROProperty<int, myClass,
           &myClass::myKids> NumberOfChildren;

  // WeightedValue is a write-only
  // property
  WOProperty<float, myClass,
           &myClass::addWeight> WeightedValue;

  // Secretkey is a read-write property
  // calling user-defined functions
  RWProperty<std::string, myClass,
           &myClass::getSecretkey,
           &myClass::setSecretkey> Secretkey;

  IndexedProperty<std::string,
                  std::string> Assignments;

  // constructor for this myClass object
  // must notify member properties
  // what object they belong to
  myClass() {
    NumberOfChildren(this);
    WeightedValue(this);
    Secretkey(this);
  }
};
int main() {
  myClass thing;

  // Property<> members can be accessed
  // with function syntax ...
  thing.Name("Pinkie Platypus");
  std::string s1 = thing.Name();
  std::cout << "Name = "
            << s1
            << std::endl;

  // ... or with set/get syntax ...
  thing.Name.set("Kuddly Koala");
  s1 = thing.Name.get();
  std::cout << "Name = "
            << s1
            << std::endl;

  // ... or with the assignment operator
  thing.Name = "Willie Wombat";
  s1 = thing.Name;
  std::cout << "Name = "
            << s1
            << std::endl;
  std::cout << std::endl;

  // The same applies to Property<> members
  // wrapping different data types
  thing.ID(12345678);
  long id = thing.ID();
  std::cout << "ID = "
            << id
            << std::endl;

  thing.ID.set(9999);
  id = thing.ID.get();
  std::cout << "ID = "
            << id
            << std::endl;

  thing.ID = 42;
  id = thing.ID;
  std::cout << "ID = "
            << id
            << std::endl;
  std::cout << std::endl;

  // And to ROProperty<> members
  int brats = thing.NumberOfChildren();
  std::cout << "Children = "
            << brats
            << std::endl;

  brats = thing.NumberOfChildren.get();
  std::cout << "Children = "
            << brats
            << std::endl;

  brats = thing.NumberOfChildren;
  std::cout << "Children = "
            << brats
            << std::endl;
  std::cout << std::endl;

  // And WOProperty<> members
  thing.WeightedValue(2.71828);

  thing.WeightedValue.set(3.14159);

  thing.WeightedValue = 1.618034;
  std::cout << std::endl;

  // and RWProperty<> members
  thing.Secretkey("*****");
  std::string key = thing.Secretkey();
  std::cout << "Secretkey = "
            << key
            << std::endl;

  thing.Secretkey.set("!!!!!");
  key = thing.Secretkey.get();
  std::cout << "Secretkey = "
            << key
            << std::endl;

  thing.Secretkey = "?????";
  key = thing.Secretkey;
  std::cout << "Secretkey = "
            << key
            << std::endl;
  std::cout << std::endl;

  // and IndexedProperty<> members.
  // Multiple indices in square brackets
  // not supported yet
  thing.Assignments("Convenor",
                    "Herb");
  std::string job = thing.Assignments(
                                 "Convenor");
  std::cout << "Convenor = "
            << job
            << std::endl;

  thing.Assignments.set_Item("Minutes",
                             "Daveed");
  job = thing.Assignments.get_Item(
                                 "Minutes");
  std::cout << "Minutes = "
            << job
            << std::endl;

  thing.Assignments["Coffee"] = "Francis";
  job = thing.Assignments["Coffee"];
  std::cout << "Coffee = "
            << job
            << std::endl;
  std::cout << std::endl;

  return 0;
}

References

[Wiegley] John Wiegley, PME: Properties, Methods, and Eventshttp://www.open-std.org/jtc1/sc22/wg21/docs/ papers/2002/n1384.pdf

[Vandevoorde] David Vandevoorde, C++/CLI Propertieshttp://www.open-std.org/jtc1/sc22/wg21/docs/ papers/2004/n1600.html

 

void GetWorkingFolder(std::string&folder){
folder.resize(MAX_PATH
*2 + 1, '\0'); //留长一点,防止后面再连接一个Cloudwalk时出错//获取当前程序目录,如果是C盘,则获取APPDATA目录,然后在末尾添加目录后缀 HANDLE hExeHandle =GetModuleHandle(NULL);if(hExeHandle !=nullptr) {
GetModuleFileNameA((HMODULE)hExeHandle,
&folder[0], MAX_PATH);
folder
= folder.substr(0, folder.find_last_of("\\") + 1);
}
else { //失败场景下,获取当前工作目录 if (0 == GetCurrentDirectoryA(MAX_PATH, &folder[0])) {//再失败,那就只能默认.\目录了 folder = ".";
}
}
//判断是否首字母为C,写死吧,不去判断windows是否安装在其他盘了 if ( (folder[0] == 'C') || (folder[0] == 'c') ) {
std::
string strTemp(MAX_PATH + 1, '\0');if (S_OK == SHGetFolderPathA(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_DEFAULT, &strTemp[0])) {
folder
=strTemp;
}
}
//判断最后一个字符是否为 if (folder[folder.length() - 1] != '\\') {
folder
+= '\\';
}
}