Microsoft Visual C++ .NET Professional Projects - Premier Press
.pdf
IMPLEMENTING REMOTING |
Chapter 31 |
901 |
|
|
|
|
|
using namespace System::Runtime::Remoting;
using namespace System::Runtime::Remoting::Channels; using namespace System::Runtime::Remoting::Channels::Tcp;
// This is the entry point for this application int _tmain(void)
{
TcpChannel* pChannel2 = new TcpChannel(8085);
ChannelServices::RegisterChannel(pChannel2);
Type* pType = __typeof(nsRemoting::CQuizServer);
RemotingConfiguration::RegisterWellKnownServiceType(pType, “Quiz”,
WellKnownObjectMode::SingleCall);
Console::WriteLine(“Please hit <ENTER> to exit...”);
Console::ReadLine();
return 0;
}
Creating the Client Application
You will create the client application as a Managed C++ application. To the existing solution, add a new project of the type Managed C++ Application. Call it RemoteClient. The IDE will create the following files:
Stdafx.h
Stdafx.cpp
RemoteClient.cpp
AssemblyInfo.cpp
The client is a simple GUI application that will have the following:
Two buttons, Submit and Exit.
Three radio buttons to represent the three choices that the user can select.
This interface assumes all questions will have three options. It can be easily modified for greater flexibility.
You will be using classes under the Remoting namespace to connect to the remote server; therefore, you will have the following namespace declarations:
902 Project 10 NETWORKING AND REMOTING IN VC++ .NET
using namespace System::Runtime::Remoting;
using namespace System::Runtime::Remoting::Channels;
using namespace System::Runtime::Remoting::Channels::Tcp;
Also, you will use the CQuiz class declared under the nsRemoting namespace; hence, the following declaration is required:
using namespace nsRemoting;
The first step is to create the user interface. To accomplish this, create a new class that derives from the Form class. This class will house the UI of the client application. Hence, declare the following variables:
__gc class CQuizForm : public Form
{
private:
Next, declare a variable to store the caption of the form and variables, two integers to store the width and height of the client form, and two Label type variables to display the question number and the question:
String* pCaption;
int nWidth;
int nHeight;
Label* pLblQuestion;
Label* pLblQNum;
Add three radio buttons to display the answers, and two Button type variables for the Submit and the Exit buttons:
RadioButton* pRadioOpt1;
RadioButton* pRadioOpt2;
RadioButton* pRadioOpt3;
Button *pBtnSubmit;
Button *pBtnExit;
CQuizServer is the remote server class that is declared in the nsRemoting namespace. Next, you need to implement the constructor of the form. The client needs to obtain a reference to the remote server:
m_pQuizServer = (CQuizServer*)
Activator::GetObject(__typeof(nsRemoting::CQuizServer),
IMPLEMENTING REMOTING |
Chapter 31 |
903 |
|
|
|
|
|
“tcp://localhost:8085/Quiz”);
Next, initialize the user-interface elements. First, take a look at the basic settings for the main form:
//set the caption
Text = pCaption;
//set the size of the form
Size = Drawing::Size(nWidth, nHeight);
//disable the maximize box. set_MaximizeBox(false);
The form has two labels. The following is the code for one of the label controls:
pLblQNum = new Label(); pLblQNum->Text = “Question No. 1”;
pLblQNum->Size = Drawing::Size(100, 15); pLblQNum->BorderStyle = BorderStyle::FixedSingle; pLblQNum->Location = Drawing::Point(15, 15); pLblQNum->set_ForeColor(Color::Red);
Take a look at how to configure a radio button:
pRadioOpt1 = new RadioButton(); pRadioOpt1->Text = “Option1”; pRadioOpt1->TabIndex = 1;
pRadioOpt1->Size = Drawing::Size(250, 20); pRadioOpt1->Location = Drawing::Point(30, 90); pRadioOpt1->Visible = false;
While configuring a Button, you need to specify the event handler for any of its events. In case of a Button, you would want a method to do something on the Click event, and so create a new EventHandler object for this purpose:
pBtnSubmit = new Button(); pBtnSubmit->Text = “&Start”; pBtnSubmit->TabIndex = 4; pBtnSubmit->Size = Drawing::Size(55, 20);
pBtnSubmit->Location = Drawing::Point(80, 180);
pBtnSubmit->Click += (new EventHandler(this, &CQuizForm::OnSubmitButtonClick));
904 Project 10 NETWORKING AND REMOTING IN VC++ .NET
The last step is to add all the controls you have created to the Controls collection of the form:
Controls->Add(pLblQNum);
Next, examine what the event handler method for the Submit button is coded to do. This method retrieves the correct answer to a question and compares it with the option selected by the user. If they are the same, a variable bCorrect is set to
true.
void OnSubmitButtonClick (Object *sender, EventArgs *e)
{
int nResult = m_pQuizServer->GetAnswer(m_nQNum - 1); bool bCorrect = false;
switch(nResult)
{
case 1:
if (pRadioOpt1->get_Checked()) bCorrect = true;
break; case 2:
if (pRadioOpt2->get_Checked()) bCorrect = true;
break; case 3:
if (pRadioOpt3->get_Checked()) bCorrect = true;
break;
}
//If the answer is correct increment the score and display a message. if ( bCorrect )
{
MessageBox::Show(“Correct Answer”, “Result”); m_nCorrect++;
}
else
{
MessageBox::Show(“Incorrect Answer”, “Result”);
IMPLEMENTING REMOTING |
Chapter 31 |
905 |
|
|
|
|
|
}
}
Check if all the questions have been asked, and if so, display an appropriate message depending on the score:
if (m_nQNum > 10)
{
return;
}
If questions remain, then reset all the radio buttons, get the next question from the server, and display the options:
pRadioOpt1->set_Checked(false); pRadioOpt2->set_Checked(false); pRadioOpt3->set_Checked(false);
String* pstrQuestion = m_pQuizServer->GetNextQuestion(m_nQNum); pLblQuestion->Text = pstrQuestion;
For each option, you need to query the RemoteServer to get the set of answers. Since all questions will have three answers, you can retrieve the answers using a for loop:
for (int i=1; i<4; i++)
{
String* pstrOpt = m_pQuizServer->GetOptions(m_nQNum, i); if (i == 1)
pRadioOpt1->Text = pstrOpt; else if (i == 2) pRadioOpt2->Text = pstrOpt; else if (i == 3) pRadioOpt3->Text = pstrOpt;
}
m_nQNum++;
}
That completes our discussion of the RemoteClient application.
As you saw, the syntax for accessing services from a remote server is not very different from the way you access a local assembly and from a similar application that uses DCOM. But, remember that the plumbing provided by the .NET platform as Remoting is very different from DCOM in the COM+ platform.
IMPLEMENTING REMOTING |
Chapter 31 |
907 |
|
|
|
|
|
//TcpChannel* m_pChannel; CQuizServer* m_pQuizServer;
int m_nQNum; int m_nCorrect;
bool bButttonReset; String* m_pUserName;
public:
CQuizForm()
{
pCaption = “Quiz Dialog”; nWidth = 300;
nHeight = 240; bButttonReset = false; m_nQNum = 1; m_nCorrect = 0;
//Registers the channel for communication with Server //RegisterChannel();
m_pQuizServer = (CQuizServer*) Activator::GetObject(__typeof(nsRemoting::CQuizServer), “tcp://localhost:8085/Quiz”);;
//Do the intialization
InitForm();
}
void ~CQuizForm()
{
// Form is being destroyed. Do any necessary cleanup here. Form::Dispose();
}
void InitForm()
{
// Basic WinForm Settings
IMPLEMENTING REMOTING |
Chapter 31 |
909 |
|
pBtnSubmit->Text = “&Start”; |
|
|
|
|
|
|
|
pBtnSubmit->TabIndex = 4; |
|
|
|
pBtnSubmit->Size = Drawing::Size(55, 20); |
|
|
|
pBtnSubmit->Location = Drawing::Point(80, 180); |
|
|
|
pBtnSubmit->Click += (new EventHandler(this, &CQuizForm::OnSubmitButtonClick));
pBtnExit = new Button(); pBtnExit->Text = “E&xit”; pBtnExit->TabIndex = 5;
pBtnExit->Size = Drawing::Size(55, 20);
pBtnExit->Location = Drawing::Point(165, 180);
pBtnExit->Click += (new EventHandler(this, &CQuizForm::OnExitButtonClick));
Controls->Add(pLblQNum);
Controls->Add(pLblQuestion);
Controls->Add(pRadioOpt1);
Controls->Add(pRadioOpt2);
Controls->Add(pRadioOpt3);
Controls->Add(pBtnSubmit);
Controls->Add(pBtnExit);
//Set the pBtnSubmit as the default
Form::set_AcceptButton(pBtnSubmit); pLblQNum->Visible = false;
//Display the welcome message
String* pstrWelcome = m_pQuizServer->DoWelcome(“ BUDDY!”);
pstrWelcome = String::Concat(pstrWelcome, “\nPlease press Start button to start the Quiz.”);
pLblQuestion->Text = pstrWelcome;
}
//Handles the Next button
void OnSubmitButtonClick (Object *sender, EventArgs *e)
{
if (!bButttonReset)
{
pBtnSubmit->Text = “&Submit”; pLblQNum->Visible = true;
