Pattern/Path matching and FsRtlIsNameInExpression()

We can do path/pattern matching using FsRtlIsNameInExpression() in the windows kernel. In the kernel it is quite difficult to debug the matching issue. So I created a usermode program for FsRtlIsNameInExpression() API using the code from ReactOS.

FsRtlIsNameInExpression.cc:

#include <iostream>
#include <assert.h>
#include <tchar.h>

/* Copied from the WDDK */
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef unsigned long ULONG;

#define CONST               const
typedef wchar_t WCHAR;    // wc,   16-bit UNICODE character
typedef WCHAR *PWCHAR, *LPWCH, *PWCH;
typedef CONST WCHAR *LPCWCH, *PCWCH;

typedef UCHAR BOOLEAN;           // winnt
typedef BOOLEAN *PBOOLEAN;       // winnt

typedef UCHAR *PUCHAR;
typedef USHORT *PUSHORT;
typedef ULONG *PULONG;

#define FALSE   0
#define TRUE    1

#define FSRTL_FAT_LEGAL                 0x01
#define FSRTL_HPFS_LEGAL                0x02
#define FSRTL_NTFS_LEGAL                0x04
#define FSRTL_WILD_CHARACTER            0x08
#define FSRTL_OLE_LEGAL                 0x10
#define FSRTL_NTFS_STREAM_LEGAL         (FSRTL_NTFS_LEGAL | FSRTL_OLE_LEGAL)

#define DOS_STAR                        (L'<‘)
#define DOS_QM                          (L’>’)
#define DOS_DOT                         (L'”‘)

static UCHAR LegalAnsiCharacterArray[] =
{
  0,                                                        /* CTRL+@, 0x00 */
  0,                                                        /* CTRL+A, 0x01 */
  0,                                                        /* CTRL+B, 0x02 */
  0,                                                        /* CTRL+C, 0x03 */
  0,                                                        /* CTRL+D, 0x04 */
  0,                                                        /* CTRL+E, 0x05 */
  0,                                                        /* CTRL+F, 0x06 */
  0,                                                        /* CTRL+G, 0x07 */
  0,                                                        /* CTRL+H, 0x08 */
  0,                                                        /* CTRL+I, 0x09 */
  0,                                                        /* CTRL+J, 0x0a */
  0,                                                        /* CTRL+K, 0x0b */
  0,                                                        /* CTRL+L, 0x0c */
  0,                                                        /* CTRL+M, 0x0d */
  0,                                                        /* CTRL+N, 0x0e */
  0,                                                        /* CTRL+O, 0x0f */
  0,                                                        /* CTRL+P, 0x10 */
  0,                                                        /* CTRL+Q, 0x11 */
  0,                                                        /* CTRL+R, 0x12 */
  0,                                                        /* CTRL+S, 0x13 */
  0,                                                        /* CTRL+T, 0x14 */
  0,                                                        /* CTRL+U, 0x15 */
  0,                                                        /* CTRL+V, 0x16 */
  0,                                                        /* CTRL+W, 0x17 */
  0,                                                        /* CTRL+X, 0x18 */
  0,                                                        /* CTRL+Y, 0x19 */
  0,                                                        /* CTRL+Z, 0x1a */
  0,                                                        /* CTRL+[, 0x1b */
  0,                                                        /* CTRL+\, 0x1c */
  0,                                                        /* CTRL+], 0x1d */
  0,                                                        /* CTRL+^, 0x1e */
  0,                                                        /* CTRL+_, 0x1f */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* ` ‘,    0x20 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `!’,    0x21 */
  FSRTL_WILD_CHARACTER,                                     /* `”‘,    0x22 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `#’,    0x23 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `$’,    0x24 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `%’,    0x25 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `&’,    0x26 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `”,    0x27 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `(‘,    0x28 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `)’,    0x29 */
  FSRTL_WILD_CHARACTER,                                     /* `*’,    0x2a */
  FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,                      /* `+’,    0x2b */
  FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,                      /* `,’,    0x2c */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `-‘,    0x2d */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `.’,    0x2e */
  0,                                                        /* `/’,    0x2f */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `0′,    0x30 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `1′,    0x31 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `2′,    0x32 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `3′,    0x33 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `4′,    0x34 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `5′,    0x35 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `6′,    0x36 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `7′,    0x37 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `8′,    0x38 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `9′,    0x39 */
  FSRTL_NTFS_LEGAL,                                         /* `:’,    0x3a */
  FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,                      /* `;’,    0x3b */
  FSRTL_WILD_CHARACTER,                                     /* `<‘,    0x3c */
  FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,                      /* `=’,    0x3d */
  FSRTL_WILD_CHARACTER,                                     /* `>’,    0x3e */
  FSRTL_WILD_CHARACTER,                                     /* `?’,    0x3f */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `@’,    0x40 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `A’,    0x41 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `B’,    0x42 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `C’,    0x43 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `D’,    0x44 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `E’,    0x45 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `F’,    0x46 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `G’,    0x47 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `H’,    0x48 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `I’,    0x49 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `J’,    0x4a */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `K’,    0x4b */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `L’,    0x4c */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `M’,    0x4d */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `N’,    0x4e */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `O’,    0x4f */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `P’,    0x50 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `Q’,    0x51 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `R’,    0x52 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `S’,    0x53 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `T’,    0x54 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `U’,    0x55 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `V’,    0x56 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `W’,    0x57 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `X’,    0x58 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `Y’,    0x59 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `Z’,    0x5a */
  FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,                      /* `[‘,    0x5b */
  0,                                                        /* `\’,    0x5c */
  FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,                      /* `]’,    0x5d */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `^’,    0x5e */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `_’,    0x5f */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* “’,    0x60 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `a’,    0x61 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `b’,    0x62 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `c’,    0x63 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `d’,    0x64 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `e’,    0x65 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `f’,    0x66 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `g’,    0x67 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `h’,    0x68 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `i’,    0x69 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `j’,    0x6a */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `k’,    0x6b */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `l’,    0x6c */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `m’,    0x6d */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `n’,    0x6e */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `o’,    0x6f */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `p’,    0x70 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `q’,    0x71 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `r’,    0x72 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `s’,    0x73 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `t’,    0x74 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `u’,    0x75 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `v’,    0x76 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `w’,    0x77 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `x’,    0x78 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `y’,    0x79 */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `z’,    0x7a */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `{‘,    0x7b */
  0,                                                        /* `|’,    0x7c */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `}’,    0x7d */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL,    /* `~’,    0x7e */
  FSRTL_FAT_LEGAL | FSRTL_HPFS_LEGAL | FSRTL_NTFS_LEGAL     /*         0x7f */
};

PUCHAR FsRtlLegalAnsiCharacterArray = LegalAnsiCharacterArray;
#define FlagOn(_F,_SF)        ((_F) & (_SF))

#define FsRtlIsUnicodeCharacterWild(C) (                                    \
     (((C) >= 0x40) ?                                                        \
     FALSE :                                                                 \
     FlagOn(FsRtlLegalAnsiCharacterArray[(C)], FSRTL_WILD_CHARACTER ))       \
)

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWCH   Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;

/* End of Copy */

//http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/fsrtl/name.c?revision=48461&view=co&pathrev=48461
BOOLEAN FsRtlDoesNameContainWildCards( PUNICODE_STRING Name);
BOOLEAN FsRtlIsNameInExpression(PUNICODE_STRING Expression,PUNICODE_STRING Name,BOOLEAN IgnoreCase,PWCHAR UpcaseTable );
BOOLEAN FsRtlIsNameInExpressionPrivate(PUNICODE_STRING Pattern,PUNICODE_STRING Data,BOOLEAN IgnoreCase,PWCHAR UpcaseTable );

BOOLEAN FsRtlDoesNameContainWildCards(PUNICODE_STRING Name)
{
    PWCHAR Ptr;

    /* Loop through every character */
    if (Name->Length)
    {
        Ptr = Name->Buffer + (Name->Length / sizeof(WCHAR)) – 1;
        while ((Ptr >= Name->Buffer) && (*Ptr != L’\\’))
        {
            /* Check for Wildcard */
            if (FsRtlIsUnicodeCharacterWild(*Ptr)) return TRUE;
            Ptr–;
        }
    }

    /* Nothing Found */
    return FALSE;
}

BOOLEAN FsRtlIsNameInExpression(PUNICODE_STRING Expression,PUNICODE_STRING Name,BOOLEAN IgnoreCase,PWCHAR UpcaseTable)
{
    BOOLEAN Result;
    //NTSTATUS Status;
    UNICODE_STRING IntName;

    if (IgnoreCase && !UpcaseTable)
    {
        /*Status = RtlUpcaseUnicodeString(&IntName, Name, TRUE);
        if (Status != STATUS_SUCCESS)
        {
            ExRaiseStatus(Status);
        }
        Name = &IntName;*/
        _TCHAR  *singleChar=NULL;
       
        for( singleChar = Name->Buffer; singleChar < ((Name->Buffer) + wcslen(Name->Buffer)); singleChar++ ) {
            *singleChar= towupper(*singleChar);
        }
        IgnoreCase = FALSE;
    }
    else
    {
        IntName.Buffer = NULL;
    }

    Result = FsRtlIsNameInExpressionPrivate(Expression, Name, IgnoreCase, UpcaseTable);

    /*if (IntName.Buffer != NULL)
    {
        RtlFreeUnicodeString(&IntName);
    }*/

    return Result;
}

BOOLEAN FsRtlIsNameInExpressionPrivate(PUNICODE_STRING Pattern,PUNICODE_STRING Data,BOOLEAN IgnoreCase,PWCHAR UpcaseTable)
{
    ULONG DataIndex = 0, tmpDataIndex, PatternIndex = 0;

    assert(!FsRtlDoesNameContainWildCards(Data));

    while (DataIndex < Data->Length / sizeof(WCHAR) && PatternIndex < Pattern->Length / sizeof(WCHAR)){
   
        if ((Pattern->Buffer[PatternIndex] == (IgnoreCase ? UpcaseTable[Data->Buffer[DataIndex]] : Data->Buffer[DataIndex])) ||
            (Pattern->Buffer[PatternIndex] == L’?’) || (Pattern->Buffer[PatternIndex] == DOS_QM) ||
            (Pattern->Buffer[PatternIndex] == DOS_DOT && (Data->Buffer[DataIndex] == L’.’ || Data->Buffer[DataIndex] == L’0′)))
        {
            DataIndex++;
            PatternIndex++;
        }
        else if (Pattern->Buffer[PatternIndex] == L’*’){
            if (PatternIndex < (Pattern->Length / sizeof(WCHAR) – 1)){
                if (Pattern->Buffer[PatternIndex+1] != L’*’ && Pattern->Buffer[PatternIndex+1] != L’?’ &&
                    Pattern->Buffer[PatternIndex+1] != DOS_DOT && Pattern->Buffer[PatternIndex+1] != DOS_QM &&
                    Pattern->Buffer[PatternIndex+1] != DOS_STAR){
                        while ((IgnoreCase ? UpcaseTable[Data->Buffer[DataIndex]] : Data->Buffer[DataIndex]) != Pattern->Buffer[PatternIndex+1] && DataIndex < Data->Length / sizeof(WCHAR))
                            DataIndex++;
                }
                else{
                    if (!(Pattern->Buffer[PatternIndex+1] != DOS_DOT && (Data->Buffer[DataIndex] == L’.’ || Data->Buffer[DataIndex] == L’0′))) {
                        DataIndex++;
                    }
                }
            }
            else
            {
                DataIndex = Data->Length / sizeof(WCHAR);
            }
            PatternIndex++;
        }
        else if (Pattern->Buffer[PatternIndex] == DOS_STAR)
        {
            tmpDataIndex = DataIndex;
            while (tmpDataIndex < Data->Length / sizeof(WCHAR)){
                if (Data->Buffer[tmpDataIndex] == L’.’){
                    DataIndex = tmpDataIndex;
                }
                tmpDataIndex++;
            }
            PatternIndex++;
        }
        else{
            DataIndex = Data->Length / sizeof(WCHAR);
        }
    }

    return (PatternIndex == Pattern->Length / sizeof(WCHAR) && DataIndex == Data->Length / sizeof(WCHAR));
}

int _tmain(int argc, _TCHAR* argv[])
{
    if (argc < 3){
        std::cout << “FsRtlIsNameInExpression.exe pattern DataTocheck” << std::endl;
        return -1;
    }
    _TCHAR* pattern    = argv[1];
    _TCHAR* DatatoCheck= argv[2];
   
    std::wcout << “Pattern    : ” << pattern << std::endl;
    std::wcout << “DatatoCheck: ” << DatatoCheck << std::endl;
   
    UNICODE_STRING us_Pattern;
    UNICODE_STRING us_DatatoCheck;
   
    us_Pattern.Length= us_Pattern.MaximumLength= (wcslen(pattern)*(sizeof(WCHAR)));
    us_Pattern.Buffer= pattern;
   
    us_DatatoCheck.Length= us_DatatoCheck.MaximumLength= (wcslen(DatatoCheck)*(sizeof(WCHAR)));
    us_DatatoCheck.Buffer= DatatoCheck;
   
    if(FsRtlIsNameInExpression(&us_Pattern,&us_DatatoCheck, TRUE, NULL )){
        std::wcout << “MATCHED” << std::endl;
    } else {
        std::wcout << “NOT MATCHED” << std::endl;
    }
}

You can find another port here in this link:
http://www.hackchina.com/r/121016/name.cxx__html
http://www.hackchina.com/r/121016/name.h__html

Advertisements
This entry was posted in C/C++, Windows, Windows VC++ and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s