STDMETHODIMP CComSpySqlAudit::Init(LPCWSTR pwszDSN, LPCWSTR pwszUser, LPCWSTR pwszPw)
{
    WCHAR wszBuffer[1024];
    SQLRETURN rc;

    if (m_henv || m_hstmt || m_hdbc)
        return E_UNEXPECTED; //did you call Init() twice?
    
    rc = SQLAllocEnv( &m_henv );
    if (!SQL_SUCCEEDED(rc))
    {
        ATLTRACE(L"CComSpySqlAudit::Init() - SQLAllocEnv failed with code %d\n", rc);
        goto Error;
    }
    

    //Allocate the Connection handle 
    rc = SQLAllocConnect( m_henv, &m_hdbc );
    if (!SQL_SUCCEEDED(rc))
    {         
        ATLTRACE(L"CComSpySqlAudit::Init() - SQLAllocConnect failed with code %d\n", rc);
        goto Error;        
    }
    

    SQLSetConnectOption(m_hdbc, SQL_LOGIN_TIMEOUT, 5);
    
    rc = SQLConnect( m_hdbc, SqlStringArg(pwszDSN), SQL_NTS,
                             SqlStringArg(pwszUser), SQL_NTS,
                             SqlStringArg(pwszPw), SQL_NTS);
    if (!SQL_SUCCEEDED(rc))
    {         
        ATLTRACE(L"CComSpySqlAudit::Init() - SQLConnect failed with code %d\n", rc);
        goto Error;
    }

    
    //Allocate the statement handle 
    rc = SQLAllocStmt( m_hdbc, &m_hstmt);
    if (!SQL_SUCCEEDED(rc))
    {         
        ATLTRACE(L"CComSpySqlAudit::Init() - SQLAllocStmt failed with code %d\n", rc);
        goto Error;
    }
    //
    //    verify the table existence
    //
    {    
        for (int i=0; i < ARRAYSIZE(pwszTables); i++)
        {
            HRESULT hrString = StringCchPrintfEx(
                wszBuffer, ARRAYSIZE(wszBuffer),
                NULL, NULL, STRSAFE_NO_TRUNCATION,
                L"CREATE TABLE dbo.%s (Ct int NOT NULL )", pwszTables[i]);
            _ASSERTE(SUCCEEDED(hrString));

            rc = SQLExecDirect(m_hstmt, SqlStringArg(wszBuffer), SQL_NTS);
            if (SQL_SUCCEEDED(rc))
            {
                // this means the table is not in the db

                //Clean up the table just created and exit 
                hrString = StringCchPrintfEx(wszBuffer, ARRAYSIZE(wszBuffer),
                    NULL, NULL, STRSAFE_NO_TRUNCATION,
                    L"drop table %s", pwszTables[i]);
                _ASSERTE(SUCCEEDED(hrString));

                rc = SQLExecDirect(m_hstmt, SqlStringArg(wszBuffer), SQL_NTS);
                ATLTRACE(L"Table %s is not in the Database.\n", pwszTables[i]);
                goto Error;
            }
        }    
    }
        
    return S_OK;

Error:
    if (m_hstmt)
    {
        SQLFreeStmt( m_hstmt, SQL_DROP );    
    }

    if (m_hdbc)
    {
       rc = SQLDisconnect( m_hdbc);
       SQLFreeConnect( m_hdbc);
       if (m_henv)
         SQLFreeEnv( m_henv );
    }

    m_hdbc = m_hstmt  = m_henv = NULL;
    
    return E_FAIL;    
    
}
void CStrSafeTester::test_StringCchPrintfEx()
{
    HRESULT hr = E_FAIL;
    LPTSTR pszDestEnd = NULL;
    size_t cchRemaining = 0;    //包括结束符在内,未使用的字符数
    DWORD dwFlags;              //各种各样的参数

    /////////////////////////////                  测试缓冲区不足时的情况           /////////////////////////////////
    TCHAR bufMin[MIN_BUFFER_SIZE] = {0};

    dwFlags = 0;                            //"abcd\0"  -- 失败时和 StringCchPrintf 一样
    ResetBuf(bufMin,_countof(bufMin));
    hr = StringCchPrintfEx(bufMin,_countof(bufMin),&pszDestEnd,&cchRemaining,dwFlags,TEXT("%s"),TEST_STRING);
    CPPUNIT_ASSERT(hr == STRSAFE_E_INSUFFICIENT_BUFFER);
    CPPUNIT_ASSERT(_tcscmp(bufMin,TEXT("abcd")) == 0);
    CPPUNIT_ASSERT(bufMin[MIN_BUFFER_SIZE - 1] == 0);
    CPPUNIT_ASSERT(pszDestEnd == &bufMin[MIN_BUFFER_SIZE - 1]);
    CPPUNIT_ASSERT(cchRemaining == 1); 

    dwFlags = STRSAFE_FILL_BEHIND_NULL;     //"abcd\0"  -- 失败时和 StringCchPrintf 一样
    ResetBuf(bufMin,_countof(bufMin));
    hr = StringCchPrintfEx(bufMin,_countof(bufMin),&pszDestEnd,&cchRemaining,dwFlags,TEXT("%s"),TEST_STRING);
    CPPUNIT_ASSERT(hr == STRSAFE_E_INSUFFICIENT_BUFFER);
    CPPUNIT_ASSERT(_tcscmp(bufMin,TEXT("abcd")) == 0);
    CPPUNIT_ASSERT(bufMin[MIN_BUFFER_SIZE - 1] == 0);
    CPPUNIT_ASSERT(pszDestEnd == &bufMin[MIN_BUFFER_SIZE - 1]);
    CPPUNIT_ASSERT(cchRemaining == 1); 

    dwFlags = STRSAFE_IGNORE_NULLS;         //"abcd\0"  -- 失败时和 StringCchPrintf 一样
    ResetBuf(bufMin,_countof(bufMin));
    hr = StringCchPrintfEx(bufMin,_countof(bufMin),&pszDestEnd,&cchRemaining,dwFlags,TEXT("%s"),TEST_STRING);
    CPPUNIT_ASSERT(hr == STRSAFE_E_INSUFFICIENT_BUFFER);
    CPPUNIT_ASSERT(_tcscmp(bufMin,TEXT("abcd")) == 0);
    CPPUNIT_ASSERT(bufMin[MIN_BUFFER_SIZE - 1] == 0);
    CPPUNIT_ASSERT(pszDestEnd == &bufMin[MIN_BUFFER_SIZE - 1]);
    CPPUNIT_ASSERT(cchRemaining == 1); 

    dwFlags = STRSAFE_FILL_ON_FAILURE;      //"\0\0\0\0\0",失败时全部填充为 NULL
    ResetBuf(bufMin,_countof(bufMin));
    hr = StringCchPrintfEx(bufMin,_countof(bufMin),&pszDestEnd,&cchRemaining,dwFlags,TEXT("%s"),TEST_STRING);
    CPPUNIT_ASSERT(hr == STRSAFE_E_INSUFFICIENT_BUFFER);
    for (INT i = 0; i < _countof(bufMin); i++)
    {
        CPPUNIT_ASSERT(bufMin[i] == 0);
    }
    CPPUNIT_ASSERT(pszDestEnd == &bufMin[0]);
    CPPUNIT_ASSERT(cchRemaining == 5);

    dwFlags = STRSAFE_NULL_ON_FAILURE;      //"\0bcd\0",失败时和 StringCchPrintf 一样填充后,将首字母变为NULL
    ResetBuf(bufMin,_countof(bufMin));
    hr = StringCchPrintfEx(bufMin,_countof(bufMin),&pszDestEnd,&cchRemaining,dwFlags,TEXT("%s"),TEST_STRING);
    CPPUNIT_ASSERT(hr == STRSAFE_E_INSUFFICIENT_BUFFER);
    CPPUNIT_ASSERT(bufMin[0] == 0);
    CPPUNIT_ASSERT(_tcslen(bufMin) == 0);
    CPPUNIT_ASSERT(_tcscmp(&bufMin[1],TEXT("bcd")) == 0);
    CPPUNIT_ASSERT(pszDestEnd == &bufMin[0]);
    CPPUNIT_ASSERT(cchRemaining == 5);

    dwFlags = STRSAFE_NO_TRUNCATION;        //"\0bcd\0",失败时和 StringCchPrintf 一样填充后,将首字母变为NULL
    ResetBuf(bufMin,_countof(bufMin));
    hr = StringCchPrintfEx(bufMin,_countof(bufMin),&pszDestEnd,&cchRemaining,dwFlags,TEXT("%s"),TEST_STRING);
    CPPUNIT_ASSERT(hr == STRSAFE_E_INSUFFICIENT_BUFFER);
    CPPUNIT_ASSERT(_tcslen(bufMin) == 0);
    CPPUNIT_ASSERT(_tcscmp(&bufMin[1],TEXT("bcd")) == 0);
    CPPUNIT_ASSERT(bufMin[MIN_BUFFER_SIZE - 1] == 0);
    CPPUNIT_ASSERT(pszDestEnd == &bufMin[0]);
    CPPUNIT_ASSERT(cchRemaining == 5); 


    dwFlags = STRSAFE_FAILURE_BYTE('?');         //Unicode 时:0x3F3F 0x3F3F 0x3F3F 0x3F3F '\0',失败时前面填充为 0x3F,最后为NULL
    ResetBuf(bufMin,_countof(bufMin));
    hr = StringCchPrintfEx(bufMin,_countof(bufMin),&pszDestEnd,&cchRemaining,dwFlags,TEXT("%s"),TEST_STRING);
    CPPUNIT_ASSERT(hr == STRSAFE_E_INSUFFICIENT_BUFFER);
    CPPUNIT_ASSERT(bufMin[MIN_BUFFER_SIZE-1] == 0);

    for (INT i = 0; i < _countof(bufMin) - 1; i++)
    {
#ifdef UNICODE
        CPPUNIT_ASSERT(bufMin[i] == 0x3F3F);
#else
        CPPUNIT_ASSERT(bufMin[i] == 0x3F);
#endif
    }
    CPPUNIT_ASSERT(pszDestEnd == &bufMin[MIN_BUFFER_SIZE-1]);
    CPPUNIT_ASSERT(cchRemaining == 1);




    /////////////////////////////                  测试缓冲区足够长的情况           /////////////////////////////////
    TCHAR bufMax[MAX_BUFFER_SIZE] = {0};

    dwFlags = 0;                            //"abcde12345\0****"
    ResetBuf(bufMax,_countof(bufMax));
    hr = StringCchPrintfEx(bufMax,_countof(bufMax),&pszDestEnd,&cchRemaining,dwFlags,TEXT("%s"),TEST_STRING);
    CPPUNIT_ASSERT(hr == S_OK);
    CPPUNIT_ASSERT(_tcscmp(bufMax,TEXT("abcde12345")) == 0);
    CPPUNIT_ASSERT(_tcslen(bufMax) == TEST_STRING_LENGTH);
    CPPUNIT_ASSERT(bufMax[TEST_STRING_LENGTH] == 0);
#ifndef UNICODE
    //for (INT i = TEST_STRING_LENGTH + 1; i < MAX_BUFFER_SIZE; i++)
    //{
    //    CPPUNIT_ASSERT(bufMax[i] == TEXT('*'));
    //}
#endif
    CPPUNIT_ASSERT(pszDestEnd == &bufMax[TEST_STRING_LENGTH]);
    CPPUNIT_ASSERT(cchRemaining == MAX_BUFFER_SIZE - TEST_STRING_LENGTH); 

    dwFlags = STRSAFE_FILL_BEHIND_NULL;     //"abcde12345\0\0\0\0\0"
    ResetBuf(bufMax,_countof(bufMax));
    hr = StringCchPrintfEx(bufMax,_countof(bufMax),&pszDestEnd,&cchRemaining,dwFlags,TEXT("%s"),TEST_STRING);
    CPPUNIT_ASSERT(hr == S_OK);
    CPPUNIT_ASSERT(_tcscmp(bufMax,TEXT("abcde12345")) == 0);
    CPPUNIT_ASSERT(_tcslen(bufMax) == TEST_STRING_LENGTH);
    CPPUNIT_ASSERT(bufMax[TEST_STRING_LENGTH] == 0);
    for (INT i = TEST_STRING_LENGTH + 1; i < MAX_BUFFER_SIZE; i++)
    {
        CPPUNIT_ASSERT(bufMax[i] == 0);
    }
    CPPUNIT_ASSERT(pszDestEnd == &bufMax[TEST_STRING_LENGTH]);
    CPPUNIT_ASSERT(cchRemaining == MAX_BUFFER_SIZE - TEST_STRING_LENGTH); 


    dwFlags = STRSAFE_IGNORE_NULLS;         //"abcde12345\0****"
    ResetBuf(bufMax,_countof(bufMax));
    hr = StringCchPrintfEx(bufMax,_countof(bufMax),&pszDestEnd,&cchRemaining,dwFlags,TEXT("%s"),TEST_STRING);
    CPPUNIT_ASSERT(hr == S_OK);
    CPPUNIT_ASSERT(_tcscmp(bufMax,TEXT("abcde12345")) == 0);
    CPPUNIT_ASSERT(_tcslen(bufMax) == TEST_STRING_LENGTH);
    CPPUNIT_ASSERT(bufMax[TEST_STRING_LENGTH] == 0);
#ifndef UNICODE
    //for (INT i = TEST_STRING_LENGTH + 1; i < MAX_BUFFER_SIZE; i++)
    //{
    //    CPPUNIT_ASSERT(bufMax[i] == TEXT('*'));
    //}
#endif
    CPPUNIT_ASSERT(pszDestEnd == &bufMax[TEST_STRING_LENGTH]);
    CPPUNIT_ASSERT(cchRemaining == MAX_BUFFER_SIZE - TEST_STRING_LENGTH); 

    dwFlags = STRSAFE_FILL_ON_FAILURE;      //"abcde12345\0****"
    ResetBuf(bufMax,_countof(bufMax));
    hr = StringCchPrintfEx(bufMax,_countof(bufMax),&pszDestEnd,&cchRemaining,dwFlags,TEXT("%s"),TEST_STRING);
    CPPUNIT_ASSERT(hr == S_OK);
    CPPUNIT_ASSERT(_tcscmp(bufMax,TEXT("abcde12345")) == 0);
    CPPUNIT_ASSERT(_tcslen(bufMax) == TEST_STRING_LENGTH);
    CPPUNIT_ASSERT(bufMax[TEST_STRING_LENGTH] == 0);
#ifndef UNICODE
    //for (INT i = TEST_STRING_LENGTH + 1; i < MAX_BUFFER_SIZE; i++)
    //{
    //    CPPUNIT_ASSERT(bufMax[i] == TEXT('*'));
    //}
#endif
    CPPUNIT_ASSERT(pszDestEnd == &bufMax[TEST_STRING_LENGTH]);
    CPPUNIT_ASSERT(cchRemaining == MAX_BUFFER_SIZE - TEST_STRING_LENGTH); 

    dwFlags = STRSAFE_NULL_ON_FAILURE;      //"abcde12345\0****"
    ResetBuf(bufMax,_countof(bufMax));
    hr = StringCchPrintfEx(bufMax,_countof(bufMax),&pszDestEnd,&cchRemaining,dwFlags,TEXT("%s"),TEST_STRING);
    CPPUNIT_ASSERT(hr == S_OK);
    CPPUNIT_ASSERT(_tcscmp(bufMax,TEXT("abcde12345")) == 0);
    CPPUNIT_ASSERT(_tcslen(bufMax) == TEST_STRING_LENGTH);
    CPPUNIT_ASSERT(bufMax[TEST_STRING_LENGTH] == 0);
#ifndef UNICODE
    //for (INT i = TEST_STRING_LENGTH + 1; i < MAX_BUFFER_SIZE; i++)
    //{
    //    CPPUNIT_ASSERT(bufMax[i] == TEXT('*'));
    //}
#endif
    CPPUNIT_ASSERT(pszDestEnd == &bufMax[TEST_STRING_LENGTH]);
    CPPUNIT_ASSERT(cchRemaining == MAX_BUFFER_SIZE - TEST_STRING_LENGTH); 

    dwFlags = STRSAFE_NO_TRUNCATION;        //"abcde12345\0****"
    ResetBuf(bufMax,_countof(bufMax));
    hr = StringCchPrintfEx(bufMax,_countof(bufMax),&pszDestEnd,&cchRemaining,dwFlags,TEXT("%s"),TEST_STRING);
    CPPUNIT_ASSERT(hr == S_OK);
    CPPUNIT_ASSERT(_tcscmp(bufMax,TEXT("abcde12345")) == 0);
    CPPUNIT_ASSERT(_tcslen(bufMax) == TEST_STRING_LENGTH);
    CPPUNIT_ASSERT(bufMax[TEST_STRING_LENGTH] == 0);
#ifndef UNICODE
    //for (INT i = TEST_STRING_LENGTH + 1; i < MAX_BUFFER_SIZE; i++)
    //{
    //    CPPUNIT_ASSERT(bufMax[i] == TEXT('*'));
    //}
#endif
    CPPUNIT_ASSERT(pszDestEnd == &bufMax[TEST_STRING_LENGTH]);
    CPPUNIT_ASSERT(cchRemaining == MAX_BUFFER_SIZE - TEST_STRING_LENGTH); 


    //使用填充字符 -- '?' 对应 0x3F, 默认的填充字符为 NULL
    dwFlags = STRSAFE_FILL_BYTE('?');       //"abcde12345\0\" 0x3F3F 0x3F3F 0x3F3F 0x3F3F
    ResetBuf(bufMax,_countof(bufMax));
    hr = StringCchPrintfEx(bufMax,_countof(bufMax),&pszDestEnd,&cchRemaining,dwFlags,TEXT("%s"),TEST_STRING);
    CPPUNIT_ASSERT(hr == S_OK);
    CPPUNIT_ASSERT(_tcscmp(bufMax,TEXT("abcde12345")) == 0);
    CPPUNIT_ASSERT(_tcslen(bufMax) == TEST_STRING_LENGTH);
    CPPUNIT_ASSERT(bufMax[TEST_STRING_LENGTH] == 0);
    for (INT i = TEST_STRING_LENGTH + 1; i < MAX_BUFFER_SIZE; i++)
    {
#ifdef UNICODE
        CPPUNIT_ASSERT(bufMax[i] == 0x3F3F);
#else
        CPPUNIT_ASSERT(bufMax[i] == 0x3F);
#endif
    }
    CPPUNIT_ASSERT(pszDestEnd == &bufMax[TEST_STRING_LENGTH]);
    CPPUNIT_ASSERT(cchRemaining == MAX_BUFFER_SIZE - TEST_STRING_LENGTH); 

}