[ Home | Syllabus |Course Notes]
Problem: How to keep state of client/server connection between RPC calls?
WIN32 RPC use the later approach.
[
uuid(c262dfb0-54af-11d1-a98f-00609752bfb9), // Used uuidgen -i to generate this number
version(1.0),
endpoint ("ncacn_ip_tcp:[44533]")
]
interface audioRPC // Provides a set of RPC calls
{
typedef [context_handle] void *audioContext; // This is a 32 bit pointer to the client state in the server
void openRecord([in , string] char*, [out, ref] audioContext * ac);
void saveAudio([in] audioContext ac, [in] int size, [in, size_is(size)] char* buf);
void closeRecord([in, out,ref] audioContext *ac);
void openPlayBack([in, string] char*, [out, ref] audioContext * ac);
void closePlayBack([in, out,ref] audioContext *ac);
int getAudio([in] audioContext ac, [in] int size, [out, size_is(size)] char buf[]);
}
F1: A reference pointer has the following characteristics: · Always points to valid storage; never has the value NULL. A reference pointer can always be dereferenced. · Never changes during a call. A reference pointer always points to the same storage on the client before and after the call. · Does not allocate new memory on the client. Data returned from the server is written into existing storage specified by the value of the reference pointer before the call. · Does not cause aliasing. Storage pointed to by a reference pointer cannot be reached from any other name in the function. A reference pointer cannot be used as the type of a pointer returned by a function.
F2: Determines length using normal string length function
F3: Pointer is passed back after opening Audio file
#include <windows.h>
#include "audMsg.h" // generated by the IDL file - contains the stubs
typedef struct
{
HANDLE audioFile;
} audioContextStruct;
// function to initialize sum context
void openRecord(unsigned char* fileName, audioContext *contextHandle)
{
audioContextStruct *tmp;
tmp=(audioContextStruct *) midl_user_allocate(sizeof(audioContextStruct));
tmp->audioFile = CreateFile((const char*)fileName, GENERIC_WRITE,
0,0, CREATE_ALWAYS, 0, 0);
*contextHandle=(audioContext)tmp;
}
void openPlayBack(unsigned char* fileName, audioContext *contextHandle)
{
audioContextStruct *tmp;
tmp=(audioContextStruct *)
midl_user_allocate(sizeof(audioContextStruct));
tmp->audioFile = CreateFile((const char*)fileName, GENERIC_READ,
0,0, OPEN_EXISTING, 0, 0);
*contextHandle=(audioContext)tmp;
}
void saveAudio(audioContext contextHandle, int size, unsigned char* buf)
{
DWORD numWrite;
WriteFile(((audioContextStruct *) contextHandle)->audioFile, buf, size, &numWrite, 0);
}
int getAudio(audioContext contextHandle,
int size, unsigned char* buf)
{
DWORD numWrite;
ReadFile(((audioContextStruct *) contextHandle)->audioFile, buf, size, &numWrite, 0);
return numWrite;
}
// function to uninitialize sum context
void closeRecord(audioContext *contextHandle)
{
CloseHandle(((audioContextStruct *) *contextHandle)->audioFile);
midl_user_free(*contextHandle);
*contextHandle=NULL;
}
void closePlayBack(audioContext *contextHandle)
{
CloseHandle(((audioContextStruct *) *contextHandle)->audioFile);
midl_user_free(*contextHandle);
*contextHandle=NULL;
}
// function which gets called if client
// looses contact with server
void __RPC_USER audioContext_rundown
(audioContext contextHandle)
{
midl_user_free(*contextHandle);
}
if (RpcServerUseAllProtseqsIf(1,
audioRPC_v1_0_s_ifspec,
NULL))
if (RpcServerRegisterIf(audioRPC_v1_0_s_ifspec,
NULL, NULL))
if (RpcServerListen(1, 5, FALSE))
// Main Window is a dialog box
class CMsgApp : public CWinApp
{
public:
virtual BOOL InitInstance(); // everybody overrides this one
};
CMsgApp msgApp;
// Init the application and the main window
BOOL CMsgApp::InitInstance()
{
CMsgDlg dlg;
m_pMainWnd = &dlg;
dlg.DoModal();
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
class CMsgDlg : public CDialog
{
public:
CMsgDlg(CWnd* pParentWnd = NULL) :
CDialog(IDD_MSGDLG, pParentWnd) {}
virtual BOOL OnInitDialog();
private:
HANDLE audioThread;
protected:
afx_msg void OnRecord();
afx_msg void OnPlay();
afx_msg void OnStop();
DECLARE_MESSAGE_MAP()
};
BOOL CMsgDlg::OnInitDialog()
{
UCHAR *stringBinding;
CDialog::OnInitDialog();
RpcStringBindingCompose(NULL,
(UCHAR *) "ncacn_ip_tcp", (UCHAR *) "localhost",
(UCHAR *) "44533", NULL,
&stringBinding);
RpcBindingFromStringBinding(stringBinding,
&audioRPCHandle);
RpcStringFree(&stringBinding);
stopRecord = CreateEvent(0, FALSE, FALSE, 0); // so that Record/Stop buttons can control recording
ResetEvent(stopRecord);
return TRUE;
}
void CMsgDlg::OnRecord()
// Saves the message
{
DWORD threadid;
void record(void*);
CString msgName;
char* msgName2;
GetDlgItem(IDC_STOP)->EnableWindow(true);
GetDlgItem(IDC_RECORD)->EnableWindow(false);
GetDlgItem(IDC_PLAY)->EnableWindow(false);
GetDlgItemText(IDC_MSG_ID, msgName);
msgName2 = new char[sizeof(msgName)]+1;
strcpy(msgName2, msgName);
audioThread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) record, msgName2, 0,
&threadid);
}
void CMsgDlg::OnStop()
{
GetDlgItem(IDC_STOP)->EnableWindow(false);
GetDlgItem(IDC_RECORD)->EnableWindow(true);
GetDlgItem(IDC_PLAY)->EnableWindow(true);
SetEvent(stopRecord);
GetDlgItem(IDC_STOP)->EnableWindow(FALSE);
}
void CMsgDlg::OnPlay()
// Saves the message
{
DWORD threadid;
void playBack(void*);
int i = 0;
CString msgName;
char* msgName2;
GetDlgItem(IDC_STOP)->EnableWindow(true);
GetDlgItem(IDC_RECORD)->EnableWindow(false);
GetDlgItem(IDC_PLAY)->EnableWindow(false);
GetDlgItemText(IDC_MSG_ID, msgName);
msgName2 = new char[sizeof(msgName)]+1;
strcpy(msgName2, msgName);
audioThread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) playBack, msgName2, 0,
&threadid);
}
void record(void * msgName) // this is a thread function which is passed a pointer to a string
{
DWORD threadid;
HANDLE recordHandle;
openRecord((unsigned char*)msgName,&ac);
msgApp.m_pMainWnd->SetWindowText("Start Recording");
calledBack = CreateEvent(0, FALSE, FALSE, 0);
ResetEvent(calledBack);
recordHandle = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) Recorder, NULL, 0,
&threadid);
openWaveInDev();
WaitForSingleObject(recordHandle, INFINITE);
waveInClose(hWaveIn);
CloseHandle(calledBack);
CloseHandle(recordHandle);
closeRecord(&ac);
msgApp.m_pMainWnd->SetWindowText("Done Recording");
}
UINT Recorder(void *p)
{
while (true)
{
WaitForSingleObject(calledBack, INFINITE); // wait till device has called back
if (!(WaveHeader.dwFlags & WHDR_DONE))
{
continue;
}
saveAudio(ac, WaveHeader.dwBytesRecorded, (unsigned char*) WaveHeader.lpData);
if (waveInUnprepareHeader(hWaveIn, &WaveHeader,
sizeof(WAVEHDR)))
{
break;
}
WaveHeader.dwFlags = 0;
if (waveInPrepareHeader(hWaveIn, &WaveHeader,
sizeof(WAVEHDR)))
{
break;
}
if (waveInAddBuffer(hWaveIn, &WaveHeader,
sizeof(WAVEHDR)))
{
break;
}
if(WaitForSingleObject(stopRecord, 0) != WAIT_TIMEOUT)
break;
}
waveInReset(hWaveIn);
return 0;
}