Microsoft Visual C++ .NET Professional Projects - Premier Press
.pdf
IMPLEMENTING COM USING ATL |
Chapter 19 |
621 |
|
|
|
|
|
__interface ICardCheck : IDispatch
{
[propget, id(1), helpstring(“property CardType”)] HRESULT CardType([out, retval] BSTR* pVal);
[propput, id(1), helpstring(“property CardType”)] HRESULT CardType([in] BSTR newVal);
[id(2), helpstring(“method Validate”)] HRESULT Validate([in] BSTR bstrCardNo, [out,retval]
VARIANT* vRetVal);
};
As you see, a pair of Put and Get methods have been added to the class for the CardType property. These methods are used to set the value of the CardType property and retrieve the stored value, respectively. The validate method declaration, which accepts one input type parameter and one return type parameter, is added. This is the method wherein you will code for the Luhn algorithm.
For storing the state data of the property CardType, you will need to add a variable to the class. State data is the data relevant to a particular instance of a component. To add a private variable bstrCardType in the header file, use the following code:
class ATL_NO_VTABLE CCardCheck : public ICardCheck
{
private:
BSTR bstrCardType;
public:
CCardCheck()
{
}
………
……….
};
Use the following code to implement the property’s Get and Put methods:
STDMETHODIMP CCardCheck::get_CardType(BSTR* pVal)
{
// TODO: Add your implementation code here
622 Project 5 CREATING A COM COMPONENT USING ATL
*pVal=SysAllocString(bstrCardType); return S_OK;
}
STDMETHODIMP CCardCheck::put_CardType(BSTR newVal)
{
// TODO: Add your implementation code here bstrCardType=SysAllocString(newVal); return S_OK;
}
Next, you will add code to implement the Luhn algorithm in the validate function (the skeleton for the function has been added by the wizard):
1.First, you need to convert the BSTR value to char *. This is done by allocating the required bytes of memory to the char * type variable, and then copying the BSTR value into the newly created variable using the
WideCharToMultiByte method.
NOTE
Wide characters are used to store Unicode characters. In the following code, the wcslen method is a wide character version of the old strlen function:
int len = wcslen(bstrCardNo);
char * pszNumber = new char[len+1];
int last =
WideCharToMultiByte(CP_ACP,0,bstrCardNo,len,pszNumber,len,0,0);
pszNumber[last] = 0;
In the preceding code, the first parameter to the WideChartoMultiByte function, CP_ACP, specifies that the ANSI character set is to be used. The second parameter is a flag, which specifies how the function should handle characters that have no equivalent in the target character set. 0 here means that the default character will be used. The third parameter, bstrCardNo, is the source string, and the fourth parameter, len, is
IMPLEMENTING COM USING ATL |
Chapter 19 |
623 |
|
|
|
|
|
the length of the string. The target string and its size are the fifth and sixth parameters, pszNumber and len, respectively.
2.Similarly, convert the card type into char * from BSTR.
3.After converting the strings, you can check if the card type is a Visa card. If it is, then check whether the number of digits is 13 or 16. If it is either, then check if the starting digit is 4. Similar checks are done to Master Card and Amex cards. If all the prior conditions are met, then check to see if it is a Luhn number:
for(i = 0, nSum = 0; i < 16; i += 2)
//for each alternative numbers starting from left
{
//Convert from char to integer by subtracting the ASCII for 0 //and double the number
int nDigit = (pszNumber[i] - 48) * 2;
//If the number has a single digit
if(nDigit < 10) {nSum=nSum + nDigit;
}
//If the number has two digits extract each of the digits and add them else
{
nSum =nSum + nDigit/10; nSum = nSum + nDigit%10;
}
//Now add the unchanged numbers nSum=nSum + (pszNumber[i+1]-48);
}
//return the results nSum=nSum%10;
CComVariant p(nSum); *bRetVal=(VARIANT)p;
624 Project 5 CREATING A COM COMPONENT USING ATL
Check if the sum is divisible by 10. If the remainder is 0, then the number is a Luhn number; otherwise it is not. In the preceding code the remainder will be returned. If it is 0, it is a valid credit card number.
Here is the complete method:
STDMETHODIMP CCardCheck::Validate(BSTR bstrCardNo, VARIANT* vRetVal)
{
// TODO: Add your implementation code here int i;
int nSum;
//Convert the card number from BSTR to char * int len = wcslen(bstrCardNo);
char * pszCardNo = new char[len+1]; int last =
WideCharToMultiByte(CP_ACP,0,bstrCardNo,len,pszCardNo,len,0,0);
pszCardNo[last] = 0;
//Convert the card type from BSTR to char * len = wcslen(bstrCardType);
char *pszCardType=new char[len+1]; last =
WideCharToMultiByte(CP_ACP,0,bstrCardType,len,pszCardType,len,0,0);
pszCardType[last] = 0;
CString s(pszCardType);
//Check if one of the accepted card types if(s.CompareNoCase(“VISA”)!=0 && s.CompareNoCase(“MASTER”)!=0 && s.CompareNoCase(“AMEX”)!=0)
{
CComVariant n(1); *vRetVal=(VARIANT)n;
return S_OK;
}
//Check if the card number Is valid for Visa if(s.CompareNoCase(“VISA”)==0)
{
if(strlen(pszCardNo)!=13 && strlen(pszCardNo)!=16)
626 Project 5 CREATING A COM COMPONENT USING ATL
if(s.CompareNoCase(“AMEX”)==0)
{
if(strlen(pszCardNo)!=15)
{
CComVariant n(1);
*vRetVal=(VARIANT)n;
return S_OK;
}
if(pszCardNo[0]!=’3’)
{
CComVariant n(1);
*vRetVal=(VARIANT)n;
return S_OK;
}
if(pszCardNo!=’4’ && pszCardNo!= ‘7’)
{
CComVariant n(1); *vRetVal=(VARIANT)n; return S_OK;
}
}
//Check if the card number is a valid Luhn number for(i = 0, nSum = 0; i < 16; i += 2)
{
int nDigit = (pszCardNo[i] - 48) * 2; if(nDigit < 10)
{
nSum=nSum + nDigit;
}
else
{
nSum =nSum + nDigit/10; nSum = nSum + nDigit%10;
}
nSum=nSum + (pszCardNo[i+1]-48);
}
nSum=nSum%10;
628 Project 5 CREATING A COM COMPONENT USING ATL
4. Add the following code to the Click event of the button on the form:
private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) |
Handles Button1.Click |
|
|
Dim card As New LuhnChecker.CCardCheck() |
|
|
Dim n As Integer |
|
|
card.CardType = “Visa” |
|
|
n = card.Validate(“4477460020208002”) |
‘ the number to |
check |
|
|
|
If (n = 0) Then |
|
|
MsgBox(“Valid Number”) |
|
|
Else |
|
MsgBox(“Invalid Number”)
End If
End Sub
Next, you will test the component by hosting it on an ASP page. To accomplish this, you will require two files. The first is an HTML file with a form on which the credit card number can be entered and the card type can be selected. Name the file default.htm.
The following is the HTML code for it:
<html>
<head>
<title>Art Shop Checkout</title>
<meta http-equiv=”Content-Type” content=”text/html; charset=iso-8859-1”> </head>
<body bgcolor=”#FFFFFF” text=”#000000”>
<form name=”Checkout” method=”post” action=”checkCard.asp”> <p>Please Enter your Credit Card details</p>
<p>Number:
<input type=”text” name=”cardno”>
</p>
<p>Card Type:
<select name=”cardtype”> <option>VISA</option>
IMPLEMENTING COM USING ATL |
Chapter 19 |
629 |
|
|
|
|
|
<option>MASTER</option>
<option>AMEX</option>
</select>
</p>
<p>Your Date of Birth(mm/dd/yyyy): <input type=”text” name=”dob”>
</p>
<p>
<input type=”submit” name=”Submit” value=”Submit”>
</p>
</p>
</form>
</body>
</html>
Data entered through this page will be received by an ASP page, which creates an instance of your component and validates the credit card number entered. Create a file named cardCheck.asp and enter the following code:
<html>
<body>
<%
Dim card dim n
Set card = Server.CreateObject(“LuhnChecker.CardCheck”) card.cardType=request.form(“cardtype”) n=card.Validate(request.form(“cardno”))
if n <> 0 then
response.write “Invalid card number. Please recheck” else
response.write “Thank you for shopping at the Art Shop” end if
%>
</body>
</html>
