[ 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; }