生成UUID算法的C语言实现-win32版本

本文介绍UUID和MD5算法的原理及实现方法,详细解释了UUID的结构、生成方式和时间戳提取过程,并提供了MD5算法的具体实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

根据定义,UUID(Universally Unique IDentifier,也称GUID)在时间和空间都是唯一的。为保证空间的唯一性,每个UUID使用了一个48位的值来记录,一般是计算机的网卡地址。 为保证时间上的唯一性,每个UUID具有一个60位的时间戳(timestamp)。这个时间戳表示自公元1582年(绝对不是1852,这是《COM技 术内幕》,1999年3月第1版第89页中的一个错误)10月15号00:00:00:00以来的时间,是以100纳秒为单位的时间间隔。1纳秒 (ns)=10-9秒(s)。UUID算法可以保证至大约公元3400年仍然唯一。UUID的C语言结构定义如下:

 
typedef struct _uuid_t
{
     unsigned long      data1;       
     unsigned short     data2;
     unsigned short     data3;
     unsigned char      data4[8];
} uuid_t;
 
它的结构大小为16个字节。即sizeof(uuid_t)==16为TRUE。写成16进制字符串的格式,一般为:
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
 
上面的字符串形式,占用36个字符,不包括结尾空字符’/0’。所以,要想容纳一个UUID字符串,必须声明为一个char[36+1]的字符数组。
 
以软件算法实现UUID非常有现实意义。参考RFC4122文档和其他一些开源代码, 我写了一个WIN32下的UUID实现C语言程序——UUID32.c。程序符合RFC4122标准。程序不但实现创建UUID和UUID String,还可以对UUID进行字符和时间上的比较。还可以从UUID从提取时间戳(精度到秒)。头文件uuid32.h定义如下:
/* uuid32.h
   2007-09-15 Last created by cheungmine.
   Partly rights reserved by cheungmine.
*/
#ifndef UUID32_H_INCLUDED
#define UUID32_H_INCLUDED

#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <memory.h>

#include "cdatatype.h"

typedef struct _timestamp_t
{
    BYTE    tm_sec;                /* Seconds after minute (0 – 59). */
    BYTE    tm_min;                /* Minutes after hour (0 – 59). */
    BYTE    tm_hour;            /* Hours after midnight (0 – 23). */
    BYTE    tm_mday;            /* Day of month (1 – 31). */
    BYTE    tm_mon;                /* Month (0 – 11; January = 0). */
    BYTE    tm_wday;            /* Day of week (0 – 6; Sunday = 0). */
    short    tm_year;            /* Year (current year minus 1900). */
    short    tm_yday;            /* Day of year (0 – 365; January 1 = 0). */
    long    tm_fraction;        /* Fraction little than 1 second */
} timestamp_t;

typedef struct _uuid_t
{
    unsigned long    data1;
    unsigned short    data2;
    unsigned short    data3;
    unsigned char    data4[8];
} uuid_t;


/**
 * Checks whether the given string matches the UUID format.
 *    params:
 *     [in] uuid - the potential UUID string
 *    return
 *     TRUE if the given string is a UUID, FALSE otherwise
 **/
BOOL is_uuid_string(const char *uuid);

/**
 * Generates a new UUID. The UUID is a time-based time 1 UUID.
 * A random per-process node identifier is used to avoid keeping global
 * state and maintaining inter-process synchronization.
 **/
void uuid_create(uuid_t* uuid);

/**
 * Generates a new UUID string. The returned UUID is a time-based time 1 UUID.
 * A random per-process node identifier is used to avoid keeping global
 * state and maintaining inter-process synchronization.
 *  return UUID string (newly allocated)
 **/
char *uuid_create_string(void);

/**
 * Generates a name-based (type 3) UUID string from the given external
 * identifier. The special namespace UUID is used as the namespace of
 * the generated UUID.
 *  params
 *     [in] external - the external identifier
 *  return
 *     UUID string (newly allocated)
 **/
void uuid_create_external(const char *external, uuid_t* uuid);

/**
 * Translate a uuid_t to a uuid string
 *  return UUID string
 **/
char *uuid_to_string(const uuid_t* uuid);

/**
 * Get timestamp from a UUID
 **/
void uuid_to_timestamp(const uuid_t* uuid, timestamp_t* time);


/**
 * Resurn a description of timestamp NOT including fraction
 **/
char* timestamp_to_string(const timestamp_t* time);

/**
 * Compare two UUID's lexically
 *    return
 *      -1   u1 is lexically before u2
 *     0   u1 is equal to u2
 *     1   u1 is lexically after u2
*/
int uuid_compare(const uuid_t *u1, const uuid_t *u2);

/**
 * Compare two UUID's temporally
 *    return
 *      -1   u1 is temporally before u2
 *     0   u1 is equal to u2
 *     1   u1 is temporally after u2
*/
int uuid_compare_time(const uuid_t *u1, const uuid_t *u2);


#endif        /* UUID32_H_INCLUDED */
 
  
       其中,头文件"cdatatype.h"如下:
 
 
/* cdatatype.h
   2008-09-15 Last created by cheungmine.
   All rights reserved by cheungmine.
*/
#ifndef CDATATYPE_H__
#define CDATATYPE_H__

/*============================================================================*/
typedef unsigned char uchar, byte, BYTE;

typedef unsigned short uint16, word_t, ushort;

typedef unsigned int uint, uint32, dword_t, size_t;

typedef unsigned long ulong;

typedef __int64 int64;
typedef unsigned __int64 uint64, qword_t;


#ifndef BOOL
    #define BOOL  int
    #define TRUE  1
    #define FALSE 0
#endif

#ifndef RESULT
    #define RESULT  long
    #define SUCCESS        0
    #define ERROR        -1
#endif

#define SIZE_BYTE    1
#define SIZE_SHORT    2
#define SIZE_INT    4
#define SIZE_FLT    4
#define SIZE_DBL    8
#define SIZE_WORD    2
#define SIZE_DWORD    4
#define SIZE_QWORD    8
#define SIZE_LINT    8
#define SIZE_INT64    8
#define SIZE_UUID    16

/*============================================================================*/
#endif    /*CDATATYPE_H__*/

           MD5算法生成的文件有:md5.h和md5.c,分别罗列如下:

#ifndef _MD5_H__
#define _MD5_H__
/* MD5.H - header file for MD5C.C */

/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
   rights reserved.

   License to copy and use this software is granted provided that it
   is identified as the "RSA Data Security, Inc. MD5 Message-Digest
   Algorithm" in all material mentioning or referencing this software
   or this function.

   License is also granted to make and use derivative works provided
   that such works are identified as "derived from the RSA Data
   Security, Inc. MD5 Message-Digest Algorithm" in all material
   mentioning or referencing the derived work.

   RSA Data Security, Inc. makes no representations concerning either
   the merchantability of this software or the suitability of this
   software for any particular purpose. It is provided "as is"
   without express or implied warranty of any kind.

   These notices must be retained in any copies of any part of this
   documentation and/or software.

   2007-09-15 Last modified by cheungmine.
 */

/* MD5 context. */
typedef struct {
    unsigned int state[4];                /* state (ABCD) */
    unsigned int count[2];                /* number of bits, modulo 2^64 (lsb first) */
    unsigned char buffer[64];    /* input buffer */
} MD5_CTX;

void  MD5_init (MD5_CTX *);
void  MD5_update (MD5_CTX *, const unsigned char *str, unsigned int len);
void  MD5_fini (unsigned char[16], MD5_CTX *);

char* MD5_sign (const unsigned char *str, unsigned int len);

#endif    /* _MD5_H__ */
/*
 * md5.c - Copyright 1997 Lachlan Roche
 *       - Modified by cheungmine, 2007-9-15
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include "md5.h"

#define MD5STR_LEN        32    


/*=====================================================================
   The remaining code is the reference MD5 code (md5c.c) from rfc1321
   MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm

   Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
   rights reserved.

   License to copy and use this software is granted provided that it
   is identified as the "RSA Data Security, Inc. MD5 Message-Digest
   Algorithm" in all material mentioning or referencing this software
   or this function.

   License is also granted to make and use derivative works provided
   that such works are identified as "derived from the RSA Data
   Security, Inc. MD5 Message-Digest Algorithm" in all material
   mentioning or referencing the derived work.

   RSA Data Security, Inc. makes no representations concerning either
   the merchantability of this software or the suitability of this
   software for any particular purpose. It is provided "as is"
   without express or implied warranty of any kind.

   These notices must be retained in any copies of any part of this
   documentation and/or software.
=====================================================================*/

/* Constants for _MD5Transform routine. */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21

static void _MD5Transform(unsigned int[4], const unsigned char[64]);
static void _Encode(unsigned char *, unsigned int *, unsigned int);
static void _Decode(unsigned int *, const unsigned char *, unsigned int);

static unsigned char PADDING[64] = {
    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

/* F, G, H and I are basic MD5 functions. */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))

/* ROTATE_LEFT rotates x left n bits. */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
   Rotation is separate from addition to prevent recomputation. */
#define FF(a, b, c, d, x, s, ac) {
 (a) += F ((b), (c), (d)) + (x) + (unsigned int)(ac);
 (a) = ROTATE_LEFT ((a), (s));
 (a) += (b);
  }
#define GG(a, b, c, d, x, s, ac) {
 (a) += G ((b), (c), (d)) + (x) + (unsigned int)(ac);
 (a) = ROTATE_LEFT ((a), (s));
 (a) += (b);
  }
#define HH(a, b, c, d, x, s, ac) {
 (a) += H ((b), (c), (d)) + (x) + (unsigned int)(ac);
 (a) = ROTATE_LEFT ((a), (s));
 (a) += (b);
  }
#define II(a, b, c, d, x, s, ac) {
 (a) += I ((b), (c), (d)) + (x) + (unsigned int)(ac);
 (a) = ROTATE_LEFT ((a), (s));
 (a) += (b);
  }

/* MD5 initialization. Begins an MD5 operation, writing a new context. */
void MD5_init(MD5_CTX * context)
{
    context->count[0] = context->count[1] = 0;
    /* Load magic initialization constants. */
    context->state[0] = 0x67452301;
    context->state[1] = 0xefcdab89;
    context->state[2] = 0x98badcfe;
    context->state[3] = 0x10325476;
}

/* MD5 block update operation. Continues an MD5 message-digest operation,
   processing another message block, and updating the context. */
void MD5_update(MD5_CTX * context, const unsigned char *input, unsigned int inputLen)
{
    unsigned int i, index, partLen;

    /* Compute number of bytes mod 64 */
    index = (unsigned int) ((context->count[0] >> 3) & 0x3F);

    /* Update number of bits */
    if ((context->count[0] += ((unsigned int) inputLen << 3)) < ((unsigned int) inputLen << 3))
        context->count[1]++;
    context->count[1] += ((unsigned int) inputLen >> 29);

    partLen = 64 - index;

    /* Transform as many times as possible. */
    if (inputLen >= partLen) {
        memcpy((void *) &context->buffer[index], (void *) input, partLen);
        _MD5Transform(context->state, context->buffer);

        for (i = partLen; i + 63 < inputLen; i += 64)
            _MD5Transform(context->state, &input[i]);

        index = 0;
    }
    else
        i = 0;

    /* Buffer remaining input */
    memcpy((void *) &context->buffer[index], (void *) &input[i], inputLen - i);
}

/* MD5 finalization. Ends an MD5 message-digest operation, writing the message digest and zeroizing the context. */
void MD5_fini(unsigned char digest[16], MD5_CTX * context)
{
    unsigned char bits[8];
    unsigned int index, padLen;

    /* Save number of bits */
    _Encode(bits, context->count, 8);

    /* Pad out to 56 mod 64. */
    index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
    padLen = (index < 56) ? (56 - index) : (120 - index);
    MD5_update(context, PADDING, padLen);

    /* Append length (before padding) */
    MD5_update(context, bits, 8);

    /* Store state in digest */
    _Encode(digest, context->state, 16);

    /* Zeroize sensitive information.*/
    memset((void *) context, 0, sizeof (*context));
}

#pragma warning(push)    /* C4996 */
#pragma warning( disable : 4996 )

char* MD5_sign (const unsigned char *str, unsigned int len)
{
    int i;
    MD5_CTX     md5;
    static char md5_str[MD5STR_LEN+1];
    char hash[16], tmp[3];
    md5_str[0] = 0;
            
    MD5_init(&md5);
    MD5_update (&md5, str, len);
    MD5_fini (hash, &md5);
        
    for ( i = 0 ; i < 16 ; i++ )
    {
        _itoa((unsigned char)hash[i], tmp , 16);

        if (tmp[1] == 0){
            tmp[2]=0;    tmp[1]=tmp[0]; tmp[0]='0';
        }
        strcat(md5_str, tmp);
    }

    return md5_str;
}

#pragma warning(pop)    /* C4996 */

/* MD5 basic transformation. Transforms state based on block. */
static void _MD5Transform(unsigned int state[4], const unsigned char block[64])
{
    unsigned int a = state[0],
                 b = state[1],
                 c = state[2],
                 d = state[3],
                 x[16];

    _Decode(x, block, 64);

    /* Round 1 */
    FF(a, b, c, d, x[0], S11, 0xd76aa478);    /* 1 */
    FF(d, a, b, c, x[1], S12, 0xe8c7b756);    /* 2 */
    FF(c, d, a, b, x[2], S13, 0x242070db);    /* 3 */
    FF(b, c, d, a, x[3], S14, 0xc1bdceee);    /* 4 */
    FF(a, b, c, d, x[4], S11, 0xf57c0faf);    /* 5 */
    FF(d, a, b, c, x[5], S12, 0x4787c62a);    /* 6 */
    FF(c, d, a, b, x[6], S13, 0xa8304613);    /* 7 */
    FF(b, c, d, a, x[7], S14, 0xfd469501);    /* 8 */
    FF(a, b, c, d, x[8], S11, 0x698098d8);    /* 9 */
    FF(d, a, b, c, x[9], S12, 0x8b44f7af);    /* 10 */
    FF(c, d, a, b, x[10], S13, 0xffff5bb1);    /* 11 */
    FF(b, c, d, a, x[11], S14, 0x895cd7be);    /* 12 */
    FF(a, b, c, d, x[12], S11, 0x6b901122);    /* 13 */
    FF(d, a, b, c, x[13], S12, 0xfd987193);    /* 14 */
    FF(c, d, a, b, x[14], S13, 0xa679438e);    /* 15 */
    FF(b, c, d, a, x[15], S14, 0x49b40821);    /* 16 */

    /* Round 2 */
    GG(a, b, c, d, x[1], S21, 0xf61e2562);    /* 17 */
    GG(d, a, b, c, x[6], S22, 0xc040b340);    /* 18 */
    GG(c, d, a, b, x[11], S23, 0x265e5a51);    /* 19 */
    GG(b, c, d, a, x[0], S24, 0xe9b6c7aa);    /* 20 */
    GG(a, b, c, d, x[5], S21, 0xd62f105d);    /* 21 */
    GG(d, a, b, c, x[10], S22, 0x2441453);    /* 22 */
    GG(c, d, a, b, x[15], S23, 0xd8a1e681);    /* 23 */
    GG(b, c, d, a, x[4], S24, 0xe7d3fbc8);    /* 24 */
    GG(a, b, c, d, x[9], S21, 0x21e1cde6);    /* 25 */
    GG(d, a, b, c, x[14], S22, 0xc33707d6);    /* 26 */
    GG(c, d, a, b, x[3], S23, 0xf4d50d87);    /* 27 */
    GG(b, c, d, a, x[8], S24, 0x455a14ed);    /* 28 */
    GG(a, b, c, d, x[13], S21, 0xa9e3e905);    /* 29 */
    GG(d, a, b, c, x[2], S22, 0xfcefa3f8);    /* 30 */
    GG(c, d, a, b, x[7], S23, 0x676f02d9);    /* 31 */
    GG(b, c, d, a, x[12], S24, 0x8d2a4c8a);    /* 32 */

    /* Round 3 */
    HH(a, b, c, d, x[5], S31, 0xfffa3942);    /* 33 */
    HH(d, a, b, c, x[8], S32, 0x8771f681);    /* 34 */
    HH(c, d, a, b, x[11], S33, 0x6d9d6122);    /* 35 */
    HH(b, c, d, a, x[14], S34, 0xfde5380c);    /* 36 */
    HH(a, b, c, d, x[1], S31, 0xa4beea44);    /* 37 */
    HH(d, a, b, c, x[4], S32, 0x4bdecfa9);    /* 38 */
    HH(c, d, a, b, x[7], S33, 0xf6bb4b60);    /* 39 */
    HH(b, c, d, a, x[10], S34, 0xbebfbc70);    /* 40 */
    HH(a, b, c, d, x[13], S31, 0x289b7ec6);    /* 41 */
    HH(d, a, b, c, x[0], S32, 0xeaa127fa);    /* 42 */
    HH(c, d, a, b, x[3], S33, 0xd4ef3085);    /* 43 */
    HH(b, c, d, a, x[6], S34, 0x4881d05);    /* 44 */
    HH(a, b, c, d, x[9], S31, 0xd9d4d039);    /* 45 */
    HH(d, a, b, c, x[12], S32, 0xe6db99e5);    /* 46 */
    HH(c, d, a, b, x[15], S33, 0x1fa27cf8);    /* 47 */
    HH(b, c, d, a, x[2], S34, 0xc4ac5665);    /* 48 */

    /* Round 4 */
    II(a, b, c, d, x[0], S41, 0xf4292244);    /* 49 */
    II(d, a, b, c, x[7], S42, 0x432aff97);    /* 50 */
    II(c, d, a, b, x[14], S43, 0xab9423a7);    /* 51 */
    II(b, c, d, a, x[5], S44, 0xfc93a039);    /* 52 */
    II(a, b, c, d, x[12], S41, 0x655b59c3);    /* 53 */
    II(d, a, b, c, x[3], S42, 0x8f0ccc92);    /* 54 */
    II(c, d, a, b, x[10], S43, 0xffeff47d);    /* 55 */
    II(b, c, d, a, x[1], S44, 0x85845dd1);    /* 56 */
    II(a, b, c, d, x[8], S41, 0x6fa87e4f);    /* 57 */
    II(d, a, b, c, x[15], S42, 0xfe2ce6e0);    /* 58 */
    II(c, d, a, b, x[6], S43, 0xa3014314);    /* 59 */
    II(b, c, d, a, x[13], S44, 0x4e0811a1);    /* 60 */
    II(a, b, c, d, x[4], S41, 0xf7537e82);    /* 61 */
    II(d, a, b, c, x[11], S42, 0xbd3af235);    /* 62 */
    II(c, d, a, b, x[2], S43, 0x2ad7d2bb);    /* 63 */
    II(b, c, d, a, x[9], S44, 0xeb86d391);    /* 64 */

    state[0] += a;
    state[1] += b;
    state[2] += c;
    state[3] += d;

    /* Zeroize sensitive information. */
    memset((void *) x, 0, sizeof (x));
}

/* Encodes input (unsigned int) into output (unsigned char). Assumes len is a multiple of 4. */
static void _Encode(unsigned char *output, unsigned int *input, unsigned int len)
{
    unsigned int i, j;

    for (i = 0, j = 0; j < len; i++, j += 4) {
        output[j] = (unsigned char) (input[i] & 0xff);
        output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
        output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
        output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
    }
}

/* Decodes input (unsigned char) into output (unsigned int). Assumes len is a multiple of 4.*/
static void _Decode(unsigned int *output, const unsigned char *input, unsigned int len)
{
    unsigned int i, j;

    for (i = 0, j = 0; j < len; i++, j += 4) {
        output[i] = ((unsigned int) input[j]) | (((unsigned int) input[j + 1]) << 8) |
                    (((unsigned int) input[j + 2]) << 16) | (((unsigned int) input[j + 3]) << 24);
    }
}

        uuid32.c文件如下:

/* uuid32.c
   2007-09-15 Last created by cheungmine.
   Partly rights reserved by cheungmine.
*/

#include <stdio.h>
#include <string.h>

#include <time.h>
#include <sys/types.h>
#include <sys/timeb.h>

#include "uuid32.h"
#include "md5.h"


#define MD5_LEN            16
#define UUID_LEN        36

/* microsecond per second. 1s=1000000us=1000000000ns*/
#define NSec100_Per_Sec        10000000
#define USec_Per_Sec        1000000
#define USec_Per_MSec        1000
#define NSec_Since_1582        ((uint64)(0x01B21DD213814000))


/*========================================================================================
                            Private Functions
========================================================================================*/
static BOOL isbigendian()
{
    int c = 1;
    return ( *((unsigned char *) &c) == 1 )? FALSE: TRUE;
};

static void swap_word( int size_bytes, void * ptr_word )
{
    int        i;
    unsigned char       temp;
    for( i=0; i < size_bytes/2; i++ )
    {
        temp = ((unsigned char *) ptr_word)[i];
        ((unsigned char *) ptr_word)[i] = ((unsigned char *) ptr_word)[size_bytes-i-1];
        ((unsigned char *) ptr_word)[size_bytes-i-1] = temp;
    }
};

static void write_word( unsigned char* stream, word_t val )
{
    memcpy(stream, &val, 2);
    if( isbigendian() ) swap_word( 2, stream );
};

static void write_dword( unsigned char* stream, dword_t val )
{
    memcpy(stream, &val, 4);
    if( isbigendian() ) swap_word( 4, stream );
};

static void  read_word( const unsigned char* stream, word_t* val )
{
    memcpy( val, stream, 2 );
    if( isbigendian() )    swap_word( 2, val );
};

static void  read_dword( const unsigned char* stream, dword_t* val )
{
    memcpy( val, stream, 4 );
    if( isbigendian() )    swap_word( 4, val );
};

static BOOL is_xdigit(char c)
{
    /* isxdigit returns a non-zero value if c is a hexadecimal digit (A – F, a – f, or 0 – 9). */
    return ((c>='A'&&c<='F')||(c>='a'&&c<='f')||(c>='0'&&c<='9'))? TRUE : FALSE;
};


/* make a pseudorandom numbel based on current time*/
static int pseudo_rand()
{
#ifdef _USE_32BIT_TIME_T
    assert(0);
#endif

    struct _timeb  timebuf;

#pragma warning(push)    /* C4996 */
#pragma warning( disable : 4996 )
    _ftime64(&timebuf);
#pragma warning(pop)    /* C4996 */
    
    srand((uint32) ((((uint32)timebuf.time&0xFFFF)+(uint32)timebuf.millitm)^(uint32)timebuf.millitm));

    return rand();
};


/*========================================================================================
                            Public Functions
========================================================================================*/

BOOL is_uuid_string(const char *uuid)
{    
    static const char fmt[] = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
    int i;
    assert(uuid != NULL);
    for (i = 0; i < sizeof(fmt); i++)
        if (fmt[i] == 'x')
            if (!is_xdigit(uuid[i]))
                return FALSE;
        else if (uuid[i] != fmt[i])
            return FALSE;

    return TRUE;
}


/**
 * internal
 * ingroup uuid
 * The thread synchronization lock used to guarantee UUID uniqueness
 * for all the threads running within a process.
 */
void uuid_create(uuid_t* u)
{    
    static BOOL        initialized = FALSE;
    static int64    timestamp;
    static uint32    advance;
    static uint16    clockseq;
    static uint16    node_high;
    static uint32    node_low;
    int64            time;    /* unit of 100ns */
    uint16            nowseq;
    int                r;

    #ifdef _USE_32BIT_TIME_T
        assert(0);
    #endif

    struct _timeb  tv;

    assert(u);

#pragma warning(push)    /* C4996 */
#pragma warning( disable : 4996 )
    _ftime64(&tv);
#pragma warning(pop)    /* C4996 */

    /* time is counter of 100ns time interval since Oct.15, 1582 (NOT 1852) */
    time = ((uint64) tv.time) * USec_Per_Sec + ((uint64) tv.millitm*USec_Per_MSec);
    time = time * 10 + NSec_Since_1582;

    if (!initialized)
    {
        timestamp = time;
        advance = 0;

        r = pseudo_rand();

        clockseq = r >> 16;
        node_high = r | 0x0100;
        
        node_low = pseudo_rand();
        
        initialized = TRUE;
    }
    else if (time < timestamp)
    {
        timestamp = time;
        advance = 0;
        clockseq++;
    }
    else if (time == timestamp)
    {
        advance++;
        time += advance;
    }
    else
    {
        timestamp = time;
        advance = 0;
    }
    nowseq = clockseq;

    assert(u);
    u->data1 = (dword_t) time;
    u->data2 = (word_t) ((time >> 32) & 0xffff);
    u->data3 = (word_t) (((time >> 48) & 0x0ffff) | 0x1000);
    write_word(&(u->data4[6]), (word_t) ((nowseq & 0x3fff) | 0x8000));    
    write_word(&(u->data4[4]), (word_t) (node_high));                    
    write_dword(&(u->data4[0]), (dword_t) (node_low));            
}

/**
 * internal
 * ingroup uuid
 * The thread synchronization lock used to guarantee UUID uniqueness
 * for all the threads running within a process.
 */
char *uuid_create_string(void)
{
    uuid_t  u;
    uuid_create(&u);
    return uuid_to_string(&u);
}

char *uuid_to_string(const uuid_t*  u)
{
    static char uuid_str[UUID_LEN+1];
    ushort a,b;
    uint32  c;
    read_word(&(u->data4[6]), &a);
    read_word(&(u->data4[4]), &b);
    read_dword(&(u->data4[0]), &c);

#pragma warning(push)    /* C4996 */
#pragma warning( disable : 4996 )
    sprintf(uuid_str, "%08lx-%04x-%04x-%04x-%04x%08lx",
                u->data1,
                u->data2,
                u->data3,
                a, b, c);
#pragma warning(pop)    /* C4996 */
    return uuid_str;
}

/**
 * internal
 * ingroup uuid
 * The predefined namespace UUID. Expressed in binary format
 * to avoid unnecessary conversion when generating name based UUIDs.
 */
static const unsigned char namespace_uuid[] = {
        0x9c, 0xfb, 0xd9, 0x1f, 0x11, 0x72, 0x4a, 0xf6,
        0xbd, 0xcb, 0x9f, 0x34, 0xe4, 0x6f, 0xa0, 0xfb
};

void  uuid_create_external(const char *external, uuid_t* u)
{
    MD5_CTX md5;
    unsigned char uuid[16];    
    
    assert(external != NULL);

    MD5_init(&md5);
    MD5_update(&md5, namespace_uuid, sizeof(namespace_uuid));
    MD5_update(&md5, (unsigned char *) external, (unsigned int) strlen(external));
    MD5_fini(uuid, &md5);

    u->data1 = (dword_t) (uuid[0] << 24 | uuid[1] << 16 | uuid[2] << 8 | uuid[3]);
    u->data2 = (word_t)  (uuid[4] << 8 | uuid[5]);
    u->data3 = (word_t)  (((uuid[6] & 0x0f) | 0x30) << 8 | uuid[7]);    
    
    /* BYTE 6-7 */
    write_word(&(u->data4[6]), (word_t) (((uuid[8] & 0x3f) | 0x80) << 8 | uuid[9]));        
    /* BYTE 4-5 */
    write_word(&(u->data4[4]), (word_t) (uuid[10] << 8 | uuid[11]));                        
    /* BYTE 0-3 */
    write_dword(&(u->data4[0]), (dword_t) (uuid[12] << 24 | uuid[13] << 16 | uuid[14] << 8 | uuid[15]));
}

/**
 * Get timestamp from a UUID
 **/
void uuid_to_timestamp(const uuid_t* u, timestamp_t* t)
{
    int64   time, t2, t3;
    struct  tm*  p;
    assert(u);

    t2 = u->data2;
    t3 = u->data3;

    time = u->data1 + (t2<<32) + ((t3&0x0fff)<<48);        /* 100ns */
    time -= NSec_Since_1582;

    t->tm_fraction = (long)(time%NSec100_Per_Sec);
    
    time /= 10;
    time /= USec_Per_Sec;
    
#pragma warning(push)    /* C4996 */
#pragma warning( disable : 4996 )
    p = _localtime64(&time);
#pragma warning(pop)    /* C4996 */
    
    t->tm_hour = p->tm_hour;
    t->tm_mday = p->tm_mday;
    t->tm_min = p->tm_min;
    t->tm_mon = p->tm_mon;
    t->tm_sec = p->tm_sec;
    t->tm_wday = p->tm_wday;
    t->tm_yday = p->tm_yday;
    t->tm_year = p->tm_year;
}

char* timestamp_to_string(const timestamp_t* time)
{
    struct tm t;
    t.tm_hour = time->tm_hour;
    t.tm_mday = time->tm_mday;
    t.tm_min = time->tm_min;
    t.tm_mon = time->tm_mon;
    t.tm_sec = time->tm_sec;
    t.tm_wday = time->tm_wday;
    t.tm_yday = time->tm_yday;
    t.tm_year = time->tm_year;

#pragma warning(push)    /* C4996 */
#pragma warning( disable : 4996 )
    return asctime(&t);
#pragma warning(pop)    /* C4996 */
}



/**
 * Compare two UUID's lexically
 *    return
 *      -1   u1 is lexically before u2
 *     0   u1 is equal to u2
 *     1   u1 is lexically after u2
*/
int uuid_compare(const uuid_t *u1, const uuid_t *u2)
{
    int i;

#define CHECK_COMP(f1, f2)  if ((f1) != (f2)) return ((f1) < (f2) ? -1 : 1);
    
    CHECK_COMP(u1->data1, u2->data1);
    CHECK_COMP(u1->data2, u2->data2);
    CHECK_COMP(u1->data3, u2->data3);

    for(i=0; i<8; i++)
        CHECK_COMP(u1->data4[i], u1->data4[i]);

#undef CHECK_COMP

    return 0;
}

/**
 * Compare two UUID's temporally
 *    return
 *      -1   u1 is temporally before u2
 *     0   u1 is equal to u2
 *     1   u1 is temporally after u2
*/
int uuid_compare_time(const uuid_t *u1, const uuid_t *u2)
{    
#define CHECK_COMP(f1, f2)  if ((f1) != (f2)) return ((f1) < (f2) ? -1 : 1);
    
    CHECK_COMP(u1->data1, u2->data1);
    CHECK_COMP(u1->data2, u2->data2);
    CHECK_COMP(u1->data3, u2->data3);

#undef CHECK_COMP

    return 0;
}

      好了,到此,所有文件都列出来了,它们是:cdatatype.h、md5.h、uuid32.h、md5.c和uuid32.c。

最后是测试代码:

/* uuidgen.c
   2007-09-15 Last created by cheungmine.
   All rights reserved by cheungmine.
   C application
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "md5.h"
#include "uuid32.h"

int main()
{
    char *sign, *uid;
    uuid_t u, v, x;
    timestamp_t  t;
    
    sign = MD5_sign("hello world", (unsigned int)strlen("hello world"));
    printf("md5 string digit:%s ", sign);
    
    uuid_create(&u);
    uid = uuid_to_string(&u);
    printf("uuid U to string:{%s} ", uid);

    uuid_create(&v);
    uid = uuid_to_string(&v);
    printf("uuid V to string:{%s} ", uid);
    
    printf("uuid compare U with V lexically:%d ", uuid_compare(&u, &v));

    printf("uuid compare V with U temporally:%d ", uuid_compare_time(&v, &u));


    uid = uuid_create_string();
    printf("new uuid string:{%s} ", uid);
        
    uuid_create_external("cheungmine", &x);
    uid = uuid_to_string(&x);
    printf("new external uuid to string:{%s} ", uid);
        
    uuid_to_timestamp(&u, &t);
    printf("%s ", timestamp_to_string(&t));
    
    return 0;
}
          以上代码保证正确。请放心使用
<think>我们正在处理一个C++问题,用户想要定义一个具有特定UUID的结构体DimStyle,并且这个结构体要继承自IDispatch接口。 根据引用[1]中的例子,我们可以看到使用__declspec(uuid("..."))来为结构体指定UUID。 同时,用户要求结构体继承IDispatch,因此我们需要在定义结构体时指定基类为IDispatch。 在C++中,结构体(struct)默认的成员访问权限是public的,而类(class)默认是private的。由于我们要继承IDispatch,并且通常COM接口都是public继承,所以这里使用struct是合适的。 因此,我们可以这样定义: struct __declspec(uuid("用户指定的UUID字符串")) DimStyle : public IDispatch { // 成员和方法 }; 注意:UUID是一个128位的全局唯一标识符,通常表示为32个十六进制数字,形式为8-4-4-4-12,例如:"00000000-0000-0000-C000-000000000046"(这是IUnknown的UUID)。 用户没有指定具体的UUID,所以我们需要提醒用户替换为实际的UUID。同时,由于IDispatch是一个接口,我们的结构体DimStyle需要实现IDispatch的所有方法(包括IUnknown的方法),或者我们可以使用某个已经实现了IDispatch的基类(如CCmdTarget等,如果使用MFC的话)来简化。 但是,用户的问题中并没有提到MFC,所以我们按照纯COM的方式来定义。 然而,直接实现IDispatch的所有方法是很复杂的,通常我们会使用ATL(Active Template Library)来简化COM对象的实现。但这里用户只要求定义结构体,所以我们先给出结构体的声明。 由于IDispatch接口已经定义(在Windows SDK中),我们需要包含相应的头文件,例如<oaidl.h>(通常通过<windows.h>或<oleauto.h>间接包含)。 因此,代码可能如下: ```cpp #include <windows.h> #include <oaidl.h> // 包含IDispatch的定义 // 使用用户提供的UUID替换下面的字符串 struct __declspec(uuid("此处替换为你的UUID")) DimStyle : public IDispatch { // 由于IDispatch是一个纯虚接口,我们必须实现它的所有纯虚函数 // 同时,IDispatch继承自IUnknown,所以也要实现IUnknown的方法 // IUnknown方法 STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject) override { // 实现QueryInterface } STDMETHOD_(ULONG, AddRef)() override { // 实现AddRef return 0; } STDMETHOD_(ULONG, Release)() override { // 实现Release return 0; } // IDispatch方法 STDMETHOD(GetTypeInfoCount)(UINT *pctinfo) override { // 实现GetTypeInfoCount return E_NOTIMPL; } STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) override { // 实现GetTypeInfo return E_NOTIMPL; } STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) override { // 实现GetIDsOfNames return E_NOTIMPL; } STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) override { // 实现Invoke return E_NOTIMPL; } }; ``` 但是,上面的实现只是一个框架,每个方法都需要根据实际需求实现。如果用户只是想要一个空的实现,那么上面的代码可以作为一个起点。 另外,我们还需要注意:在定义UUID时,必须确保它是一个有效的GUID。用户应该生成一个新的GUID或者使用已有的GUID。可以使用工具(如guidgen.exe)生成。 此外,引用[2]和[3]提到了__declspec(dllexport)和__declspec(dllimport)用于DLL导出导入,但这里用户没有提到DLL,所以我们不涉及。 最后,引用[4]是关于类型定义冲突的错误,与当前问题无关。 因此,我们给出如下定义,并提醒用户替换UUID实现接口方法。 注意:在COM中,通常我们不会直接这样实现一个接口,而是通过创建一个对象来实现接口。这里用户要求的是结构体定义,所以我们按照结构体定义给出。 如果用户需要创建一个COM对象,那么还需要实现一个类工厂,并且注册到COM中。但问题只要求结构体定义。 所以,我们最终回答如下:</think>在C++中定义具有特定UUID并继承`IDispatch`接口的结构体`DimStyle`,需使用`__declspec(uuid)`和COM接口继承语法。以下是完整实现: ```cpp #include <windows.h> #include <oaidl.h> // 包含IDispatch定义 // 定义DimStyle结构体(UUID需替换为实际值) struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) DimStyle : public IDispatch { // 必须实现IUnknown和IDispatch的纯虚方法 STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) override { if (riid == IID_IUnknown || riid == IID_IDispatch || riid == __uuidof(DimStyle)) { *ppvObject = this; AddRef(); return S_OK; } return E_NOINTERFACE; } STDMETHOD_(ULONG, AddRef)() override { /* 引用计数实现 */ return 1; } STDMETHOD_(ULONG, Release)() override { /* 引用计数实现 */ return 1; } // IDispatch方法实现占位 STDMETHOD(GetTypeInfoCount)(UINT* pctinfo) override { return E_NOTIMPL; } STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) override { return E_NOTIMPL; } STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) override { return E_NOTIMPL; } STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) override { return E_NOTIMPL; } }; ``` ### 关键说明: 1. **UUID指定** 使用`__declspec(uuid("..."))`为结构体附加GUID,格式必须为8-4-4-4-12的十六进制字符串。示例中的UUID需替换为实际值(可通过`uuidgen.exe`生成)[^1]。 2. **接口继承** `public IDispatch`表示继承COM调度接口,需实现其全部纯虚方法(包括`IUnknown`方法)。实际开发中应完善引用计数和类型信息处理[^2]。 3. **类型识别** `__uuidof(DimStyle)`在运行时获取结构体的GUID,用于`QueryInterface`的接口验证[^3]。 4. **编译要求** 需链接`ole32.lib`和`oleaut32.lib`,并确保Windows SDK头文件路径正确。 ### 注意事项: - 完整COM对象需实现类工厂和注册逻辑 - 实际项目中建议使用ATL或WTL简化实现 - 跨模块使用时需处理`__declspec(dllexport/dllimport)`[^2] ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值