|
TNx for the jnfo
|
|
|
|
|
Hi I've got this code and I am trying to implement a thread with it.
Could someone tell me what are the sizes of the input and output buffer and their durations ? Are these parameters fixed or can be manipulated ?
What other parameters are being used in this code which can be manipulated ?
What is the rate at which samples are being played from output.
Code :
HRESULT __fastcall TDSFilter::InitDirectSound()
{
HRESULT hr;
DSBUFFERDESC dsbdesc;
// ZeroMemory( &aPosNotify, sizeof(DSBPOSITIONNOTIFY) * FNumBuffers);
dwOutputBufferSize = 0;
dwCaptureBufferSize = 0;
dwNotifySize = 0;
dwNextOutputOffset = 0;
// Initialize COM
if( FAILED( hr = CoInitialize(NULL) ) ) return DXTRACE_ERR_MSGBOX( TEXT("CoInitialize"), hr );
// Create IDirectSound using the preferred sound device
if( FAILED( hr = DirectSoundCreate8( NULL, &pDS, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("DirectSoundCreate"), hr );
// Set coop level to DSSCL_PRIORITY
if( FAILED( hr = pDS->SetCooperativeLevel( hWnd, DSSCL_PRIORITY ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("SetCooperativeLevel"), hr );
// Obtain primary buffer
ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
if( FAILED( hr = pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("CreateSoundBuffer"), hr );
// Create IDirectSoundCapture using the preferred capture device
if( FAILED( hr = DirectSoundCaptureCreate8( NULL, &pDSCapture, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("DirectSoundCaptureCreate"), hr );
return S_OK;
}
HRESULT __fastcall TDSFilter::FreeDirectSound()
{
// Release DirectSound interfaces
SAFE_RELEASE( pDSNotify );
SAFE_RELEASE( pDSBPrimary );
SAFE_RELEASE( pDSBOutput );
SAFE_RELEASE( pDSBCapture );
SAFE_RELEASE( pDSCapture );
SAFE_RELEASE( pDS );
// Release COM
CoUninitialize();
return S_OK;
}
HRESULT __fastcall TDSFilter::ScanAvailableOutputFormats()
{
WAVEFORMATEX wfx;
WAVEFORMATEX wfxSet;
HRESULT hr;
ZeroMemory( &wfxSet, sizeof(wfxSet) );
wfxSet.wFormatTag = WAVE_FORMAT_PCM;
ZeroMemory( &wfx, sizeof(wfx) );
wfx.wFormatTag = WAVE_FORMAT_PCM;
// Try 20 different standard format to see if they are supported
for( INT iIndex = 0; iIndex < 20; iIndex++ )
{
GetWaveFormatFromIndex( iIndex, &wfx );
// To test if a playback format is supported, try to set the format
// using a specific format. If it works then the format is
// supported, otherwise not.
if( FAILED( hr = pDSBPrimary->SetFormat( &wfx ) ) )
{
abOutputFormatSupported[ iIndex ] = FALSE;
}
else
{
// Get the format that was just set, and see if it
// is actually supported since SetFormat() sometimes returns DS_OK
// even if the format was not supported
if( FAILED( hr = pDSBPrimary->GetFormat( &wfxSet, sizeof(wfxSet),
NULL ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("GetFormat"), hr );
if( memcmp( &wfx, &wfxSet, sizeof(wfx) ) == 0 )
abOutputFormatSupported[ iIndex ] = TRUE;
else
abOutputFormatSupported[ iIndex ] = FALSE;
}
}
return S_OK;
}
void __fastcall TDSFilter::GetWaveFormatFromIndex( INT nIndex, WAVEFORMATEX* pwfx )
{
INT iSampleRate = nIndex % 5;
INT iType = nIndex / 5;
switch( iSampleRate )
{
case 0: pwfx->nSamplesPerSec = 48000; break;
case 1: pwfx->nSamplesPerSec = 44100; break;
case 2: pwfx->nSamplesPerSec = 22050; break;
case 3: pwfx->nSamplesPerSec = 11025; break;
case 4: pwfx->nSamplesPerSec = 8000; break;
}
switch( iType )
{
case 0: pwfx->wBitsPerSample = 16; pwfx->nChannels = 2; break;
case 1: pwfx->wBitsPerSample = 16; pwfx->nChannels = 1; break;
case 2: pwfx->wBitsPerSample = 8; pwfx->nChannels = 2; break;
case 3: pwfx->wBitsPerSample = 8; pwfx->nChannels = 1; break;
}
pwfx->nBlockAlign = pwfx->nChannels * ( pwfx->wBitsPerSample / 8 );
pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
}
void __fastcall TDSFilter::ConvertWaveFormatToString( WAVEFORMATEX* pwfx, TCHAR* strFormatName)
{
wsprintf( strFormatName,
TEXT("%u Hz, %u-bit %s"),
pwfx->nSamplesPerSec,
pwfx->wBitsPerSample,
( pwfx->nChannels == 1 ) ? TEXT("Mono") : TEXT("Stereo") );
}
HRESULT __fastcall TDSFilter::ScanAvailableInputFormats()
{
WAVEFORMATEX wfx;
DSCBUFFERDESC dscbd;
LPDIRECTSOUNDCAPTUREBUFFER pDSCaptureBuffer = NULL;
ZeroMemory( &wfx, sizeof(wfx) );
wfx.wFormatTag = WAVE_FORMAT_PCM;
ZeroMemory( &dscbd, sizeof(dscbd) );
dscbd.dwSize = sizeof(dscbd);
// Try 20 different standard format to see if they are supported
for( INT iIndex = 0; iIndex < 20; iIndex++ )
{
GetWaveFormatFromIndex( iIndex, &wfx );
// To test if a capture format is supported, try to create a
// new capture buffer using a specific format. If it works
// then the format is supported, otherwise not.
dscbd.dwBufferBytes = wfx.nAvgBytesPerSec;
dscbd.lpwfxFormat = &wfx;
if( FAILED( pDSCapture->CreateCaptureBuffer( &dscbd, &pDSCaptureBuffer, NULL ) ) ) abInputFormatSupported[ iIndex ] = FALSE;
else abInputFormatSupported[ iIndex ] = TRUE;
SAFE_RELEASE( pDSCaptureBuffer );
}
return S_OK;
}
HRESULT __fastcall TDSFilter::SetBufferFormats( WAVEFORMATEX* pwfxInput, WAVEFORMATEX* pwfxOutput )
{
HRESULT hr ;
// Set the format of the primary buffer
// to the format of the output buffer
if( FAILED( hr = pDSBPrimary->SetFormat( pwfxOutput ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("SetFormat"), hr );
// Set the notification size
dwNotifySize = FBufferSize ;
dwNotifySize -= dwNotifySize % pwfxInput->nBlockAlign;
// Set the buffer sizes
dwOutputBufferSize = FNumBuffers * dwNotifySize / 2;
dwCaptureBufferSize = dwNotifySize * FNumBuffers ;
SAFE_RELEASE( pDSBCapture );
// Create the capture buffer
DSCBUFFERDESC dscbd;
ZeroMemory( &dscbd, sizeof(dscbd) );
dscbd.dwSize = sizeof(dscbd);
dscbd.dwBufferBytes = dwCaptureBufferSize;
dscbd.lpwfxFormat = pwfxInput; // Set the format during creatation
if( FAILED( hr = pDSCapture->CreateCaptureBuffer( &dscbd, &pDSBCapture, NULL))) return DXTRACE_ERR_MSGBOX( TEXT("CreateCaptureBuffer"), hr );
return S_OK;
}
HRESULT __fastcall TDSFilter::CreateOutputBuffer()
{
HRESULT hr;
WAVEFORMATEX wfxInput;
// This sample works by creating notification events which
// are signaled when the capture buffer reachs specific offsets
// WinMain() waits for the associated event to be signaled, and
// when it is, it calls HandleNotifications() which copy the
// data from the capture buffer into the output buffer
ZeroMemory( &wfxInput, sizeof(wfxInput) );
pDSBCapture->GetFormat( &wfxInput, sizeof(wfxInput), NULL );
// Create the direct sound buffer using the same format as the
// capture buffer.
DSBUFFERDESC dsbd;
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_GLOBALFOCUS;
dsbd.dwBufferBytes = dwOutputBufferSize;
dsbd.guid3DAlgorithm = GUID_NULL;
dsbd.lpwfxFormat = &wfxInput;
// Create the DirectSound buffer
if( FAILED( hr = pDS->CreateSoundBuffer( &dsbd, &pDSBOutput, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("CreateSoundBuffer"), hr );
// Create a notification event, for when the sound stops playing
if( FAILED( hr = pDSBCapture->QueryInterface( IID_IDirectSoundNotify, (VOID**)&pDSNotify ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("QueryInterface"), hr );
// Setup the notification positions
for( unsigned int i = 0; i < FNumBuffers ; i++ ) {
aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
aPosNotify[i].hEventNotify = hNotificationEvent;
}
// Tell DirectSound when to notify us. the notification will come in the from
// of signaled events that are handled in WinMain()
if( FAILED( hr = pDSNotify->SetNotificationPositions( FNumBuffers, aPosNotify ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("SetNotificationPositions"), hr );
return S_OK;
}
HRESULT __fastcall TDSFilter::StartBuffers()
{
WAVEFORMATEX wfxOutput;
VOID* pDSLockedBuffer = NULL;
DWORD dwDSLockedBufferSize;
HRESULT hr;
// Restore lost buffers
if( FAILED( hr = RestoreBuffer( pDSBOutput, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("RestoreBuffer"), hr );
// Reset the buffers
dwNextOutputOffset = 0;
pDSBOutput->SetCurrentPosition( 0 );
// Find out where the capture buffer is right now, then write data
// some extra amount forward to make sure we're ahead of the write cursor
pDSBCapture->GetCurrentPosition( &dwNextCaptureOffset, NULL );
dwNextCaptureOffset -= dwNextCaptureOffset % dwNotifySize;
dwNextOutputOffset = dwNextCaptureOffset + ( dwNotifySize << 1);
dwNextOutputOffset %= dwOutputBufferSize; // Circular buffer
// Tell the capture buffer to start recording
pDSBCapture->Start( DSCBSTART_LOOPING );
// Rewind the output buffer, fill it with silence, and play it
pDSBOutput->SetCurrentPosition( dwNextOutputOffset );
// Save the format of the capture buffer in g_pCaptureWaveFormat
ZeroMemory( &wfxCaptureWaveFormat, sizeof(WAVEFORMATEX) );
pDSBCapture->GetFormat( &wfxCaptureWaveFormat, sizeof(WAVEFORMATEX), NULL );
// Get the format of the output buffer
ZeroMemory( &wfxOutput, sizeof(wfxOutput) );
pDSBOutput->GetFormat( &wfxOutput, sizeof(wfxOutput), NULL );
// Fill the output buffer with silence at first
// As capture data arrives, HandleNotifications() will fill
// the output buffer with wave data.
if( FAILED( hr = pDSBOutput->Lock( 0, dwOutputBufferSize, &pDSLockedBuffer, &dwDSLockedBufferSize, NULL, NULL, 0)))
return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );
FillMemory( (BYTE*) pDSLockedBuffer, dwDSLockedBufferSize,
(BYTE)( wfxOutput.wBitsPerSample == 8 ? 128 : 0 ) );
pDSBOutput->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, NULL );
// Play the output buffer
pDSBOutput->Play( 0, 0, DSBPLAY_LOOPING );
return S_OK;
}
HRESULT __fastcall TDSFilter::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSBuffer, BOOL* pbRestored )
{
HRESULT hr;
if( pbRestored) *pbRestored = FALSE;
if( !pDSBuffer ) return S_FALSE;
DWORD dwStatus;
if( FAILED( hr = pDSBuffer->GetStatus( &dwStatus ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("GetStatus"), hr );
if( dwStatus & DSBSTATUS_BUFFERLOST ) {
// Since the app could have just been activated, then
// DirectSound may not be giving us control yet, so
// the restoring the buffer may fail.
// If it does, sleep until DirectSound gives us control.
do {
hr = pDSBuffer->Restore();
if( hr == DSERR_BUFFERLOST )
Sleep( 10 );
} while( ( hr = pDSBuffer->Restore() ) == DSERR_BUFFERLOST );
if( pbRestored) *pbRestored = TRUE;
return S_OK;
} else return S_FALSE;
}
HRESULT __fastcall TDSFilter::HandleNotification()
{
HRESULT hr;
VOID* pDSCaptureLockedBuffer = NULL;
VOID* pDSOutputLockedBuffer = NULL;
DWORD dwDSCaptureLockedBufferSize;
DWORD dwDSOutputLockedBufferSize;
DWORD dwStatus;
// Make sure buffers were not lost, if the were we need
// to start the capture again
if( FAILED( hr = pDSBOutput->GetStatus( &dwStatus))) return DXTRACE_ERR_MSGBOX( TEXT("GetStatus"), hr );
if( dwStatus & DSBSTATUS_BUFFERLOST ) {
if( FAILED( hr = StartBuffers())) return DXTRACE_ERR_MSGBOX( TEXT("StartBuffers"), hr );
return S_OK;
}
// Lock the capture buffer down
if( FAILED( hr = pDSBCapture->Lock( dwNextCaptureOffset, dwNotifySize, &pDSCaptureLockedBuffer,
&dwDSCaptureLockedBufferSize, NULL, NULL, 0L)))
return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );
// Lock the output buffer down
if( FAILED( hr = pDSBOutput->Lock( dwNextOutputOffset, dwNotifySize, &pDSOutputLockedBuffer,
&dwDSOutputLockedBufferSize, NULL, NULL, 0L)))
return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );
// These should be equal
if( dwDSOutputLockedBufferSize != dwDSCaptureLockedBufferSize ) return E_FAIL; // Sanity check unhandled case
// Just copy the memory from the
// capture buffer to the playback buffer
Process( (short*) pDSCaptureLockedBuffer, dwDSOutputLockedBufferSize) ;
CopyMemory( pDSOutputLockedBuffer, pDSCaptureLockedBuffer, dwDSOutputLockedBufferSize );
// Unlock the play buffer
pDSBOutput->Unlock( pDSOutputLockedBuffer, dwDSOutputLockedBufferSize, NULL, 0 );
// Unlock the capture buffer
pDSBCapture->Unlock( pDSCaptureLockedBuffer, dwDSCaptureLockedBufferSize, NULL, 0 );
// Move the capture offset along
dwNextCaptureOffset += dwDSCaptureLockedBufferSize;
dwNextCaptureOffset %= dwCaptureBufferSize; // Circular buffer
// Move the playback offset along
dwNextOutputOffset += dwDSOutputLockedBufferSize;
dwNextOutputOffset %= dwOutputBufferSize; // Circular buffer
return S_OK;
}
I would really appreciate your help.
Thanks
|
|
|
|
|
student_eng wrote: Could someone tell me what are the sizes of the input and output buffer...
Without needlessly looking though hundreds of lines of code, what buffers are you referring to?
In the future, post just the relevant code and you'll stand a better chance of receiving help.
"Let us be thankful for the fools. But for them the rest of us could not succeed." - Mark Twain
"There is no death, only a change of worlds." - Native American Proverb
|
|
|
|
|
Hi,
I have a problem while using a CToolTipCtrl in a modeless dialog. I have created the tooltip the standard way:
BOOL CMyDlg::OnInitDialog()
{
m_pTip = new CToolTipCtrl();
m_pTip->Create(this, TTS_ALWAYSTIP);
m_pTip->SetMaxTipWidth(250);
m_pTip->AddTool(GetDlgItem(IDC_SOMETHING), "Something");
m_pTip->Activate(TRUE);
}
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg)
{
if(m_pTip != NULL)
m_pTip->RelayEvent(&msg);
}
If I create the dialog modeless the tooltip isn't shown. If I create the dialog modal it works fine!
Can someone help me please?
mADmAX0001
|
|
|
|
|
madmax0001 wrote: Can someone help me please?
Does this help?
"Let us be thankful for the fools. But for them the rest of us could not succeed." - Mark Twain
"There is no death, only a change of worlds." - Native American Proverb
|
|
|
|
|
Hi,
thank you for your reply. Unfortunatelly it doesn't work. I think it is because the dialog resource is within a DLL.
|
|
|
|
|
Hi madmax0001,
maybe it is some helpful to you
////h File/////////////////
void SetToolTip(LPCTSTR lpszText);
CToolTipCtrl m_tooltip;
////h File/////////////////
BOOL CAnswerView::OnInitDialog()
{
m_tooltip.Create(this);
SetToolTip("Hello");
}
void CAnswerView::SetToolTip(LPCTSTR lpszText)
{
TOOLINFO ti;
ti.cbSize = sizeof(TOOLINFO);
ti.lpszText = (LPTSTR)lpszText;
ti.hinst = AfxGetInstanceHandle();
ti.hwnd = m_Button.m_hWnd;//GetDlgItem(IDC_BUTTON1)->m_hWnd;
ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
ti.uId = (UINT) m_Button.m_hWnd;//GetDlgItem(IDC_BUTTON1)->m_hWnd;
m_tooltip.SendMessage(TTM_ADDTOOL, 0, (LPARAM) &ti);
}
|
|
|
|
|
Hi,
thank you! This works ! Even if the dialog resource is within a DLL.
Thank you very much !
|
|
|
|
|
Hi, me again...
I have done several tests in the meantime and unfortunatelly there is still a small problem with the tooltip.
To setup the tooltips for the modeless dialog in my dll I use this function:
//////////////////////////////////////////
void CMyDialog::SetToolTip(CWnd* pWnd, LPCTSTR lpszText)
{
if((pWnd != NULL) && (m_pTip != NULL)){
TOOLINFO ti;
ti.cbSize = sizeof(TOOLINFO);
ti.lpszText = (LPTSTR)lpszText;
ti.hinst = AfxGetInstanceHandle();
ti.hwnd = pWnd->m_hWnd;
ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
ti.uId = (UINT)pWnd->m_hWnd;
m_pTip->SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti);
}
}
//////////////////////////////////////////
This works without (!) any call to CMyDialog::PreTranslateMessage(MSG* pMsg). But I need this call, because there is an MFC bug with tooltips for disabled controls and I used in my modal dialogs this code:
//////////////////////////////////////////
BOOL CMyDialog::PreTranslateMessage(MSG* pMsg)
{
TRACE("PreTranslateMessage\n");
if(m_pTip != NULL){
// The following code is a workaround for a MFC tooltip bug which
// prevents the popup of a tooltip for a disabled control in a modal dialog.
// Transate the message based on TTM_WINDOWFROMPOINT
MSG msg = *pMsg;
msg.hwnd = (HWND)m_pTip->SendMessage(TTM_WINDOWFROMPOINT, 0, (LPARAM)&msg.pt);
CPoint pt = pMsg->pt;
if((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
::ScreenToClient(msg.hwnd, &pt);
msg.lParam = MAKELONG(pt.x, pt.y);
// Let the ToolTip process this message.
m_pTip->RelayEvent(&msg);
} // if
return CDialog::PreTranslateMessage(pMsg);
}
//////////////////////////////////////////
Then I tried to use the message hook which was neccessary to use accellerators in CMyDialog:
//////////////////////////////////////////
// Hook procedure for WH_GETMESSAGE hook type.
LRESULT CALLBACK GetMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
// If this is a keystrokes message, translate it in controls'
// PreTranslateMessage().
LPMSG lpMsg = (LPMSG)lParam;
if((nCode >= 0) &&
(PM_REMOVE == wParam) &&
(lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST) &&
(AfxGetApp()->PreTranslateMessage((LPMSG)lParam)) == TRUE){
// The value returned from this hookproc is ignored, and it cannot
// be used to tell Windows the message has been handled. To avoid
// further processing, convert the message to WM_NULL before
// returning.
lpMsg->message = WM_NULL;
lpMsg->lParam = 0L;
lpMsg->wParam = 0;
}
if((nCode >= 0) &&
(PM_REMOVE == wParam) &&
(lpMsg->message >= WM_MOUSEFIRST && lpMsg->message <= WM_MOUSELAST) &&
(AfxGetApp()->PreTranslateMessage((LPMSG)lParam)) == TRUE){
// Do nothing ???
}
// Passes the hook information to the next hook procedure in
// the current hook chain.
return ::CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
//////////////////////////////////////////
When I use the above code the tooltips for disabled controls work, but something with the mosemessage handling is wrong, because CCombobox Controls can't be opened.
Does anyone kwon how to solve my problem ?? I think somehow I must call RelayEvent of the tooltip.
THX
|
|
|
|
|
I had the same issue.
And now, thanks to your suggestion it works.
I switched from:
m_toolTip.AddTool(this,ttwtext.c_str(),cr,1);
To
TOOLINFO ti;
ti.cbSize = sizeof(TOOLINFO);
ti.lpszText = (LPTSTR)last_ttwtext.c_str();
ti.hinst = AfxGetInstanceHandle();
ti.hwnd = this->GetSafeHwnd();
ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
ti.uId = (UINT) this->GetSafeHwnd();
m_toolTip.SendMessage(TTM_ADDTOOL, 0, (LPARAM) &ti);
Thanks!
|
|
|
|
|
Hi, me again...
I have done several tests in the meantime and unfortunatelly there is still a small problem with the tooltip.
To setup the tooltips for the modeless dialog in my dll I use this function:
//////////////////////////////////////////
void CMyDialog::SetToolTip(CWnd* pWnd, LPCTSTR lpszText)
{
if((pWnd != NULL) && (m_pTip != NULL)){
TOOLINFO ti;
ti.cbSize = sizeof(TOOLINFO);
ti.lpszText = (LPTSTR)lpszText;
ti.hinst = AfxGetInstanceHandle();
ti.hwnd = pWnd->m_hWnd;
ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
ti.uId = (UINT)pWnd->m_hWnd;
m_pTip->SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti);
}
}
//////////////////////////////////////////
This works without (!) any call to CMyDialog::PreTranslateMessage(MSG* pMsg). But I need this call, because there is an MFC bug with tooltips for disabled controls and I used in my modal dialogs this code:
//////////////////////////////////////////
BOOL CMyDialog::PreTranslateMessage(MSG* pMsg)
{
TRACE("PreTranslateMessage\n");
if(m_pTip != NULL){
// The following code is a workaround for a MFC tooltip bug which
// prevents the popup of a tooltip for a disabled control in a modal dialog.
// Transate the message based on TTM_WINDOWFROMPOINT
MSG msg = *pMsg;
msg.hwnd = (HWND)m_pTip->SendMessage(TTM_WINDOWFROMPOINT, 0, (LPARAM)&msg.pt);
CPoint pt = pMsg->pt;
if((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
::ScreenToClient(msg.hwnd, &pt);
msg.lParam = MAKELONG(pt.x, pt.y);
// Let the ToolTip process this message.
m_pTip->RelayEvent(&msg);
} // if
return CDialog::PreTranslateMessage(pMsg);
}
//////////////////////////////////////////
Then I tried to use the message hook which was neccessary to use accellerators in CMyDialog:
//////////////////////////////////////////
// Hook procedure for WH_GETMESSAGE hook type.
LRESULT CALLBACK GetMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
// If this is a keystrokes message, translate it in controls'
// PreTranslateMessage().
LPMSG lpMsg = (LPMSG)lParam;
if((nCode >= 0) &&
(PM_REMOVE == wParam) &&
(lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST) &&
(AfxGetApp()->PreTranslateMessage((LPMSG)lParam)) == TRUE){
// The value returned from this hookproc is ignored, and it cannot
// be used to tell Windows the message has been handled. To avoid
// further processing, convert the message to WM_NULL before
// returning.
lpMsg->message = WM_NULL;
lpMsg->lParam = 0L;
lpMsg->wParam = 0;
}
if((nCode >= 0) &&
(PM_REMOVE == wParam) &&
(lpMsg->message >= WM_MOUSEFIRST && lpMsg->message <= WM_MOUSELAST) &&
(AfxGetApp()->PreTranslateMessage((LPMSG)lParam)) == TRUE){
// Do nothing ???
}
// Passes the hook information to the next hook procedure in
// the current hook chain.
return ::CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
//////////////////////////////////////////
When I use the above code the tooltips for disabled controls work, but something with the mosemessage handling is wrong, because CCombobox Controls can't be opened.
Does anyone kwon how to solve my problem ?? I think somehow I must call RelayEvent of the tooltip.
THX
|
|
|
|
|
I have a CArray of structs and I would like to sort my multiple members of the struct. Say it's a person struct and I want to sort by last name & age. Or maybe last name, first name, and age. Anyone have a clue how to do this?
Thanks
Kurt
|
|
|
|
|
Hi,
Will this Suffice , then implement the callback
// call the functions: First sort with name
qsort(qsortdata, count, sizeof(struct Person), qsort_callbackName);
// then sort the required ones age etc
qsort(qsortdata, count-noidfiles, sizeof(struct Person), qsort_callbackAge);
(IMHO)
Regards,
FarPointer
-- modified at 13:06 Friday 31st March, 2006
|
|
|
|
|
What do you mean by this in the second sort? count-noidfiles
|
|
|
|
|
Well what iam actually doing is that first i will sort with respect to the name ,then sort the sorteddata with respect to the age .
int qsort_callback(const void * first, const void * second)<br />
{<br />
struct person *p1, * p2;<br />
p1 = (struct person *)first;<br />
p2 = (struct person *)second;<br />
if( (*(p1->Name)).Compare(*(p2->Name)) >0 )<br />
{<br />
if(p1->Age > p2->Age)<br />
return 1;<br />
if(p1->Age < p2->Age)<br />
return -1; <br />
}<br />
<br />
}
// Well here i have tried to make sorting in one go as David says qsort is not stable one but the previous one is more logical clear ,like if later we need a more customization on the sort you again sort on the sorted data
Regards,
FarPointer
-- modified at 13:20 Friday 31st March, 2006
|
|
|
|
|
FarPointer wrote: ...but the previous one is more logical clear ,like if later we need a more customization on the sort you again sort on the sorted data
For reasons already mentioned, calling qsort() again on the sorted list using a different key will not work.
"Let us be thankful for the fools. But for them the rest of us could not succeed." - Mark Twain
"There is no death, only a change of worlds." - Native American Proverb
|
|
|
|
|
FarPointer wrote: Will this Suffice
No, because qsort() is not a stable sort. You would need to combine the effects of qsort_callbackName() and qsort_callbackAge() and call qsort() only once.
"Let us be thankful for the fools. But for them the rest of us could not succeed." - Mark Twain
"There is no death, only a change of worlds." - Native American Proverb
|
|
|
|
|
Wat do you mean by not a stable sort ,it should be a well tested and implemented one right(IMHO).
Regards,
FarPointer
|
|
|
|
|
Stable sorting algorithms maintain the relative order of records with equal keys. If whenever there are two records A and B with the same key and with A appearing before B in the original list, A will appear before B in the sorted list, the algorithm is said to be stable.
"Let us be thankful for the fools. But for them the rest of us could not succeed." - Mark Twain
"There is no death, only a change of worlds." - Native American Proverb
|
|
|
|
|
Well thanks for making it clear .
Regards,
FarPointer
|
|
|
|
|
|
David
Can you show me an example?
|
|
|
|
|
int bynameinage( const void * v1, const void * v2 )
{
pmyData data1 = *(pmyData *) v1;
pmyData data2 = *(pmyData *) v2;
int dt = data1->age - data2->age;
if (dt != 0)
return dt;
return _tcscmp(data1->name, data2->name);
}
...
qsort(..., bynameinage);
"Let us be thankful for the fools. But for them the rest of us could not succeed." - Mark Twain
"There is no death, only a change of worlds." - Native American Proverb
|
|
|
|
|
Neat and Clean.
Regards,
FarPointer
|
|
|
|
|
Probably a fairly common problem, but I'm having difficulty getting precisely the answer I need, so I'm asking a different way.
I have an MFC class (actually a dialog) in my app that I need to shift out to a DLL. There's a major product rearchitecture looming, so this is a short-term problem I need to solve. It doesn't have to be pretty, but it does need to be quick to implement.
Of course, to make my life difficult, the DLL will need to call a couple of class methods from back in the app. A typical example would be the dialog in the DLL has a Help button that, when pressed, launches a Help() method back in the app.
I'm thinking I make a "Callback" class, which exposes only the methods I need. The app creates one of these and sets up the "inside" objects it needs to know about, and the DLL itself only needs to know about this callback class. Is this the right approach?
At this point I'm stuck. I know I'm trying to hack a solution to a bad early design decision, but luckily this is only short term (but needs to be done).
Like I say, I've searched but so far haven't found any example code that deals with this specifically. Lots of "generic" stuff that mostly talks about C functions and "mentions" class callbacks. I could use a nudge in the right direction.
Brad.
|
|
|
|
|