Problem Showing Enumerated Sound Devices in ComboBox [modified]
-
Hi, I'm trying to work through the example code in the MSDN DirectSound Programming Guide to enumerate sound devices. When I run my app, the ComboBox which should list the available sound devices is for some reason empty. Below is the Callback Procedure I've used for the Direct Sound device enumeration.
BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCSTR lpszDescription, LPCSTR lpszDriverName, LPVOID lpContext)
{
HWND hCombo = (HWND)lpContext;
LPGUID lpTemp = NULL;if(lpGUID != NULL) { if((lpTemp = (LPGUID)malloc(sizeof(GUID))) == NULL) return TRUE; memcpy(lpTemp, lpGUID, sizeof(GUID)); } ComboBox\_AddString(hCombo, lpszDescription); ComboBox\_SetItemData(hCombo, ComboBox\_FindString(hCombo, 0, lpszDescription), lpTemp); free(lpTemp); return TRUE;
}
FYI Inspecting
lpGUID
during debugging reveals that the first time theif(lpGUID != NULL)
is reached, it's value is 0 so the statement evaluates to FALSE, and lpszDescription points to the 'P' of "Primary Sound Driver". The call toComboBox_AddString
processes ok without returning CB_ERR or CB_ERRSPACE. The process repeats for the other available devices, but once it's finished the ComboBox remains empty!?:confused: Below is my Callback procedure for the dialog containing the ComboBox. I've added a static text to display the total number of entries as a check, but this shows "Num Entries: 0" when I run the app. What am I missing here?BOOL CALLBACK DLG_AudioDeviceSelectionProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
HWND hCombo, hEntryCountText;
int iCount;
TCHAR szBuffer[32];switch(message) { case WM\_INITDIALOG: hCombo = GetDlgItem(hDlg, IDC\_COMBO); if(DirectSoundEnumerate((LPDSENUMCALLBACK)DSEnumProc,(VOID\*)&hCombo) != DS\_OK) { EndDialog(hDlg, TRUE); return TRUE; } iCount = ComboBox\_GetCount(hCombo); hEntryCountText = GetDlgItem(hDlg, IDC\_ENTRY\_COUNT); wsprintf(szBuffer, TEXT("Num Entries: %i"), iCount); SetWindowText(hEntryCountText, szBuffer); case WM\_COMMAND: switch(LOWORD(wParam)) { case IDCANCEL: case IDOK: EndDialog(hDlg, 0); return TRUE; } break; } return FALSE;
}
I'm using MS VC++ 2010. I've worked through Petzold but I'm still essentially a Win API noob.
modified on Monday, April 11, 2011 12:57 AM
-
Hi, I'm trying to work through the example code in the MSDN DirectSound Programming Guide to enumerate sound devices. When I run my app, the ComboBox which should list the available sound devices is for some reason empty. Below is the Callback Procedure I've used for the Direct Sound device enumeration.
BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCSTR lpszDescription, LPCSTR lpszDriverName, LPVOID lpContext)
{
HWND hCombo = (HWND)lpContext;
LPGUID lpTemp = NULL;if(lpGUID != NULL) { if((lpTemp = (LPGUID)malloc(sizeof(GUID))) == NULL) return TRUE; memcpy(lpTemp, lpGUID, sizeof(GUID)); } ComboBox\_AddString(hCombo, lpszDescription); ComboBox\_SetItemData(hCombo, ComboBox\_FindString(hCombo, 0, lpszDescription), lpTemp); free(lpTemp); return TRUE;
}
FYI Inspecting
lpGUID
during debugging reveals that the first time theif(lpGUID != NULL)
is reached, it's value is 0 so the statement evaluates to FALSE, and lpszDescription points to the 'P' of "Primary Sound Driver". The call toComboBox_AddString
processes ok without returning CB_ERR or CB_ERRSPACE. The process repeats for the other available devices, but once it's finished the ComboBox remains empty!?:confused: Below is my Callback procedure for the dialog containing the ComboBox. I've added a static text to display the total number of entries as a check, but this shows "Num Entries: 0" when I run the app. What am I missing here?BOOL CALLBACK DLG_AudioDeviceSelectionProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
HWND hCombo, hEntryCountText;
int iCount;
TCHAR szBuffer[32];switch(message) { case WM\_INITDIALOG: hCombo = GetDlgItem(hDlg, IDC\_COMBO); if(DirectSoundEnumerate((LPDSENUMCALLBACK)DSEnumProc,(VOID\*)&hCombo) != DS\_OK) { EndDialog(hDlg, TRUE); return TRUE; } iCount = ComboBox\_GetCount(hCombo); hEntryCountText = GetDlgItem(hDlg, IDC\_ENTRY\_COUNT); wsprintf(szBuffer, TEXT("Num Entries: %i"), iCount); SetWindowText(hEntryCountText, szBuffer); case WM\_COMMAND: switch(LOWORD(wParam)) { case IDCANCEL: case IDOK: EndDialog(hDlg, 0); return TRUE; } break; } return FALSE;
}
I'm using MS VC++ 2010. I've worked through Petzold but I'm still essentially a Win API noob.
modified on Monday, April 11, 2011 12:57 AM
First of all, there is no
break;
after thecase WM_INITDIALOG:
block. If this doesn't fix the problem, then get count of the combo box after eachAddString()
- put a breakpoint on it to make sure it's incremented. If you still have problem, post here your code where you callAddString()
.Best wishes, Hans
-
First of all, there is no
break;
after thecase WM_INITDIALOG:
block. If this doesn't fix the problem, then get count of the combo box after eachAddString()
- put a breakpoint on it to make sure it's incremented. If you still have problem, post here your code where you callAddString()
.Best wishes, Hans
Thank you for your response Hans. I added the
break;
after the caseWM_INITDIALOG:
block. Thank you, this was an oversight. Unfortunately it has not fixed the problem. I've now added astatic int
callediCount
to the callback procedure where I callComboBox_AddString()
. I've usedComboBox_GetCount()
to updateiCount
. I've also added some error handling to theComboBox_AddString()
call. When I put in a breakpoint here and debug, I see thatiCount
remains at 0 each time the code passes through. Below is my revised code.BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCSTR lpszDescription, LPCSTR lpszDriverName, LPVOID lpContext)
{
HWND hCombo = (HWND)lpContext;
LPGUID lpTemp = NULL;
static int iCount;
if(lpGUID != NULL)
{
if((lpTemp = (LPGUID)malloc(sizeof(GUID))) == NULL)
return TRUE;
memcpy(lpTemp, lpGUID, sizeof(GUID));
}// Put data into ComboBox if(ComboBox\_AddString(hCombo, lpszDescription) == CB\_ERR | CB\_ERRSPACE) { MessageBox(hCombo, TEXT("Error Adding String To ComboBox"), TEXT("Error!"), MB\_OK); } iCount = ComboBox\_GetCount(hCombo); ComboBox\_SetItemData(hCombo, ComboBox\_FindString(hCombo, 0, lpszDescription), lpTemp); free(lpTemp); return TRUE;
}
Is it something to do with the way I'm trying to pass the ComboBox handle to the DSEnumProc procedure when I initialize the dialog? I notice that the value of hCombo in the code below is different from the value in the code above when I debug.
hCombo = GetDlgItem(hDlg, IDC\_COMBO); if(DirectSoundEnumerate((LPDSENUMCALLBACK)DSEnumProc,(VOID\*)&hCombo) != DS\_OK) { EndDialog(hDlg, TRUE); return TRUE; }
Thank you again for your help Paul
-
Thank you for your response Hans. I added the
break;
after the caseWM_INITDIALOG:
block. Thank you, this was an oversight. Unfortunately it has not fixed the problem. I've now added astatic int
callediCount
to the callback procedure where I callComboBox_AddString()
. I've usedComboBox_GetCount()
to updateiCount
. I've also added some error handling to theComboBox_AddString()
call. When I put in a breakpoint here and debug, I see thatiCount
remains at 0 each time the code passes through. Below is my revised code.BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCSTR lpszDescription, LPCSTR lpszDriverName, LPVOID lpContext)
{
HWND hCombo = (HWND)lpContext;
LPGUID lpTemp = NULL;
static int iCount;
if(lpGUID != NULL)
{
if((lpTemp = (LPGUID)malloc(sizeof(GUID))) == NULL)
return TRUE;
memcpy(lpTemp, lpGUID, sizeof(GUID));
}// Put data into ComboBox if(ComboBox\_AddString(hCombo, lpszDescription) == CB\_ERR | CB\_ERRSPACE) { MessageBox(hCombo, TEXT("Error Adding String To ComboBox"), TEXT("Error!"), MB\_OK); } iCount = ComboBox\_GetCount(hCombo); ComboBox\_SetItemData(hCombo, ComboBox\_FindString(hCombo, 0, lpszDescription), lpTemp); free(lpTemp); return TRUE;
}
Is it something to do with the way I'm trying to pass the ComboBox handle to the DSEnumProc procedure when I initialize the dialog? I notice that the value of hCombo in the code below is different from the value in the code above when I debug.
hCombo = GetDlgItem(hDlg, IDC\_COMBO); if(DirectSoundEnumerate((LPDSENUMCALLBACK)DSEnumProc,(VOID\*)&hCombo) != DS\_OK) { EndDialog(hDlg, TRUE); return TRUE; }
Thank you again for your help Paul
When you say
(VOID*)&hCombo
, what you're doing is passing the address of hCombo. But in your callback, you writeHWND hCombo = (HWND)lpContext;
So, you're doing one thing, but telling the compiler something else. Do you see what I mean? I could go further if you want.
Best wishes, Hans
-
When you say
(VOID*)&hCombo
, what you're doing is passing the address of hCombo. But in your callback, you writeHWND hCombo = (HWND)lpContext;
So, you're doing one thing, but telling the compiler something else. Do you see what I mean? I could go further if you want.
Best wishes, Hans
Yes, I used
(Void*)&hCombo
andHWND hCombo = (HWND)lpContext
as this was how it was written in the MSDN explanatory code snippets. I think I understand what you mean though.lpContext
is a pointer which contains the address ofhCombo
when I pass it, so I need to dereferencelpContext
when I'm initializing the localhCombo
in the callback, right? I've triedHWND hCombo = (HWND)*lpContext;
but the IDE says "Error: expression must be a pointer to a complete object type". Is it incorrect to declare, dereference, cast and initialize all in the one statement? Thank you again. Paul -
Yes, I used
(Void*)&hCombo
andHWND hCombo = (HWND)lpContext
as this was how it was written in the MSDN explanatory code snippets. I think I understand what you mean though.lpContext
is a pointer which contains the address ofhCombo
when I pass it, so I need to dereferencelpContext
when I'm initializing the localhCombo
in the callback, right? I've triedHWND hCombo = (HWND)*lpContext;
but the IDE says "Error: expression must be a pointer to a complete object type". Is it incorrect to declare, dereference, cast and initialize all in the one statement? Thank you again. PaulActually, it would be simpler to just keep your callback code the same, and write
(Void*)hCombo
. AHWND
will fit into a pointer-size variable, which is whatlpContext
is. So keep the callback like you had it before:HWND hCombo = (HWND)lpContext;
Best wishes, Hans
-
Actually, it would be simpler to just keep your callback code the same, and write
(Void*)hCombo
. AHWND
will fit into a pointer-size variable, which is whatlpContext
is. So keep the callback like you had it before:HWND hCombo = (HWND)lpContext;
Best wishes, Hans
Thanks Hans. It works. :-D I think I took MSDN's description of
DirectSoundEnumerate
too literally. It says:HRESULT DirectSoundEnumerate(
LPDSENUMCALLBACK lpDSEnumCallback,
LPVOID lpContext
)Parameters lpDSEnumCallback Address of the DSEnumCallback function that will be called for each device installed in the system. lpContext Address of the user-defined context passed to the enumeration callback function every time that function is called. So I assumed lpContext had to be a pointer, but since it's just being passed straight on to the callback function anyway, I guess it doesn't have to be. Your help is greatly appreciated.:thumbsup: Best regards Paul
-
Thanks Hans. It works. :-D I think I took MSDN's description of
DirectSoundEnumerate
too literally. It says:HRESULT DirectSoundEnumerate(
LPDSENUMCALLBACK lpDSEnumCallback,
LPVOID lpContext
)Parameters lpDSEnumCallback Address of the DSEnumCallback function that will be called for each device installed in the system. lpContext Address of the user-defined context passed to the enumeration callback function every time that function is called. So I assumed lpContext had to be a pointer, but since it's just being passed straight on to the callback function anyway, I guess it doesn't have to be. Your help is greatly appreciated.:thumbsup: Best regards Paul
Good ol' MSDN. God's gift to consultants. :laugh: BTW, Petzold was how I learned Win32 too. If you get tired of dealing with all that wndproc stuff, check out MFC; it's a very thin wrapper over Win32, and makes a lot of things easier. Good luck. :thumbsup:
Best wishes, Hans