VB4SMS32.CPP

//**************************************************************************** 
//
// Copyright (c) 1995, Microsoft Corporation
//
// File: VB4SMS32.CPP
//
// Implementation file for the 32-bit Visual Basic interface DLL
// for SMSAPI.DLL (a Win32 dll)
//
// History:
//
// Gary F. Fuehrer, SEA 01 Mar 96 Created.
//
//****************************************************************************

/********************* Header Files **********************/

#define STRICT
#define WIN32_EXTRA_LEAN
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winnls.h>
#include <ole2.h>
#include <time.h>
#include <string.h>

/****************************************************************************/
#include "smsapi.h"
#include "vb4sms32.h"
typedef void* HLSTR;
typedef USHORTERR;// err

// Default selector limit for 32bit char*
#define MAX_VB_STRING SMS_DATA_BUFF_SIZE+1


/**************************** Globals ***************************************/
static HANDLE ghInst = NULL;

// An array of open connections. This is merely a convenience for the user.
// Any connections made beyond MAX_CONNECTIONS won't be disconnected by WEP.
#define MAX_CONNECTIONS 16
static HANDLE gahConnections[MAX_CONNECTIONS];

// General use buffer of length SMS_DATA_BUFF_SIZE
static char gStrBuff[SMS_DATA_BUFF_SIZE + 1];

// General use buffer of length SMS_DATA_BUFF_SIZE
static char gNameBuff[SMS_DATA_BUFF_SIZE + 1];

// General use TOKEN buffer
static TOKEN gTokenBuff;

/****************************************************************************/


/********************************************************************\
* Function: int FAR PASCAL LibMain( HINSTANCE, WORD, WORD, LPSTR ) *
* *
* Purpose: DLL entry point *
* *
* Comments: Loads the Win32 stub application *
* *
* *
\********************************************************************/

BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
int nIndex;

switch( ul_reason_for_call ) {
case DLL_PROCESS_ATTACH:
ghInst = hModule;
break;

case DLL_THREAD_ATTACH:
break;

case DLL_THREAD_DETACH:
break;

case DLL_PROCESS_DETACH:
// Disconnect any known open connections
for (nIndex = 0; nIndex < MAX_CONNECTIONS; nIndex++)
if (gahConnections[nIndex])
SmsDataSourceDisconnect(gahConnections[nIndex]);
break;
}
return TRUE;
}

/*********************** Utility Routines and Macros ************************/

BYTE gbANSI = FALSE;
#define VBStringLength(String) ((gbANSI) ? SysStringByteLen(String) \
: SysStringLen(String))

// Copy VB string to an ANSI SZ string
inline SMS_STATUS
CopyString2Sms(char *pszDest, BSTR pszSrc, UINT uLimit = MAX_VB_STRING)
{
if (uLimit <= 0) return SMS_OK;

UINT uLen = min(VBStringLength(pszSrc), uLimit-1);
if (gbANSI)
strncpy(pszDest, (char*)pszSrc, uLen);
else WideCharToMultiByte(CP_ACP, 0, pszSrc, uLen, pszDest, uLimit,
NULL, NULL);
pszDest[uLen] = '\0';

return SMS_OK;
}

// Copy ANSI SZ string to a VB string (freeing the old one)
inline SMS_STATUS
CopyString2VB(BSTR* pBStr, const char *pszSrc, UINT uLimit = MAX_VB_STRING)
{
UINT uLen = min(strlen(pszSrc), uLimit-1);

// Allocate a VB string of this length
BSTR pwsz = NULL;
if (uLen != 0)
pwsz = SysAllocStringByteLen(NULL, (gbANSI) ? uLen : uLen << 1);

if (pwsz != NULL || uLen == 0)
{
if (*pBStr != NULL) SysFreeString(*pBStr);
*pBStr = pwsz;

if (pwsz == NULL) return SMS_OK;

if (gbANSI)
strncpy((char*)pwsz, pszSrc, uLen);
else MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszSrc, uLen,
pwsz, uLen);

return SMS_OK;
}

return SMS_ERROR;
}


///////////////////////////////////////////////////////////////////////
/////////// The APIs //////////////////////////////////////////
///////////////////////////////////////////////////////////////////////


// ====================================================================
// Version number API.
// ====================================================================
/* VB:
Declare Function SmsAPIVer& Lib "vb4sms32.dll" (pVersion As String)
'*/
extern "C" SMS_STATUS WINAPI
SmsAPIVerVB(BSTR* pbstrVersion)
{
char *pszVer32;
SMS_STATUS ret;

// Call 32bit SMS API routine
ret = SmsAPIVer(&pszVer32);

if (ret == SMS_OK)
ret = CopyString2VB(pbstrVersion, pszVer32);

return ret;
}


// ====================================================================
// Connection APIs.
// ====================================================================
/* VB:
Declare Function SmsDataSourceConnect& Lib "vb4sms32.dll" (pDataSource As SQL_CONNECT_PARAMS, phConn As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsDataSourceConnectVB(SQL_CONNECT_PARAMS *pSqlCP, HANDLE *phConn)
{
int nIndex;
DATASOURCE ds;
SMS_STATUS ret = SMS_ERROR;

//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to SQL_CONNECT_PARAMS is invalid)
if (IsBadWritePtr(pSqlCP, sizeof(*pSqlCP)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// See if we can find an availiable connection slot.
for (nIndex = 0; nIndex < MAX_CONNECTIONS; nIndex++)
if (!gahConnections[nIndex]) break;

// Call 32bit SMS API routine
ds.sqlParams = *pSqlCP;
ret = SmsDataSourceConnect(&ds, phConn);

if (ret == SMS_OK && nIndex < MAX_CONNECTIONS)
gahConnections[nIndex] = *phConn;

return ret;
}

/* VB:
Declare Function SmsDataSourceDisconnect& Lib "vb4sms32.dll" (ByVal hConn As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsDataSourceDisconnectVB(HANDLE hConn)
{
int nIndex;
SMS_STATUS ret = SMS_ERROR;

// Try to find the connection in the list of known connections
for (nIndex = 0; nIndex < MAX_CONNECTIONS; nIndex++)
if (hConn == gahConnections[nIndex]) break;

// Call 32bit SMS API routine
ret = SmsDataSourceDisconnect(hConn);

if (ret == SMS_OK && nIndex < MAX_CONNECTIONS)
gahConnections[nIndex] = 0;

return ret;
}


// ====================================================================
// Engine APIs.
// ====================================================================

HRESULT
AllocVBArray(SAFEARRAY* &pArray, DWORD cArray, UINT uElemSize)
{

if (pArray != NULL)
{
// See if the array is the right kind
if (SafeArrayGetElemsize(pArray) != uElemSize) return E_INVALIDARG;

// See if the array is already large enough
if (cArray <= pArray->rgsabound[0].cElements) return SMS_OK;

SAFEARRAYBOUND sab = pArray->rgsabound[0];
sab.cElements = cArray;
return SafeArrayRedim(pArray, &sab);
}
else
{
// Allocate an array descriptor for an array of user defined types
HRESULT ret = SafeArrayAllocDescriptor(1, &pArray);
if (ret != S_OK) return ret;

// Set the element size and array bounds
pArray->cbElements = uElemSize;
pArray->rgsabound[0].lLbound = 0;
pArray->rgsabound[0].cElements = cArray;
return SafeArrayAllocData(pArray);
}
}

SMS_STATUS
CopyFolderInfo2VB(FOLDER_INFO *pFolderInfoVB, FOLDER_INFO *pFolderInfo)
{
SMS_STATUS ret;

// Preserve the BSTR and SAFEARRAY members in the FOLDER_INFO from VB
char* pszTagVB = pFolderInfoVB->pszTag;
DWORD* pFolderTagsVB = pFolderInfoVB->pFolderTags;
DWORD* pFilterTagsVB = pFolderInfoVB->pFilterTags;
SCALAR_INFOVB* pScalarsVB = (SCALAR_INFOVB*)pFolderInfoVB->pScalars;

// Copy the folder info structure into the VB array
*pFolderInfoVB = *pFolderInfo;

// Restore members of FOLDER_INFO before possible exit
pFolderInfoVB->pszTag = pszTagVB;
pFolderInfoVB->pFolderTags = pFolderTagsVB;
pFolderInfoVB->pFilterTags = pFilterTagsVB;
pFolderInfoVB->pScalars = (SCALAR_INFO*)pScalarsVB;

// Copy the pszTag member
ret = CopyString2VB((BSTR*)&pFolderInfoVB->pszTag, pFolderInfo->pszTag);
if (ret != SMS_OK) return ret;

// Copy the pFolderTags array
if (pFolderInfo->ctFolders > 0)
{
// Create or Redim as necessary
if (AllocVBArray((SAFEARRAY*&)pFolderInfoVB->pFolderTags,
pFolderInfo->ctFolders,
sizeof(*pFolderTagsVB)) != S_OK)
return SMS_ERROR;

// Lock down the array and obtain pointer to the data
if (SafeArrayAccessData((SAFEARRAY*)pFolderInfoVB->pFolderTags,
(void**)&pFolderTagsVB) != S_OK)
return SMS_ERROR;

// Copy the array and unlock it
memcpy(pFolderTagsVB, pFolderInfo->pFolderTags,
pFolderInfo->ctFolders * sizeof(*pFolderTagsVB));
SafeArrayUnaccessData((SAFEARRAY*)pFolderInfoVB->pFolderTags);
}

// Copy the pFilterTags array
if (pFolderInfo->ctFilters > 0)
{
// Create or Redim as necessary
if (AllocVBArray((SAFEARRAY*&)pFolderInfoVB->pFilterTags,
pFolderInfo->ctFilters,
sizeof(*pFilterTagsVB)) != S_OK)
return SMS_ERROR;

// Lock down the array and obtain pointer to the data
if (SafeArrayAccessData((SAFEARRAY*)pFolderInfoVB->pFilterTags,
(void**)&pFilterTagsVB) != S_OK)
return SMS_ERROR;

// Copy the array and unlock it
memcpy(pFilterTagsVB, pFolderInfo->pFilterTags,
pFolderInfo->ctFilters * sizeof(*pFilterTagsVB));
SafeArrayUnaccessData((SAFEARRAY*)pFolderInfoVB->pFilterTags);
}

// Copy the pScalars array
if (pFolderInfo->ctScalars > 0)
{
// Create or Redim as necessary
if (AllocVBArray((SAFEARRAY*&)pFolderInfoVB->pScalars,
pFolderInfo->ctScalars,
sizeof(*pScalarsVB)) != S_OK) return SMS_ERROR;

// Lock down the array and obtain pointer to the data
if (SafeArrayAccessData((SAFEARRAY*)pFolderInfoVB->pScalars,
(void**)&pScalarsVB) != S_OK) return SMS_ERROR;

// Copy the array and unlock it
DWORD dwIndex = pFolderInfo->ctScalars;
SCALAR_INFO* pScalars = pFolderInfo->pScalars;
while (dwIndex-- > 0)
{
pScalarsVB->scType = pScalars->scType;
pScalars->fAccess = pScalars->fAccess;
ret = CopyString2VB(&pScalarsVB->szName, pScalars->szName);
if (ret != SMS_OK) break;

// Advance to next scalar
pScalarsVB++;
pScalars++;
}
SafeArrayUnaccessData((SAFEARRAY*)pFolderInfoVB->pScalars);
}

return ret;
}

/* VB:
Declare Function SmsDescribeFolder& Lib "vb4sms32.dll" (tObjectity As BASETYPE, ByVal dwTag As Long, pFolderInfo As FOLDER_INFO)
'*/
extern "C" SMS_STATUS WINAPI
SmsDescribeFolderVB(BASETYPE* tObjectity, DWORD dwTag,
LPSAFEARRAY* ppArray)
{
SAFEARRAY* &pArray = *ppArray;
SMS_STATUS ret;

// Create or Redim as necessary
FOLDER_INFO* pFoldersVB;
if (AllocVBArray(pArray, 1, sizeof(*pFoldersVB)) != S_OK)
return SMS_INVALID_PARAMETER;

// Lock down the array and obtain pointer to the data
if (SafeArrayAccessData(pArray, (void**)&pFoldersVB) != S_OK)
return SMS_INVALID_PARAMETER;

// Call 32bit SMS API routine
FOLDER_INFO *pFolderInfo;
ret = SmsDescribeFolder(*tObjectity, dwTag, &pFolderInfo);
if (ret == SMS_OK)
// Copy the FOLDER_INFO struct from 32bit land
ret = CopyFolderInfo2VB(pFoldersVB, pFolderInfo);

// Unlock the VB array
SafeArrayUnaccessData(pArray);
return ret;
}


typedef SMS_STATUS (*ENUM_FN)(FOLDER_INFO**, DWORD*);

SMS_STATUS
SmsEnumFoldersContainers(LPSAFEARRAY* ppArray, DWORD *pCount, ENUM_FN SmsEnum)
{
SAFEARRAY* &pArray = *ppArray;
FOLDER_INFO* pFoldersVB;
SMS_STATUS ret;

//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (pCount is invalid)
if (IsBadWritePtr(pCount, sizeof(*pCount)))
return SMS_INVALID_PARAMETER;

// if (Count is too big)
if (*pCount >= 0x80000000 / sizeof(*pFoldersVB))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Get the count of FOLDER_INFOs
*pCount = 0;
ret = SmsEnum(NULL, pCount);
if (ret != SMS_MORE_DATA) return ret;

// Create or Redim as necessary
if (AllocVBArray(pArray, *pCount, sizeof(*pFoldersVB)) != S_OK)
return SMS_INVALID_PARAMETER;

// Lock down the array and obtain pointer to the data
if (SafeArrayAccessData(pArray, (void**)&pFoldersVB) != S_OK)
return SMS_INVALID_PARAMETER;

// Get an array large enough to accept FOLDER_INFO pointers
DWORD cFolders = *pCount;
FOLDER_INFO** ppFolders = new FOLDER_INFO*[cFolders];
if (ppFolders != NULL)
{
// Call 32bit SMS API routine
ret = SmsEnum(ppFolders, pCount);

if (ret == SMS_OK)
for (DWORD dwIndex = 0; dwIndex < cFolders; dwIndex++)
{
ret = CopyFolderInfo2VB(&pFoldersVB[dwIndex],
ppFolders[dwIndex]);
if (ret != SMS_OK) break;
}

// Free the array of FOLDER_INFO pointers
delete[] ppFolders;
ppFolders = NULL;
}
else ret = SMS_ERROR;

// Unlock the VB array of FOLDER_INFOs
SafeArrayUnaccessData(pArray);
return ret;
}

/* VB:
Declare Function SmsEnumContainers& Lib "vb4sms32.dll" (Containers() As FOLDER_INFO, pCount As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsEnumContainersVB(LPSAFEARRAY* ppArray, DWORD *pCount)
{
return SmsEnumFoldersContainers(ppArray, pCount, SmsEnumContainers);
}

/* VB:
Declare Function SmsEnumFolders& Lib "vb4sms32.dll" (Folders() As FOLDER_INFO, pCount As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsEnumFoldersVB(LPSAFEARRAY* ppArray, DWORD *pCount)
{
return SmsEnumFoldersContainers(ppArray, pCount, SmsEnumFolders);
}

SMS_STATUS
CopyFilterInfo2VB(FILTER_INFOVB *pFilterInfoVB, FILTER_INFO *pFilterInfo)
{
SMS_STATUS ret = SMS_OK;

// szTag
if (ret == SMS_OK)
ret = CopyString2VB(&pFilterInfoVB->szTag,
pFilterInfo->szTag,
sizeof(pFilterInfo->szTag));

// filterType
pFilterInfoVB->filterType = pFilterInfo->filterType;

// szName
if (ret == SMS_OK)
ret = CopyString2VB(&pFilterInfoVB->szName,
pFilterInfo->szName,
sizeof(pFilterInfo->szName));

// szValue
if (ret == SMS_OK)
ret = CopyString2VB(&pFilterInfoVB->szValue,
pFilterInfo->szValue,
sizeof(pFilterInfo->szValue));

// szOperator
if (ret == SMS_OK)
ret = CopyString2VB(&pFilterInfoVB->szOperator,
pFilterInfo->szOperator,
sizeof(pFilterInfo->szOperator));

// szArchitecture
if (ret == SMS_OK)
ret = CopyString2VB(&pFilterInfoVB->szArchitecture,
pFilterInfo->szArchitecture,
sizeof(pFilterInfo->szArchitecture));

// szGroupClass
if (ret == SMS_OK)
ret = CopyString2VB(&pFilterInfoVB->szGroupClass,
pFilterInfo->szGroupClass,
sizeof(pFilterInfo->szGroupClass));

// szAttributeName
if (ret == SMS_OK)
ret = CopyString2VB(&pFilterInfoVB->szAttributeName,
pFilterInfo->szAttributeName,
sizeof(pFilterInfo->szAttributeName));

return ret;
}

/* VB:
Declare Function SmsEnumFilters& Lib "vb4sms32.dll" (Filters() As FILTER_INFO, pCount As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsEnumFiltersVB(LPSAFEARRAY* ppArray, DWORD *pCount)
{
SAFEARRAY* &pArray = *ppArray;
FILTER_INFOVB* pFiltersVB;
SMS_STATUS ret;

//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (pCount is invalid)
if (IsBadWritePtr(pCount, sizeof(*pCount)))
return SMS_INVALID_PARAMETER;

// if (Count is too big)
if (*pCount >= 0x80000000 / sizeof(*pFiltersVB))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Get the count of FILTER_INFOs
*pCount = 0;
ret = SmsEnumFilters(NULL, pCount);
if (ret != SMS_MORE_DATA) return ret;

// Create or Redim as necessary
if (AllocVBArray(pArray, *pCount, sizeof(*pFiltersVB)) != S_OK)
return SMS_INVALID_PARAMETER;

// Lock down the array and obtain pointer to the data
if (SafeArrayAccessData(pArray, (void**)&pFiltersVB) != S_OK)
return SMS_INVALID_PARAMETER;

// Get an array large enough to accept FILTER_INFO pointers
DWORD cFilters = *pCount;
FILTER_INFO* pFilters = new FILTER_INFO[cFilters];
if (pFilters != NULL)
{
// Call 32bit SMS API routine
ret = SmsEnumFilters(pFilters, pCount);

if (ret == SMS_OK)
for (DWORD dwIndex = 0; dwIndex < cFilters; dwIndex++)
{
ret = CopyFilterInfo2VB(&pFiltersVB[dwIndex],
&pFilters[dwIndex]);
if (ret != SMS_OK) break;
}

// Unlock the array of FILTER_INFO pointers
delete[] pFilters;
pFilters = NULL;
}
else ret = SMS_ERROR;

// Unlock the VB array of FILTER_INFOs
SafeArrayUnaccessData(pArray);
return ret;
}


// ====================================================================
// Container APIS.
// ====================================================================
/* VB:
Declare Function SmsOpenContainer& Lib "vb4sms32.dll" (ByVal cType As Long, ByVal hConnection As Long, phContainer As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsOpenContainerVB(DWORD cType, HANDLE hConnection, HANDLE *phContainer)
{
//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to Container Handle from VB is invalid)
if (IsBadWritePtr((void*)phContainer, sizeof(*phContainer)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Call 32bit SMS API routine
return SmsOpenContainer(cType, hConnection, phContainer);
}

/* VB:
Declare Function SmsSetFilter& Lib "vb4sms32.dll" (ByVal hContainer As Long, ByVal hFilter As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsSetFilterVB(HANDLE hContainer, HANDLE hFilter)
{
// Call 32bit SMS API routine
return SmsSetFilter(hContainer, hFilter);
}

/* VB:
Declare Function SmsPopulate& Lib "vb4sms32.dll" (ByVal hContainer As Long, ByVal dwOptions As Long, pNotify As Any)
'*/
extern "C" SMS_STATUS WINAPI
SmsPopulateVB(HANDLE hContainer, DWORD dwOptions, NOTIFY* pNotify)
{
//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to Folder Handle from VB is invalid)
if (dwOptions != POP_SYNC
&& IsBadWritePtr((void*)pNotify, sizeof(*pNotify)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Call 32bit SMS API routine
return SmsPopulate(hContainer, dwOptions, pNotify);
}

/* VB:
Declare Function SmsGetNextFolder& Lib "vb4sms32.dll" (ByVal hParent As Long, ByVal fType As Long, phFolder As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsGetNextFolderVB(HANDLE hParent, DWORD fType, HANDLE *phFolder)
{
//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to Folder Handle from VB is invalid)
if (IsBadWritePtr((void*)phFolder, sizeof(*phFolder)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Call 32bit SMS API routine
return SmsGetNextFolder(hParent, fType, phFolder);
}

/* VB:
Declare Function SmsCloseContainer& Lib "vb4sms32.dll" (ByVal hContainer As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsCloseContainerVB(HANDLE hContainer)
{
// Call 32bit SMS API routine
return SmsCloseContainer(hContainer);
}


// ====================================================================
// Folder (collection) APIs.
// A collection contains other things, that is it can have embedded
// collections and it can also have properties (scalars).
// ====================================================================
/* VB:
Declare Function SmsCreateFolder& Lib "vb4sms32.dll" (ByVal hParent As Long, ByVal fType As Long, ByVal pszFolderID As String, phFolder As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsCreateFolderVB(HANDLE hParent, DWORD fType, const char *pszFolderID,
HANDLE *phFolder)
{
//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to string from VB is invalid)
if (IsBadStringPtr(pszFolderID, MAX_VB_STRING))
return SMS_INVALID_PARAMETER;

// if (Pointer to Folder Handle from VB is invalid)
if (IsBadWritePtr((void*)phFolder, sizeof(*phFolder)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Call 32bit SMS API routine
return SmsCreateFolder(hParent, fType, pszFolderID, phFolder);
}

/* VB:
Declare Function SmsGetFolderID& Lib "vb4sms32.dll" (ByVal hFolder As Long, pszFolderID As String)
'*/
extern "C" SMS_STATUS WINAPI
SmsGetFolderIDVB(HANDLE hFolder, BSTR* pszFolderID)
{
SMS_STATUS ret;

// Call 32bit SMS API routine
ret = SmsGetFolderID(hFolder, gStrBuff);
if (ret == SMS_OK)
// Copy the string to VB land
ret = CopyString2VB(pszFolderID, gStrBuff, sizeof(gStrBuff));

return ret;
}
/* VB:
Declare Function SmsGetFolderType& Lib "vb4sms32.dll" (ByVal hFolder As Long, pfType As Long, pszfType As String)
'*/
extern "C" SMS_STATUS WINAPI
SmsGetFolderTypeVB(HANDLE hFolder, DWORD *pfType, BSTR* pszfType)
{
SMS_STATUS ret;

//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to Type from VB is invalid)
if (IsBadWritePtr(pfType, sizeof(*pfType)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Call 32bit SMS API routine
ret = SmsGetFolderType(hFolder, pfType, gStrBuff);
if (ret == SMS_OK)
// Copy the string to VB land
ret = CopyString2VB(pszfType, gStrBuff, sizeof(gStrBuff));

return ret;
}

/* VB:
Declare Function SmsEnumFolderTypes& Lib "vb4sms32.dll" (ByVal hFolder As Long, pfTypes As Long, pCount As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsEnumFolderTypesVB(HANDLE hFolder, LPSAFEARRAY* ppArray, DWORD *pCount)
{
SAFEARRAY* &pArray = *ppArray;
DWORD* pfTypes;
SMS_STATUS ret;

//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to Folder Type Count from VB is invalid)
if (IsBadWritePtr(pCount, sizeof(*pCount)))
return SMS_INVALID_PARAMETER;

// if (Count is too big)
if (*pCount >= 0x80000000 / sizeof(*pfTypes))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Get the count of folder types
*pCount = 0;
ret = SmsEnumFolderTypes(hFolder, NULL, pCount);
if (ret != SMS_MORE_DATA) return ret;

// Create or Redim as necessary
if (AllocVBArray(pArray, *pCount, sizeof(*pfTypes)) != S_OK)
return SMS_INVALID_PARAMETER;

// Lock down the array and obtain pointer to the data
if (SafeArrayAccessData(pArray, (void**)&pfTypes) != S_OK)
return SMS_INVALID_PARAMETER;

// Call 32bit SMS API routine
ret = SmsEnumFolderTypes(hFolder, pfTypes, pCount);

// Unlock the array
SafeArrayUnaccessData(pArray);

return ret;
}

/* VB:
Declare Function SmsGetFolderCount& Lib "vb4sms32.dll" (ByVal hFolder As Long, ByVal fType As Long, pCount As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsGetFolderCountVB(HANDLE hFolder, DWORD fType, DWORD *pCount)
{
//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to Folder Type Count from VB is invalid)
if (IsBadWritePtr(pCount, sizeof(*pCount)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Call 32bit SMS API routine
return SmsGetFolderCount(hFolder, fType, pCount);
}

/* VB:
Declare Function SmsGetFolderByID& Lib "vb4sms32.dll" (ByVal hFolder As Long, ByVal fType As Long, ByVal pszFolderID As String, phSubFolder As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsGetFolderByIDVB(HANDLE hFolder, DWORD fType, const char *pszFolderID,
HANDLE *phSubFolder)
{
//////////////////////////////////////////////////////////////////////////
// Check parameters


// if (Pointer to string from VB is invalid)
if (IsBadStringPtr(pszFolderID, MAX_VB_STRING))
return SMS_INVALID_PARAMETER;

// if (Pointer to SubFolder Handle from VB is invalid)
if (IsBadWritePtr((void*)phSubFolder, sizeof(*phSubFolder)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Call 32bit SMS API routine
char *pTemp = const_cast<char*>(pszFolderID); // FIX: SMSAPI incorrectly declared 3rd parameter
return SmsGetFolderByID(hFolder, fType, pTemp, phSubFolder);
}

/* VB:
Declare Function SmsRewind& Lib "vb4sms32.dll" (ByVal hFolder As Long, ByVal dwOptions As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsRewindVB(HANDLE hFolder, DWORD dwOptions)
{
// Call 32bit SMS API routine
return SmsRewind(hFolder, dwOptions);
}

/* VB:
Declare Function SmsCloseFolder& Lib "vb4sms32.dll" (ByVal hFolder As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsCloseFolderVB(HANDLE hFolder)
{
// Call 32bit SMS API routine
return SmsCloseFolder(hFolder);
}

/* VB:
Declare Function SmsLinkFolder& Lib "vb4sms32.dll" (ByVal hFolder As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsLinkFolderVB(HANDLE hFolder)
{
// Call 32bit SMS API routine
return SmsLinkFolder(hFolder);
}

/* VB:
Declare Function SmsUnlinkFolder& Lib "vb4sms32.dll" (ByVal hFolder As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsUnlinkFolderVB(HANDLE hFolder)
{
// Call 32bit SMS API routine
return SmsUnlinkFolder(hFolder);
}

/* VB:
Declare Function SmsCommitFolder& Lib "vb4sms32.dll" (ByVal hFolder As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsCommitFolderVB(HANDLE hFolder)
{
// Call 32bit SMS API routine
return SmsCommitFolder(hFolder);
}

/* VB:
Declare Function SmsDupFolder& Lib "vb4sms32.dll" (ByVal hParent As Long, ByVal hFolder As Long, phNewFolder As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsDupFolderVB(HANDLE hParent, HANDLE hFolder, HANDLE* phNewFolder)
{
// Call 32bit SMS API routine
return SmsDupFolder(hParent, hFolder, phNewFolder);
}

/* VB:
Declare Function SmsGetScalarCount& Lib "vb4sms32.dll" (ByVal hFolder As Long, pCount As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsGetScalarCountVB(HANDLE hFolder, DWORD *pCount)
{
//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to Folder Count from VB is invalid)
if (IsBadWritePtr(pCount, sizeof(*pCount)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Call 32bit SMS API routine
return SmsGetScalarCount(hFolder, pCount);
}

/* VB:
Declare Function SmsGetNextScalar& Lib "vb4sms32.dll" (ByVal hFolder As Long, pScalarStruct As SCALAR)
'*/
extern "C" SMS_STATUS WINAPI
SmsGetNextScalarVB(HANDLE hFolder, LPSAFEARRAY* ppArray)
{
SMS_STATUS ret;
char *pszName;
BSTR pszValue;
SAFEARRAY* pValue;
SAFEARRAY* &pArray = *ppArray;

// Create or Redim as necessary
SCALAR *pScalar;
if (AllocVBArray(pArray, 1, sizeof(*pScalar)) != S_OK)
return SMS_INVALID_PARAMETER;

// Lock down the array and obtain pointer to the data
if (SafeArrayAccessData(pArray, (void**)&pScalar) != S_OK)
return SMS_INVALID_PARAMETER;

// Preserve the BSTR members, pszName & pszValue, in the SCALAR from VB
pszName = pScalar->pszName;
pszValue = (BSTR)pScalar->pszValue;
pValue = (SAFEARRAY*)pScalar->pValue;

// Provide SCALAR with buffers to receive data
pScalar->pszName = gNameBuff;
pScalar->pszValue = NULL;
pScalar->pValue = NULL;
pScalar->dwLen = 0;

// Call 32bit SMS API routine to get buffer lengths
ret = SmsGetNextScalar(hFolder, pScalar);

// Check for BINARY scalar and wrong return code
if (ret == SMS_OK && pScalar->scType == SCALAR_BINARY &&
pScalar->dwLen > 0)
ret = SMS_MORE_DATA;

if (ret == SMS_MORE_DATA)
{
// Provide SCALAR with buffers to receive data
if (pScalar->scType == SCALAR_STRING)
{
pScalar->pszValue = new char[pScalar->dwLen];
if (pScalar->pszValue == NULL) ret = SMS_ERROR;
}
else if (pScalar->scType == SCALAR_BINARY)
{
// Create or Redim as necessary
if (AllocVBArray(pValue, pScalar->dwLen, 1) != S_OK)
ret = SMS_INVALID_PARAMETER;

// Lock down the array and obtain pointer to the data
else if (SafeArrayAccessData(pValue, &pScalar->pValue) != S_OK)
ret = SMS_INVALID_PARAMETER;
}
else ret = SMS_ERROR;

if (ret == SMS_MORE_DATA)
{
// Call 32bit SMS API routine to get data
ret = SmsGetScalarByName(hFolder, pScalar->pszName, pScalar);

// Copy string buffer to pszValue
if (ret == SMS_OK && pScalar->pszValue != NULL)
{
ret = CopyString2VB(&pszValue, pScalar->pszValue);

// Free the string buffer
delete[] pScalar->pszValue;
}

// Unlock the VB Byte array
if (pScalar->pValue != NULL)
SafeArrayUnaccessData(pValue);
}
}

// Restore pszName & pszValue members of SCALAR before possible exit
pScalar->pszName = pszName;
pScalar->pszValue = (char*)pszValue;
pScalar->pValue = pValue;

// Copy the name from buffer to VB BSTR
if (ret == SMS_OK)
ret = CopyString2VB((BSTR*)&pScalar->pszName, gNameBuff);

// Unlock the VB array
SafeArrayUnaccessData(pArray);

return ret;
}

/* VB:
Declare Function SmsGetScalarByName& Lib "vb4sms32.dll" (ByVal hFolder As Long, ByVal pszName As String, pScalarStruct As SCALAR)
'*/
extern "C" SMS_STATUS WINAPI
SmsGetScalarByNameVB(HANDLE hFolder, const char *pszNameVB,
LPSAFEARRAY* ppArray)
{
SMS_STATUS ret;
char *pszName;
BSTR pszValue;
SAFEARRAY* pValue;
SAFEARRAY* &pArray = *ppArray;

//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to string from VB is invalid)
if (IsBadStringPtr(pszNameVB, MAX_VB_STRING))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Create or Redim as necessary
SCALAR *pScalar;
if (AllocVBArray(pArray, 1, sizeof(*pScalar)) != S_OK)
return SMS_INVALID_PARAMETER;

// Lock down the array and obtain pointer to the data
if (SafeArrayAccessData(pArray, (void**)&pScalar) != S_OK)
return SMS_INVALID_PARAMETER;

// Preserve the BSTR members, pszName & pszValue, in the SCALAR from VB
pszName = pScalar->pszName;
pszValue = (BSTR)pScalar->pszValue;
pValue = (SAFEARRAY*)pScalar->pValue;

// Provide SCALAR with buffers to receive data
pScalar->pszName = gNameBuff;
pScalar->pszValue = NULL;
pScalar->pValue = NULL;
pScalar->dwLen = 0;

// Call 32bit SMS API routine to get buffer lengths
ret = SmsGetScalarByName(hFolder, pszNameVB, pScalar);

// Check for BINARY scalar and wrong return code
if (ret == SMS_OK && pScalar->scType == SCALAR_BINARY &&
pScalar->dwLen > 0)
ret = SMS_MORE_DATA;

if (ret == SMS_MORE_DATA ||
(pScalar->scType == SCALAR_BINARY) && pScalar->dwLen > 0)
{
// Provide SCALAR with buffers to receive data
if (pScalar->scType == SCALAR_STRING)
{
pScalar->pszValue = new char[pScalar->dwLen];
if (pScalar->pszValue == NULL) ret = SMS_ERROR;
}
else if (pScalar->scType == SCALAR_BINARY)
{
// Create or Redim as necessary
if (AllocVBArray(pValue, pScalar->dwLen, 1) != S_OK)
ret = SMS_INVALID_PARAMETER;

// Lock down the array and obtain pointer to the data
else if (SafeArrayAccessData(pValue, &pScalar->pValue) != S_OK)
ret = SMS_INVALID_PARAMETER;
}
else ret = SMS_ERROR;

if (ret == SMS_MORE_DATA)
{
// Call 32bit SMS API routine to get data
ret = SmsGetScalarByName(hFolder, pszNameVB, pScalar);

// Copy string buffer to pszValue
if (ret == SMS_OK && pScalar->pszValue != NULL)
{
ret = CopyString2VB(&pszValue, pScalar->pszValue);

// Free the string buffer
delete[] pScalar->pszValue;
}

// Unlock the VB Byte array
if (pScalar->pValue != NULL)
SafeArrayUnaccessData(pValue);
}
}

// Restore pszTag & pszValue members of SCALAR before possible exit
pScalar->pszName = pszName;
pScalar->pszValue = (char*)pszValue;
pScalar->pValue = pValue;

// Copy the name from buffer to VB BSTR
if (ret == SMS_OK)
ret = CopyString2VB((BSTR*)&pScalar->pszName, gNameBuff);

// Unlock the VB array
SafeArrayUnaccessData(pArray);

return ret;
}

/* VB:
Declare Function SmsSetScalar& Lib "vb4sms32.dll" (ByVal hFolder As Long, pScalarStruct As SCALAR)
'*/
extern "C" SMS_STATUS WINAPI
SmsSetScalarVB(HANDLE hFolder, LPSAFEARRAY* ppArray)
{
BSTR pszName, pszValue;
SAFEARRAY* pValue;
SAFEARRAY* &pArray = *ppArray;
char NullCharBuff = '\0', *pCharBuff = &NullCharBuff;
BYTE NullByteBuff = NULL, *pByteBuff = &NullByteBuff;

// Lock down the array and obtain pointer to the data
SCALAR *pScalar;
if (SafeArrayAccessData(pArray, (void**)&pScalar) != S_OK)
return SMS_INVALID_PARAMETER;

if (pScalar->scType == SCALAR_STRING && pScalar->pszValue == NULL &&
pScalar->dwLen > 0) return SMS_INVALID_PARAMETER;

if (pScalar->scType == SCALAR_BINARY && pScalar->pValue == NULL)
if (pScalar->dwLen > 0) return SMS_INVALID_PARAMETER;

// Preserve the BSTR members, pszName & pszValue, in the SCALAR from VB
pszName = (BSTR)pScalar->pszName;
pszValue = (BSTR)pScalar->pszValue;
pValue = (SAFEARRAY*)pScalar->pValue;

// Get a value string buffer
if (pScalar->scType == SCALAR_STRING && pszValue != NULL &&
(pCharBuff = new char[VBStringLength(pszValue) + 1]) == NULL)
return SMS_ERROR;

// Lock down the array and obtain pointer to the byte data
if (pScalar->scType == SCALAR_BINARY && pValue != NULL &&
SafeArrayAccessData(pValue, (void**)&pByteBuff) != S_OK)
return SMS_ERROR;

// Copy the strings from VB to SMS
CopyString2Sms(gNameBuff, pszName);
if (pCharBuff != NULL) CopyString2Sms(pCharBuff, pszValue);

// Set SCALAR value to buffers with data
pScalar->pszName = gNameBuff;
pScalar->pszValue = pCharBuff;
pScalar->pValue = pByteBuff;

// Call 32bit SMS API routine
SMS_STATUS ret = SmsSetScalar(hFolder, pScalar);

// Restore pszTag, pszValue, & pValue members of SCALAR before exit
pScalar->pszName = (char*)pszName;
pScalar->pszValue = (char*)pszValue;
pScalar->pValue = pValue;

// Unlock the array and delete the string value buffer
if (pByteBuff != &NullByteBuff) SafeArrayUnaccessData(pValue);
if (pCharBuff != &NullCharBuff) delete[] pCharBuff;

// Unlock the VB array
SafeArrayUnaccessData(pArray);

return ret;
}


// ====================================================================
// FilterContainer APIs
// ====================================================================
/* VB:
Declare Function SmsOpenFilterContainer& Lib "vb4sms32.dll" (ByVal hConnection As Long, phFContainer As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsOpenFilterContainerVB(HANDLE hConnection, HANDLE *phFContainer)
{
//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to Container Handle from VB is invalid)
if (IsBadWritePtr((void*)phFContainer, sizeof(*phFContainer)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Call 32bit SMS API routine
return SmsOpenFilterContainer(hConnection, phFContainer);
}

/* VB:
Declare Function SmsCloseFilterContainer& Lib "vb4sms32.dll" (ByVal hFContainer As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsCloseFilterContainerVB(HANDLE hFContainer)
{
// Call 32bit SMS API routine
return SmsCloseFilterContainer(hFContainer);
}

/* VB:
Declare Function SmsGetNextFilter& Lib "vb4sms32.dll" (ByVal hFContainer As Long, ByVal frType As Long, phFilter As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsGetNextFilterVB(HANDLE hFContainer, DWORD frType, HANDLE *phFilter)
{
//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to Filter Handle from VB is invalid)
if (IsBadWritePtr((void*)phFilter, sizeof(*phFilter)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Call 32bit SMS API routine
return SmsGetNextFilter(hFContainer, frType, phFilter);
}

/* VB:
Declare Function SmsGetFilterByID& Lib "vb4sms32.dll" (ByVal hFContainer As Long, ByVal frType As Long, ByVal pszFilterID As String, phFilter As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsGetFilterByIDVB(HANDLE hFContainer, DWORD frType, const char *pszFilterID,
HANDLE *phFilter)
{
//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to string from VB is invalid)
if (IsBadStringPtr(pszFilterID, MAX_VB_STRING))
return SMS_INVALID_PARAMETER;

// if (Pointer to Filter Handle from VB is invalid)
if (IsBadWritePtr((void*)phFilter, sizeof(*phFilter)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Call 32bit SMS API routine
return SmsGetFilterByID(hFContainer, frType, pszFilterID, phFilter);
}

/* VB:
Declare Function SmsGetFilterID& Lib "vb4sms32.dll" (ByVal hFilter As Long, pszFilterID As String)
'*/
extern "C" SMS_STATUS WINAPI
SmsGetFilterIDVB(HANDLE hFilter, BSTR* pszFilterID)
{
SMS_STATUS ret;

// Call 32bit SMS API routine
ret = SmsGetFilterID(hFilter, gStrBuff);
if (ret == SMS_OK)
ret = CopyString2VB(pszFilterID, gStrBuff, sizeof(gStrBuff));

return ret;
}

/* VB:
Declare Function SmsCommitFilter& Lib "vb4sms32.dll" (ByVal hFilter As Long, ByVal hFContainer As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsCommitFilterVB(HANDLE hFilter, HANDLE hFContainer)
{
// Call 32bit SMS API routine
return SmsCommitFilter(hFilter, hFContainer);
}


// ====================================================================
// Filter APIs
// ====================================================================
/* VB:
Declare Function SmsCreateFilter& Lib "vb4sms32.dll" (ByVal frType As Long, ByVal hConnection As Long, phFilter As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsCreateFilterVB(DWORD frType, HANDLE hConnection, HANDLE *phFilter)
{
//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to Filter Handle from VB is invalid)
if (IsBadWritePtr((void*)phFilter, sizeof(*phFilter)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Call 32bit SMS API routine
return SmsCreateFilter(frType, hConnection, phFilter);
}

/* VB:
Declare Function SmsCloseFilter& Lib "vb4sms32.dll" (ByVal hFilter As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsCloseFilterVB(HANDLE hFilter)
{
// Call 32bit SMS API routine
return SmsCloseFilter(hFilter);
}

/* VB:
Declare Function SmsGetFilterType& Lib "vb4sms32.dll" (ByVal hFilter As Long, pfilterType As Long, pszTag As String)
'*/
extern "C" SMS_STATUS WINAPI
SmsGetFilterTypeVB(HANDLE hFilter, DWORD *pfilterType, BSTR* pszTag)
{
SMS_STATUS ret;

//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to Filter Handle from VB is invalid)
if (IsBadWritePtr(pfilterType, sizeof(*pfilterType)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Call 32bit SMS API routine
ret = SmsGetFilterType(hFilter, pfilterType, gStrBuff);
if (ret == SMS_OK)
ret = CopyString2VB(pszTag, gStrBuff, sizeof(gStrBuff));

return ret;
}

/* VB:
Declare Function SmsGetToken& Lib "vb4sms32.dll" (ByVal hFilter As Long, ByVal iIndex As Long, pTokenInfo As TOKEN)
'*/
extern "C" SMS_STATUS WINAPI
SmsGetTokenVB(HANDLE hFilter, INT iIndex, TOKENVB *pTokenInfoVB)
{
SMS_STATUS ret;

//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to FOLDER_INFO struct from VB is invalid)
if (IsBadWritePtr(pTokenInfoVB, sizeof(*pTokenInfoVB)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Turn on ANSI string copy
gbANSI = TRUE;

// Call 32bit SMS API routine
ret = SmsGetToken(hFilter, iIndex, &gTokenBuff);

// tokenType
pTokenInfoVB->tokenType = gTokenBuff.tokenType;

// szName
if (ret == SMS_OK)
ret = CopyString2VB(&pTokenInfoVB->szName,
gTokenBuff.szName,
sizeof(gTokenBuff.szName));

// szValue
if (ret == SMS_OK)
ret = CopyString2VB(&pTokenInfoVB->szValue,
gTokenBuff.szValue,
sizeof(gTokenBuff.szValue));

// dwOp
pTokenInfoVB->dwOp = gTokenBuff.dwOp;

// szArchitecture
if (ret == SMS_OK)
ret = CopyString2VB(&pTokenInfoVB->szArchitecture,
gTokenBuff.szArchitecture,
sizeof(gTokenBuff.szArchitecture));

// szGroupClass
if (ret == SMS_OK)
ret = CopyString2VB(&pTokenInfoVB->szGroupClass,
gTokenBuff.szGroupClass,
sizeof(gTokenBuff.szGroupClass));

// szAttributeName
if (ret == SMS_OK)
ret = CopyString2VB(&pTokenInfoVB->szAttributeName,
gTokenBuff.szAttributeName,
sizeof(gTokenBuff.szAttributeName));

// szTokenString
if (ret == SMS_OK)
ret = CopyString2VB(&pTokenInfoVB->szTokenString,
gTokenBuff.szTokenString,
sizeof(gTokenBuff.szTokenString));

// bIndent
pTokenInfoVB->bIndent = gTokenBuff.bIndent;

gbANSI = FALSE;
return ret;
}
/* VB:
Declare Function SmsAddToken& Lib "vb4sms32.dll" (ByVal hFilter As Long, opAndOr As ANDOR, pTokenInfo As TOKEN, ByVal iIndex As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsAddTokenVB(HANDLE hFilter, ANDOR* opAndOr, TOKENVB *pTokenInfoVB, INT iIndex)
{
//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to TOKENVB struct from VB is invalid)
if (IsBadReadPtr(pTokenInfoVB, sizeof(*pTokenInfoVB)))
return SMS_INVALID_PARAMETER;

if (VBStringLength(pTokenInfoVB->szName) >= sizeof(gTokenBuff.szName))
return SMS_INVALID_PARAMETER;

if (VBStringLength(pTokenInfoVB->szValue) >= sizeof(gTokenBuff.szValue))
return SMS_INVALID_PARAMETER;

if (VBStringLength(pTokenInfoVB->szArchitecture)
>= sizeof(gTokenBuff.szArchitecture))
return SMS_INVALID_PARAMETER;

if (VBStringLength(pTokenInfoVB->szGroupClass)
>= sizeof(gTokenBuff.szGroupClass))
return SMS_INVALID_PARAMETER;

if (VBStringLength(pTokenInfoVB->szAttributeName)
>= sizeof(gTokenBuff.szAttributeName))
return SMS_INVALID_PARAMETER;

if (VBStringLength(pTokenInfoVB->szTokenString)
>= sizeof(gTokenBuff.szTokenString))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Turn on ANSI string copy
gbANSI = TRUE;

// tokenType
gTokenBuff.tokenType = pTokenInfoVB->tokenType;

// szName
CopyString2Sms(gTokenBuff.szName, pTokenInfoVB->szName,
sizeof(gTokenBuff.szName));

// szValue
CopyString2Sms(gTokenBuff.szValue, pTokenInfoVB->szValue,
sizeof(gTokenBuff.szValue));

// dwOp
gTokenBuff.dwOp = pTokenInfoVB->dwOp;

// szArchitecture
CopyString2Sms(gTokenBuff.szArchitecture, pTokenInfoVB->szArchitecture,
sizeof(gTokenBuff.szArchitecture));

// szGroupClass
CopyString2Sms(gTokenBuff.szGroupClass, pTokenInfoVB->szGroupClass,
sizeof(gTokenBuff.szGroupClass));

// szAttributeName
CopyString2Sms(gTokenBuff.szAttributeName, pTokenInfoVB->szAttributeName,
sizeof(gTokenBuff.szAttributeName));

// szTokenString
CopyString2Sms(gTokenBuff.szTokenString, pTokenInfoVB->szTokenString,
sizeof(gTokenBuff.szTokenString));

// bIndent
gTokenBuff.bIndent = pTokenInfoVB->bIndent;

// Turn back off ANSI copy
gbANSI = FALSE;

// Call 32bit SMS API routine
return SmsAddToken(hFilter, *opAndOr, &gTokenBuff, iIndex);
}

/* VB:
Declare Function SmsGetTokenCount& Lib "vb4sms32.dll" (ByVal hFilter As Long, pCount As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsGetTokenCountVB(HANDLE hFilter, DWORD *pCount)
{
//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to Filter Handle from VB is invalid)
if (IsBadWritePtr(pCount, sizeof(*pCount)))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Call 32bit SMS API routine
return SmsGetTokenCount(hFilter, pCount);
}

/* VB:
Declare Function SmsManipulateTokens& Lib "vb4sms32.dll" (ByVal hFilter As Long, ByVal dwFlags As Long, ByVal iStart As Long, ByVal iEnd As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsManipulateTokensVB(HANDLE hFilter, DWORD dwFlags, INT iStart, INT iEnd)
{
// Call 32bit SMS API routine
return SmsManipulateTokens(hFilter, dwFlags, iStart, iEnd);
}

/* VB:
Declare Function SmsGetAllFilters& Lib "vb4sms32.dll" (ByVal hContainer As Long, pahFilters As Long, pCount As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsGetAllFiltersVB(HANDLE hContainer, LPSAFEARRAY* ppArray, DWORD *pCount)
{
SMS_STATUS ret;
HANDLE *pahFilters;
SAFEARRAY* &pArray = *ppArray;

//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (Pointer to Count from VB is invalid)
if (IsBadWritePtr(pCount, sizeof(*pCount)))
return SMS_INVALID_PARAMETER;

// if (Count is too big)
if (*pCount >= 0x80000000 / sizeof(*pahFilters))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Get the count of FILTER_INFOs
*pCount = 0;
ret = SmsGetAllFilters(hContainer, NULL, pCount);
if (ret != SMS_MORE_DATA) return ret;

// Create or Redim as necessary
if (AllocVBArray(pArray, *pCount, sizeof(*pahFilters)) != S_OK)
return SMS_INVALID_PARAMETER;

// Lock down the array and obtain pointer to the data
if (SafeArrayAccessData(pArray, (void**)&pahFilters) != S_OK)
return SMS_INVALID_PARAMETER;

// Call 32bit SMS API routine
ret = SmsGetAllFilters(hContainer, pahFilters, pCount);

// Unlock the VB array of FILTER_INFOs
SafeArrayUnaccessData(pArray);
return ret;
}

/* VB:
Declare Function SmsEnumObjectTypes& Lib "vb4sms32.dll" (ByVal hConnection As Long, pObjects() As String, pCount As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsEnumObjectTypesVB(HANDLE hConnection, LPSAFEARRAY* ppArray, DWORD *pCount)
{
SAFEARRAY* &pArray = *ppArray;
BSTR* paObjTypesVB;
SMS_STATUS ret;

//////////////////////////////////////////////////////////////////////////
// Check parameters

// if (pCount is invalid)
if (IsBadWritePtr(pCount, sizeof(*pCount)))
return SMS_INVALID_PARAMETER;

// if (Count is too big)
if (*pCount >= 0x80000000 / sizeof(*paObjTypesVB))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Get the count of object types
*pCount = 0;
ret = SmsEnumObjectTypes(hConnection, NULL, pCount);
if (ret != SMS_MORE_DATA) return ret;

// Create or Redim as necessary
if (AllocVBArray(pArray, *pCount, sizeof(*paObjTypesVB)) != S_OK)
return SMS_INVALID_PARAMETER;

// Lock down the array and obtain pointer to the data
if (SafeArrayAccessData(pArray, (void**)&paObjTypesVB) != S_OK)
return SMS_INVALID_PARAMETER;

// Get an array large enough to accept object types

DWORD cObjTypes = *pCount; 
SMSBUFF* pObjTypes = new SMSBUFF[cObjTypes];
if (pObjTypes != NULL)
{
// Call 32bit SMS API routine
ret = SmsEnumObjectTypes(hConnection, pObjTypes, pCount);

if (ret == SMS_OK)
for (DWORD dwIndex = 0; dwIndex < cObjTypes; dwIndex++)
{
ret = CopyString2VB(&paObjTypesVB[dwIndex],
pObjTypes[dwIndex]);
if (ret != SMS_OK) break;
}

// Unlock the array of object types
delete[] pObjTypes;
pObjTypes = NULL;
}
else ret = SMS_ERROR;

// Unlock the VB array of object types
SafeArrayUnaccessData(pArray);
return ret;
}


SMS_STATUS CopyObjectDescriptor2VB(OBJDESCRIPTORVB* pObjectVB,
OBJDESCRIPTOR* pObject)
{
SMS_STATUS ret = SMS_OK;

// objType
pObjectVB->objType = pObject->objType;

// szName
if (ret == SMS_OK)
ret = CopyString2VB(&pObjectVB->szName,
pObject->szName);

// szFriendlyName
if (ret == SMS_OK)
ret = CopyString2VB(&pObjectVB->szFriendlyName,
pObject->szFriendlyName);

// bGotFriendlyName
pObjectVB->bGotFriendlyName = pObject->bGotFriendlyName;

// dwRelopMin
pObjectVB->dwRelopMin = pObject->dwRelopMin;

// dwRelopMax
pObjectVB->dwRelopMax = pObject->dwRelopMax;

// bGotRelops
pObjectVB->bGotRelops = pObject->bGotRelops;

return ret;
}
/* VB:
Declare Function SmsEnumObjects& Lib "vb4sms32.dll" (ByVal hConnection As Long, ByVal pszObjectType As String, pPredecessors() As String, ByVal CtPredecessors As Long, pObjects() As OBJDESCRIPTOR, pCtObjects As Long)
'*/
extern "C" SMS_STATUS WINAPI
SmsEnumObjectsVB(HANDLE hConnection, char* pszObjectType, LPSAFEARRAY* ppPredecessorsVB, DWORD CtPredecessors, LPSAFEARRAY* ppArray, DWORD *pCount)
{
SAFEARRAY* &pArray = *ppArray;
SAFEARRAY* &pPredecessorsVB = *ppPredecessorsVB;
BSTR* paPredecessorsVB;
OBJDESCRIPTORVB* paObjectsVB;
SMS_STATUS ret = SMS_OK;

//////////////////////////////////////////////////////////////////////////
// Check parameters

if (ppPredecessorsVB != NULL && CtPredecessors > 0)
{
if (pPredecessorsVB->cDims != 1)
return SMS_INVALID_PARAMETER;

if (pPredecessorsVB->cbElements!= 4)
return SMS_INVALID_PARAMETER;

if (pPredecessorsVB->rgsabound[0].cElements < CtPredecessors)
return SMS_INVALID_PARAMETER;
}

// if (pCount is invalid)
if (IsBadWritePtr(pCount, sizeof(*pCount)))
return SMS_INVALID_PARAMETER;

// if (Count is too big)
if (*pCount >= 0x80000000 / sizeof(*paObjectsVB))
return SMS_INVALID_PARAMETER;

//////////////////////////////////////////////////////////////////////////

// Copy Predecessors array
// Get an array large enough to accept object types
SMSBUFF* pPredecessors = NULL;
if (ppPredecessorsVB != NULL && CtPredecessors > 0)
{
pPredecessors = new SMSBUFF[CtPredecessors];
if (pPredecessors == NULL) return SMS_ERROR;

// Lock down the array and obtain pointer to the data
if (SafeArrayAccessData(pPredecessorsVB, (void**)&paPredecessorsVB) != S_OK)
{ret = SMS_INVALID_PARAMETER; goto SmsEnumObjectsVB_Quit;}

// Turn on ANSI string copy
gbANSI = TRUE;

for (DWORD dwIndex = 0; dwIndex < CtPredecessors; dwIndex++)
{
ret = CopyString2Sms(pPredecessors[dwIndex],
paPredecessorsVB[dwIndex]);
if (ret != SMS_OK) break;
}

// Turn back off ANSI string copy
gbANSI = FALSE;

// Unlock the VB array of object types
SafeArrayUnaccessData(pPredecessorsVB);
}

if (ret == SMS_OK)
{
// Get the count of object types
*pCount = 0;
ret = SmsEnumObjects(hConnection, pszObjectType, pPredecessors,
CtPredecessors, NULL, pCount);
if (ret != SMS_MORE_DATA) goto SmsEnumObjectsVB_Quit;

// Create or Redim as necessary
if (AllocVBArray(pArray, *pCount, sizeof(*paObjectsVB)) != S_OK)
{ret = SMS_INVALID_PARAMETER; goto SmsEnumObjectsVB_Quit;}

// Lock down the array and obtain pointer to the data
if (SafeArrayAccessData(pArray, (void**)&paObjectsVB) != S_OK)
{ret = SMS_INVALID_PARAMETER; goto SmsEnumObjectsVB_Quit;}

// Get an array large enough to accept object types
DWORD cObjects = *pCount;
OBJDESCRIPTOR* pObjects = new OBJDESCRIPTOR[cObjects];
if (pObjects != NULL)
{
// Call 32bit SMS API routine
ret = SmsEnumObjects(hConnection, pszObjectType, pPredecessors,
CtPredecessors, pObjects, pCount);

if (ret == SMS_OK)
for (DWORD dwIndex = 0; dwIndex < cObjects; dwIndex++)
{
ret = CopyObjectDescriptor2VB(&paObjectsVB[dwIndex],
&pObjects[dwIndex]);
if (ret != SMS_OK) break;
}

// Unlock the array of object types
delete[] pObjects;
pObjects = NULL;
}
else ret = SMS_ERROR;

// Unlock the VB array of object types
SafeArrayUnaccessData(pArray);
}

SmsEnumObjectsVB_Quit:
// Free the array of predecessors
if (pPredecessors != NULL) delete[] pPredecessors;
pPredecessors = NULL;

return ret;
}