|
I am trying to implement a service provider to connect with a hardware device. request some suggestion on my approach and ideas to implement a robust system.
Mentioned are the raised requirements
0. Receive data from other EXE process
1. To process received Q information.
2. Asynchronously send information on some failure.
TO implement the mentioned system:
1. Selected 2 named pipe (commandRecv & commandSend)
2. CommandRecv pipe will be used as "Named Pipe Server Using Overlapped" I/O"
3. commandSend pipe will be used for sending the processed information.
4. commandSend will also need to send all the async messages from service provider to connected application.
On init system will create a thread to hold connection instance of commandSend pipe.After creating thread instance commandRecv pipe will be set to overlapped I/O mode and process recieve queue information.
This is the code which i am trying to extend:
<pre>#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#define CONNECTING_STATE 0
#define READING_STATE 1
#define WRITING_STATE 2
#define INSTANCES 4
#define PIPE_TIMEOUT 5000
#define BUFSIZE 4096
typedef struct
{
OVERLAPPED oOverlap;
HANDLE hPipeInst;
TCHAR chRequest[BUFSIZE];
DWORD cbRead;
TCHAR chReply[BUFSIZE];
DWORD cbToWrite;
DWORD dwState;
BOOL fPendingIO;
int processId;
} PIPEINST, *LPPIPEINST;
typedef struct
{
char appName[256];
int processId;
}PIPEHANDSHAKE;
VOID DisconnectAndReconnect(DWORD);
BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);
VOID GetAnswerToRequest(LPPIPEINST);
PIPEINST Pipe[INSTANCES];
HANDLE hEvents[INSTANCES];
HANDLE responsePipeHandle[INSTANCES];
DWORD WINAPI InstanceThread(LPVOID);
HANDLE hPipeHandles[10];
PULONG s;
LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe");
LPTSTR lpszResponsePipe = TEXT("\\\\.\\pipe\\mynamedpipe1");
int responsePipeConnectionHandler(VOID)
{
BOOL fConnected = FALSE;
DWORD dwThreadId = 0;
HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL;
int cbBytesRead;
INT threadCount=0;
char bufferSize[512];
for (;;)
{
_tprintf( TEXT("\nPipe Server: Main thread awaiting client connection on %s\n"), lpszResponsePipe);
hPipe = CreateNamedPipe(
lpszResponsePipe,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE |
PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
BUFSIZE,
BUFSIZE,
0,
NULL);
if (hPipe == INVALID_HANDLE_VALUE)
{
_tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError());
return -1;
}
fConnected = ConnectNamedPipe(hPipe, NULL) ?
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if(fConnected){
PIPEHANDSHAKE processData;
fConnected = ReadFile(
hPipe,
bufferSize,
sizeof(PIPEHANDSHAKE),
&cbBytesRead,
NULL);
memset(&processData,0,sizeof(PIPEHANDSHAKE));
memcpy(&processData,&bufferSize,sizeof(PIPEHANDSHAKE));
printf("APP Process id: %d , app name: %s",processData.processId,processData.appName);
}
}
return 0;
}
DWORD WINAPI InstanceThread(LPVOID lpvParam)
{
HANDLE hHeap = GetProcessHeap();
TCHAR* pchRequest = (TCHAR*)HeapAlloc(hHeap, 0, BUFSIZE*sizeof(TCHAR));
TCHAR* pchReply = (TCHAR*)HeapAlloc(hHeap, 0, BUFSIZE*sizeof(TCHAR));
DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;
BOOL fSuccess = FALSE;
HANDLE hPipe = NULL;
if (lpvParam == NULL)
{
printf( "\nERROR - Pipe Server Failure:\n");
printf( " InstanceThread got an unexpected NULL value in lpvParam.\n");
printf( " InstanceThread exitting.\n");
if (pchReply != NULL) HeapFree(hHeap, 0, pchReply);
if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);
return (DWORD)-1;
}
if (pchRequest == NULL)
{
printf( "\nERROR - Pipe Server Failure:\n");
printf( " InstanceThread got an unexpected NULL heap allocation.\n");
printf( " InstanceThread exitting.\n");
if (pchReply != NULL) HeapFree(hHeap, 0, pchReply);
return (DWORD)-1;
}
if (pchReply == NULL)
{
printf( "\nERROR - Pipe Server Failure:\n");
printf( " InstanceThread got an unexpected NULL heap allocation.\n");
printf( " InstanceThread exitting.\n");
if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);
return (DWORD)-1;
}
printf("InstanceThread created, receiving and processing messages.\n");
hPipe = (HANDLE) lpvParam;
while (1)
{
fSuccess = ReadFile(
hPipe,
pchRequest,
BUFSIZE*sizeof(TCHAR),
&cbBytesRead,
NULL);
if (!fSuccess || cbBytesRead == 0)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
{
_tprintf(TEXT("InstanceThread: client disconnected.\n"), GetLastError());
}
else
{
_tprintf(TEXT("InstanceThread ReadFile failed, GLE=%d.\n"), GetLastError());
}
break;
}
else{
printf(" Recieved data in PIPE");
}
cbReplyBytes = (strlen(pchRequest)+1)*sizeof(TCHAR);
fSuccess = WriteFile(
hPipe,
pchRequest,
cbReplyBytes,
&cbWritten,
NULL);
if (!fSuccess || cbReplyBytes != cbWritten)
{
_tprintf(TEXT("InstanceThread WriteFile failed, GLE=%d.\n"), GetLastError());
break;
}
}
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
HeapFree(hHeap, 0, pchRequest);
HeapFree(hHeap, 0, pchReply);
printf("InstanceThread exitting.\n");
return 1;
}
int _tmain(VOID)
{
DWORD i, dwWait, cbRet, dwErr,hThread;
BOOL fSuccess;
int dwThreadId;
hThread = CreateThread(
NULL,
0,
responsePipeConnectionHandler,
NULL,
0,
&dwThreadId);
if (hThread == NULL)
{
printf("Response server creation failed with %d.\n", GetLastError());
return 0;
}
for (i = 0; i < INSTANCES; i++)
{
hEvents[i] = CreateEvent(
NULL,
TRUE,
TRUE,
NULL);
if (hEvents[i] == NULL)
{
printf("CreateEvent failed with %d.\n", GetLastError());
return 0;
}
Pipe[i].oOverlap.hEvent = hEvents[i];
Pipe[i].hPipeInst = CreateNamedPipe(
lpszPipename,
PIPE_ACCESS_DUPLEX |
FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE |
PIPE_WAIT,
INSTANCES,
BUFSIZE*sizeof(TCHAR),
BUFSIZE*sizeof(TCHAR),
PIPE_TIMEOUT,
NULL);
if (Pipe[i].hPipeInst == INVALID_HANDLE_VALUE)
{
printf("CreateNamedPipe failed with %d.\n", GetLastError());
return 0;
}
Pipe[i].fPendingIO = ConnectToNewClient(
Pipe[i].hPipeInst,
&Pipe[i].oOverlap);
Pipe[i].dwState = Pipe[i].fPendingIO ?
CONNECTING_STATE :
READING_STATE;
}
while (1)
{
dwWait = WaitForMultipleObjects(
INSTANCES,
hEvents,
FALSE,
INFINITE);
i = dwWait - WAIT_OBJECT_0;
if (i < 0 || i > (INSTANCES - 1))
{
printf("Index out of range.\n");
return 0;
}
if (Pipe[i].fPendingIO)
{
fSuccess = GetOverlappedResult(
Pipe[i].hPipeInst,
&Pipe[i].oOverlap,
&cbRet,
FALSE);
switch (Pipe[i].dwState)
{
case CONNECTING_STATE:
if (! fSuccess)
{
printf("Error %d.\n", GetLastError());
return 0;
}
Pipe[i].dwState = READING_STATE;
break;
case READING_STATE:
if (! fSuccess || cbRet == 0)
{
DisconnectAndReconnect(i);
continue;
}
Pipe[i].cbRead = cbRet;
Pipe[i].dwState = WRITING_STATE;
break;
case WRITING_STATE:
if (! fSuccess || cbRet != Pipe[i].cbToWrite)
{
DisconnectAndReconnect(i);
continue;
}
Pipe[i].dwState = READING_STATE;
break;
default:
{
printf("Invalid pipe state.\n");
return 0;
}
}
}
switch (Pipe[i].dwState)
{
case READING_STATE:
fSuccess = ReadFile(
Pipe[i].hPipeInst,
Pipe[i].chRequest,
BUFSIZE*sizeof(TCHAR),
&Pipe[i].cbRead,
&Pipe[i].oOverlap);
if (fSuccess && Pipe[i].cbRead != 0)
{
Pipe[i].fPendingIO = FALSE;
Pipe[i].dwState = WRITING_STATE;
continue;
}
dwErr = GetLastError();
if (! fSuccess && (dwErr == ERROR_IO_PENDING))
{
Pipe[i].fPendingIO = TRUE;
continue;
}
DisconnectAndReconnect(i);
break;
case WRITING_STATE:
GetAnswerToRequest(&Pipe[i]);
fSuccess = WriteFile(
Pipe[i].hPipeInst,
Pipe[i].chReply,
Pipe[i].cbToWrite,
&cbRet,
&Pipe[i].oOverlap);
if (fSuccess && cbRet == Pipe[i].cbToWrite)
{
Pipe[i].fPendingIO = FALSE;
Pipe[i].dwState = READING_STATE;
continue;
}
dwErr = GetLastError();
if (! fSuccess && (dwErr == ERROR_IO_PENDING))
{
Pipe[i].fPendingIO = TRUE;
continue;
}
DisconnectAndReconnect(i);
break;
default:
{
printf("Invalid pipe state.\n");
return 0;
}
}
}
return 0;
}
VOID DisconnectAndReconnect(DWORD i)
{
if (! DisconnectNamedPipe(Pipe[i].hPipeInst) )
{
printf("DisconnectNamedPipe failed with %d.\n", GetLastError());
}
Pipe[i].fPendingIO = ConnectToNewClient(
Pipe[i].hPipeInst,
&Pipe[i].oOverlap);
Pipe[i].dwState = Pipe[i].fPendingIO ?
CONNECTING_STATE :
READING_STATE;
}
BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
{
BOOL fConnected, fPendingIO = FALSE;
fConnected = ConnectNamedPipe(hPipe, lpo);
if (fConnected)
{
printf("ConnectNamedPipe failed with %d.\n", GetLastError());
return 0;
}
switch (GetLastError())
{
case ERROR_IO_PENDING:
fPendingIO = TRUE;
break;
case ERROR_PIPE_CONNECTED:
if (SetEvent(lpo->hEvent))
break;
default:
{
printf("ConnectNamedPipe failed with %d.\n", GetLastError());
return 0;
}
}
return fPendingIO;
}
VOID GetAnswerToRequest(LPPIPEINST pipe)
{
_tprintf( TEXT("[%d] %s\n"), pipe->hPipeInst, pipe->chRequest);
strncpy(pipe->chReply, "Default answer from server",BUFSIZE);
pipe->cbToWrite = (lstrlen(pipe->chReply)+1)*sizeof(TCHAR);
}</pre>
Current pending activities:
1. Need to get process id of the connected process. this will be mainly used for identifying the client to send response data.
Since the system is developed under MINGW - WIN32 - server will not be able to get the process id directly by using (GetNamedPipeClientProcessId). need to form a message structure on getting a client connection.
|
|
|
|
|
Why you can't use GetNamedPipeClientProcessId()?
Your limit is not MingW-32, but your OS.
This function isn't available on XP and below.
If you're developing on VISTA and above be shure that the WINVER and _WIN32_WINNT are correctly set for VISTA or above see here.
If you're developing on XP you're no luky, there is no way other than access file informations in kernel mode (you have to write a driver to do that).
modified 9-Feb-15 9:57am.
|
|
|
|
|
Yup, you are tight , iwas jsut able to extend and use it directly...
|
|
|
|
|
How I can read and write dicom image via c++?
|
|
|
|
|
Maybe this[^] link will help.
"the debugger doesn't tell me anything because this code compiles just fine" - random QA comment
"Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst
|
|
|
|
|
I wrote a program which includes these declarations:-
class PEN{public: HDC d; HPEN pen,old;
PEN(HDC dc,COLORREF col);
~PEN();};
/*-----*/
/* the device context dc must still exist when the pen is deleted */
PEN::PEN(HDC dc,COLORREF col){ d=dc;
pen=(HPEN)CreatePen(0,1,col);
old=(HPEN)SelectObject(dc,pen);};
PEN::~PEN(){ SelectObject(d,old);
DeleteObject(pen);};
/*-----*/
// then I can write for example:-
/*-----*/
if(xhairs) {
PEN orange(WIdc,RGB(255,128,0)); Line(WIdc,0,b/2,(int)(2*a),(int)(b/2));
Line(WIdc,(int)(a/2),0,(int)(a/2),b);
Line(WIdc,(int)(a*1.5),0,(int)(a*1.5),b);}
/*-----*/
and the new pen is automatically cleared away when control leaves the block where the pen was declared.
And similarly with fonts etc.
modified 3-Feb-15 9:41am.
|
|
|
|
|
And your question is?
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
Is this class declaration likely to be any use to any of you?
|
|
|
|
|
Anthony Appleyard wrote: Is this class declaration likely to be any use to any of you? Not really, the GDI+ Pen class[^] is already available.
|
|
|
|
|
I' m new with MFC. I needed to create a floating toolbar (CToolBar) with no option of docking and save and restore its last pos.
The toolbar also should be active all the time, but its NOT. When I'm openning a new child window (dialog for instance) from the mainframe, the floating tool bar become not active (I can not click on its buttons, or drag it etc..).
In the past I've used CDialog with Overlapped style and it was floating and always active as I needed. Is it possible to do the same with my Floating Toolbar? Thanks
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
toolbarIconSize.cx = toolbarIconSize.cy = TOOLBAR_MAIN_ICON_SIZE;
if ( !m_wndMyFloatingToolbar.Create(this,m_wndMyFloatingToolbar.GetBarStyle() |WS_EX_PALETTEWINDOW | WS_EX_TOPMOST |CBRS_FLOATING | WS_VISIBLE) ||
!m_wndMyFloatingToolbar.LoadToolBar(IDR_GENERAL_TOOLBAR, toolbarIconSize))
{
TRACE0("Failed to create My Floating Toolbar\n");
return -1; }
m_wndMyFloatingToolbar.EnableDocking(0);
EnableDocking(0);
if (!CreateCtrlBar())
{
TRACE0("Failed to create ctrl toolbar\n");
return -1; }
return 0;
}
void CMainFrame::OnViewToolBar()
{
CPoint Pos = MyFloatingToolbarGetLastPosition(); \\Get last pos
FloatControlBar( &m_wndMyFloatingToolbar, Pos, CBRS_ALIGN_LEFT );
MyFloatingToolbarSetIsVisible();
FloatControlBar( &m_wndMyFloatingToolbar, Pos, CBRS_ALIGN_LEFT );
}
void CMainFrame::MyFloatingToolbarSetIsVisible()
{
WINDOWPLACEMENT wp;
m_wndMyFloatingToolbar.GetParent()->GetParent()->GetWindowPlacement(&wp);
wp.showCmd = SW_SHOW;
m_wndMyFloatingToolbar.GetParent()->GetParent()->SetWindowPlacement(&wp);
m_wndMyFloatingToolbar.GetParent()->GetWindowPlacement(&wp);
wp.showCmd = SW_SHOW;
m_wndMyFloatingToolbar.GetParent()->SetWindowPlacement(&wp);
m_wndMyFloatingToolbar.GetWindowPlacement(&wp);
wp.showCmd = SW_SHOW;
m_wndMyFloatingToolbar.SetWindowPlacement(&wp);
}
void CWJToolBar::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
{
CToolBar::OnWindowPosChanging(lpwndpos);
if ( GetBarStyle() & CBRS_FLOATING )
{
if((lpwndpos->flags & SWP_HIDEWINDOW) && ((this->GetParentFrame())->m_hWnd !=(this->GetTopLevelFrame())->m_hWnd))
{
CMainFrame* mf = (CMainFrame*)(AfxGetApp()->GetMainWnd());
mf->MyFloatingToolbarSavePosition();
}
}
}
|
|
|
|
|
In Visual C/C++ 2008 version's main top menu, clicking on "Build" causes a dropdown menu, which includes:-
Build Solution
Rebuild Solution
Clean Solution
Build xxxx
Rebuild xxxx
Clean xxxx
Project Only
and clicking on "Project Only" causes a sub-dropdown menu with:-
Build Only xxxx
Rebuild Only xxxx
Clean Only xxxx
Link Only xxxx
where "xxxx" is the name of the current project.
What is "Solution" and what is "xxxx" and what is "Only xxxx"? Which of these 3 options recompiles the whole of the current project? Which option recompiles what?
|
|
|
|
|
Each project is part of a Solution (top folder in the tree), which may contain other projects. So you can build/rebuild/clean only a particular project, or every project in the Solution.
|
|
|
|
|
The first line of the output should use the %d place holder in the format string to print the number 42.
The second line should use the %c placeholder to print the letter J.
The third line should use the %f placeholder to print the number 3.14159 with 6 decimal digits after the
decimal (this is the default)
|
|
|
|
|
smells like homework - read your lecture notes & textbook, then post back whatever actual code you have written - we don't write code, especially homework for people - it makes them lazy and us annoyed, and your teacher/professor/whatever can smell copied/stolen works a mile off
|
|
|
|
|
|
error C2440: 'static_cast' : cannot convert from 'void (__thiscall COptionDBTransport::* )(PCTSTR)' to 'AFX_PMSG'
Throws error at this line-
ON_BN_CLICKED(IDC_BUTTON_udpCheck, &COptionDBTransport::OnBnClickedButtonudpcheck)
Please help me for this issue.
modified 31-Jan-15 3:49am.
|
|
|
|
|
Seemingly your only problem is that your method signature doesn't match.
See the AFX_PMSG[^] signature.
You method receives a PCTSTR parameter while a button event handler should be a method without any parameters.
|
|
|
|
|
Yes ,it is inherited from CCmdTarget(base class of all classes used)
M still stuck to that error
@pasztorpisti-How to pass multiple parameters to a button event handler.
|
|
|
|
|
You can not pass a parameter to a button event handler. You have to gather the data in the handler - for example by querying textboxes/checkboxes/etc in your handler method.
|
|
|
|
|
thanks pasztorpisti, will try that.
|
|
|
|
|
Does your COptionDBTransport inherit from CCmdTarget (or a derived type of it)?
Have you included (even if indirectly) <afxwin.h>? (ON_BN_CLICKED is defined in another header)
|
|
|
|
|
Thanks, Yes Have inculded the header file.
|
|
|
|
|
Then I'm totally baffled. Recommend you compile with /P (preprocess to file) and then, from a command-prompt try to compile that generated file. It should contain #line directives and such making it (hopefully) obvious why it fails.
++luck;
|
|
|
|
|
This is a code for snake game using dev c++. now i would like to know how can i create:
- a new snake (2nd snake) which eats the apple(so called apple) on its own..
- which means.. 1st snake will be handled by user. while the 2nd snake works on its own. and both snake fights to get the apple.
can any1 suggest me how can i do this.
#include <iostream>
#include <windows.h>
#include <stdlib.h>
#include <conio.h>
using namespace std;
typedef struct tailpos
{
int x;
int y;
struct tailpos *next;
struct tailpos *prev;
}
tail;
int d=4;
class snake
{
public:
int foodx,foody;
HANDLE console_handle;
COORD cur_cord;
tail *start,*current,*newtail;
snake();
void insert(int x , int y);
void draw();
void drawWall();
void move();
bool collision();
void drawfood(int x=0);
};
snake::snake()
{
start = NULL;
current = NULL;
newtail = NULL;
console_handle=GetStdHandle( STD_OUTPUT_HANDLE );
foodx=12;
foody=14;
}
void snake::drawWall()
{
cur_cord.X=0;
for(int y=0;y<=30;y++)
{.....
}
void snake::drawfood(int x)
{
tail *tmp;
tmp=start->next;
if(x==1) .....
}
void snake :: insert(int x , int y)
{
if(start == NULL)
{
newtail = new tail;
newtail->x=x;
newtail->y=y;
newtail->next=NULL;
newtail->prev=NULL;
start=newtail;
current=newtail;
}
else
{
newtail = new tail;
newtail->x=x;
newtail->y=y;
newtail->next=NULL;
newtail->prev=current;
current->next=newtail;
current=newtail;
}
}
void snake::move()
{
tail *tmp,*cur;
tmp =current;
while(tmp->prev!=NULL)
{
tmp->x=tmp->prev->x;
tmp->y=tmp->prev->y;
tmp=tmp->prev;
}
if(d==1)
start->y--;
if(d==2)
start->y++;
if(d==3)
start->x--;
if(d==4)
start->x++;
}
bool snake::collision()
{
tail *tmp;
tmp=start->next;
while(tmp->next!=NULL)
{
if(start->x == tmp->x && start->y == tmp->y)
return true;
tmp=tmp->next;
}
if(start->x == foodx && start->y == foody)
{
insert(foodx,foody);
drawfood(1);
}
for(int x=0;x<=30;x++)
{
if(start->x == x .....
}
void snake::draw()
{
tail *tmp , *last;
tmp=start;
last = current;
while(tmp!=NULL)
{
cur_cord.X=tmp->x;
cur_cord.Y=tmp->y;
SetConsoleCursorPosition(console_handle,cur_cord);
cout << "#";
tmp=tmp->next;
}
cur_cord.X=last->x;
cur_cord.Y=last->y;
SetConsoleCursorPosition(console_handle,cur_cord);
cout << ' ';
cur_cord.X.....
}
int main()
{
......
}
getch();
return 0;
}
|
|
|
|
|
Hello,
I'm trying to adapt some Microsoft code (member.cpp in Detours) for my case
( I just want to replace
void CMember::Target(void)
by
QString QString::fromAscii(const char *str, int size):
MS Code :
class CMember
{
public:
void Target(void);
};
void CMember::Target(void)
{
printf(" CMember::Target! (this:%p)\n", this);
}
class CDetour
{
public:
void Mine_Target(void);
static void (CDetour::* Real_Target)(void);
};
void CDetour::Mine_Target(void)
{
printf(" CDetour::Mine_Target! (this:%p)\n", this);
(this->*Real_Target)();
}
void (CDetour::* CDetour::Real_Target)(void) = (void (CDetour::*)(void))&CMember::Target;
My code :
class CDetour
{
public:
QString Mine_Target(const char *str, int size);
static QString (CDetour::* Real_Target)(const char *str, int size);
};
QString CDetour::Mine_Target(const char *str, int size)
{
printf(" CDetour::Mine_Target! (this:%p)\n", this);
(this->*Real_Target)(str, size);
}
QString (CDetour::* CDetour::Real_Target)(const char *str, int size) = (CDetour::*)(const char *str, int size)&QString::fromAscii;
But I get :
error C2059: syntax error: '< tag >::*'
for the last line
Why ?!
Thanks.
Edit :
If I do :
QString (CDetour::* CDetour::Real_Target)(const char *str, int size) = (QString(CDetour::*)(const char *str, int size))&QString::fromAscii;
I get :
error C2440: 'type cast' : impossible to convert from 'QString (__cdecl *)(const char *,int)' into 'QString (__thiscall CDetour::* )(const char *,int)'
modified 29-Jan-15 7:21am.
|
|
|
|
|