Cannot play sound with win32 XAudio2 in window procedure callback - winapi

I'm preparing a birthday present for my classmate and I want to play the birthday song with XAudio2. However, I couldn't hear any sound. The code that plays sound was failed in window procedure, but succeed in main or WinMain.
The code below is from MSDN. It is called when WndProc got WM_PAINT message.
HRESULT hr = S_OK;
LPCWSTR strFileName = L".\\bgm.wav";
// Open the file
HANDLE hFile = CreateFile(
strFileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
return HRESULT_FROM_WIN32(GetLastError());
if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
return HRESULT_FROM_WIN32(GetLastError());
DWORD dwChunkSize;
DWORD dwChunkPosition;
FindChunk(hFile, fourccRIFF, dwChunkSize, dwChunkPosition);
DWORD filetype;
ReadChunkData(hFile, &filetype, sizeof(DWORD), dwChunkPosition);
if (filetype != fourccWAVE) return S_FALSE;
FindChunk(hFile, fourccFMT, dwChunkSize, dwChunkPosition);
ReadChunkData(hFile, &(wfx), dwChunkSize, dwChunkPosition);
FindChunk(hFile, fourccDATA, dwChunkSize, dwChunkPosition);
BYTE* pDataBuffer = new BYTE[dwChunkSize];
ReadChunkData(hFile, pDataBuffer, dwChunkSize, dwChunkPosition);
buf.AudioBytes = dwChunkSize;
buf.pAudioData = pDataBuffer;
buf.Flags = XAUDIO2_END_OF_STREAM;
hr = pXAudio2->CreateSourceVoice(&(pSourceVoice), (WAVEFORMATEX*)&(wfx));
if (FAILED(hr)) return hr; // My code returns here with XAUDIO_E_INVALID_CALL
if (FAILED(hr = pSourceVoice->SubmitSourceBuffer(&buf)))
return hr;
pSourceVoice->Start();
return hr;
And what's more, where can I put the code if pXAudio2->CreateSourceVoice cannot be called in callback?

According to IXAudio2::CreateSourceVoice,
It is invalid to call CreateSourceVoice from within a callback
(that is, IXAudio2EngineCallback or IXAudio2VoiceCallback). If you
call CreateSourceVoice within a callback, it returns
XAUDIO2_E_INVALID_CALL.

Related

Extracting a function in shell extension programming

I want to extract some DropHandler code into a separate function, but have no idea how to do that while working with interface pointers or C++ in general. I want to get just the first item in DragEnter using a separate function.
HRESULT drop_handler::GetFirstItem(IDataObject* p_data_obj, IShellItemArray* items, IShellItem* first_item)
{
HRESULT hr = SHCreateShellItemArrayFromDataObject(p_data_obj, IID_PPV_ARGS(&items));
if (hr != ERROR_SUCCESS)
{
return E_INVALIDARG;
}
DWORD item_count;
items->GetCount(&item_count);
if (item_count != 1)
{
items->Release();
return E_INVALIDARG;
}
hr = items->GetItemAt(0, &first_item);
if (hr != ERROR_SUCCESS)
{
items->Release();
return E_INVALIDARG;
}
return ERROR_SUCCESS;
}
HRESULT drop_handler::DragEnter(IDataObject* p_data_obj, DWORD gtf_key_state, POINTL pt, DWORD* pdw_effect)
{
IShellItemArray* items = nullptr;
IShellItem* dragged_item = nullptr;
HRESULT hr = GetFirstItem(p_data_obj, items, dragged_item);
if (hr != ERROR_SUCCESS)
{
return E_INVALIDARG;
}
//...use dragged_item
This code attempt crashes Explorer big time. I'm not sure what kind of function signature and pointers I should be using to make it work.
Edit: Fixed answer per Anders
HRESULT drop_handler::GetFirstItem(IDataObject* p_data_obj, IShellItemArray*& items, IShellItem*& first_item)
{
HRESULT hr = SHCreateShellItemArrayFromDataObject(p_data_obj, IID_PPV_ARGS(&items));
if (hr != ERROR_SUCCESS)
{
return E_INVALIDARG;
}
DWORD item_count;
hr = items->GetCount(&item_count);
if (hr != ERROR_SUCCESS || item_count != 1)
{
items->Release();
return E_INVALIDARG;
}
hr = items->GetItemAt(0, &first_item);
if (hr != ERROR_SUCCESS)
{
items->Release();
return E_INVALIDARG;
}
return ERROR_SUCCESS;
}
HRESULT drop_handler::DragEnter(IDataObject* p_data_obj, DWORD gtf_key_state, POINTL pt, DWORD* pdw_effect)
{
IShellItemArray* items;
IShellItem* dragged_item;
HRESULT hr = GetFirstItem(p_data_obj, items, dragged_item);
if (hr != ERROR_SUCCESS)
{
return E_INVALIDARG;
}
//...use dragged_item
Your handling of IShellItemArray* and IShellItem* is wrong. GetFirstItem will free IShellItemArray* on failure but on success you will leak it and first_item will never be returned correctly. items and first_item in DragEnter will never be valid.
IShellItemArray* should probably be a local variable in GetFirstItem.
The IShellItem* first_item parameter needs to be IShellItem** first_item or IShellItem*& first_item so that the pointer value is returned correctly to the caller.
You never check the return value of GetCount.
Since you are having problems with pointers you might want to add some asserts to verify that your interface pointers are non-null before using them.

How to get the supported 802.11 operation modes for a WLAN adapter in user mode?

I'm working on a packet capture software on Windows which supports to capture raw 802.11 packets on monitor mode. One thing I need to do is to get the supported 802.11 operation modes for a WLAN adapter.
I know how to do this in a kernel mode: just query the OID OID_DOT11_OPERATION_MODE_CAPABILITY in a kernel driver.
However, I also want to know how to do this in user mode (a DLL). I already know that Microsoft has provided the Native Wifi API. I can use the functions like WlanQueryInterface, WlanSetInterface to get/set the current operation mode (the code below shows it). But it doesn't provide a function to get the operation modes supported by the adapter.
Is there any way to solve this without relying on the kernel code? Thanks!
DWORD SetInterface(WLAN_INTF_OPCODE opcode, PVOID pData, GUID* InterfaceGuid)
{
TRACE_ENTER();
DWORD dwResult = 0;
HANDLE hClient = NULL;
DWORD dwCurVersion = 0;
if (!initWlanFunctions())
{
TRACE_PRINT("SetInterface failed, initWlanFunctions error");
TRACE_EXIT();
return ERROR_INVALID_FUNCTION;
}
// Open Handle for the set operation
dwResult = My_WlanOpenHandle(WLAN_CLIENT_VERSION_VISTA, NULL, &dwCurVersion, &hClient);
if (dwResult != ERROR_SUCCESS)
{
TRACE_PRINT1("SetInterface failed, My_WlanOpenHandle error, errCode = %x", dwResult);
TRACE_EXIT();
return dwResult;
}
dwResult = My_WlanSetInterface(hClient, InterfaceGuid, opcode, sizeof(ULONG), pData, NULL);
if (dwResult != ERROR_SUCCESS)
{
TRACE_PRINT1("SetInterface failed, My_WlanSetInterface error, errCode = %x", dwResult);
}
My_WlanCloseHandle(hClient, NULL);
TRACE_EXIT();
return dwResult;
}
DWORD GetInterface(WLAN_INTF_OPCODE opcode, PVOID* ppData, GUID* InterfaceGuid)
{
TRACE_ENTER();
DWORD dwResult = 0;
HANDLE hClient = NULL;
DWORD dwCurVersion = 0;
DWORD outsize = 0;
WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_invalid;
if (!initWlanFunctions())
{
TRACE_PRINT("SetInterface failed, initWlanFunctions error");
TRACE_EXIT();
return ERROR_INVALID_FUNCTION;
}
// Open Handle for the set operation
dwResult = My_WlanOpenHandle(WLAN_CLIENT_VERSION_VISTA, NULL, &dwCurVersion, &hClient);
if (dwResult != ERROR_SUCCESS)
{
TRACE_PRINT1("GetInterface failed, My_WlanOpenHandle error, errCode = %x", dwResult);
TRACE_EXIT();
return dwResult;
}
dwResult = My_WlanQueryInterface(hClient, InterfaceGuid, opcode, NULL, &outsize, ppData, &opCode);
if (dwResult != ERROR_SUCCESS)
{
TRACE_PRINT1("GetInterface failed, My_WlanQueryInterface error, errCode = %x", dwResult);
}
My_WlanCloseHandle(hClient, NULL);
TRACE_EXIT();
return dwResult;
}

I need getRTF() example for win32 api richedit control [duplicate]

(Sorry for my crazy English)
I want to get all the text in Rich Edit with RTF format, not plain text to a variable. I tried SendMessage() with EM_STREAMOUT to write directly Rich Edit to file, but I can't save the content to specific variables, for example LPWSTR. Please remember, only Win API, not MFC. Thanks for you help!
You can pass your variable to the EM_STREAMOUT callback so it can be updated as needed, eg:
DWORD CALLBACK EditStreamOutCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
std::stringstream *rtf = (std::stringstream*) dwCookie;
rtf->write((char*)pbBuff, cb);
*pcb = cb;
return 0;
}
.
std::stringstream rtf;
EDITSTREAM es = {0};
es.dwCookie = (DWORD_PTR) &rtf;
es.pfnCallback = &EditStreamOutCallback;
SendMessage(hRichEditWnd, EM_STREAMOUT, SF_RTF, (LPARAM)&es);
// use rtf.str() as needed...
Update: to load RTF data into the RichEdit control, use EM_STREAMIN, eg:
DWORD CALLBACK EditStreamInCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
std::stringstream *rtf = (std::stringstream*) dwCookie;
*pcb = rtf->readsome((char*)pbBuff, cb);
return 0;
}
.
std::stringstream rtf("...");
EDITSTREAM es = {0};
es.dwCookie = (DWORD_PTR) &rtf;
es.pfnCallback = &EditStreamInCallback;
SendMessage(hRichEditWnd, EM_STREAMIN, SF_RTF, (LPARAM)&es);
Using the EM_STREAMOUT message is the answer.
Here is the simplest example that I can construct to demonstrate. This will save the contents of a rich edit control to a file.
DWORD CALLBACK EditStreamOutCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
HANDLE hFile = (HANDLE)dwCookie;
DWORD NumberOfBytesWritten;
if (!WriteFile(hFile, pbBuff, cb, &NumberOfBytesWritten, NULL))
{
//handle errors
return 1;
// or perhaps return GetLastError();
}
*pcb = NumberOfBytesWritten;
return 0;
}
void SaveRichTextToFile(HWND hWnd, LPCWSTR filename)
{
HANDLE hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
//handle errors
}
EDITSTREAM es = { 0 };
es.dwCookie = (DWORD_PTR) hFile;
es.pfnCallback = EditStreamOutCallback;
SendMessage(hWnd, EM_STREAMOUT, SF_RTF, (LPARAM)&es);
CloseHandle(hFile);
if (es.dwError != 0)
{
//handle errors
}
}

How to convert LPWSTR to LPBYTE

I found many informations how to convert LPBYTE to LPWSTR, but no info about reverse process. I have tried do it on my own and tested such methods:
// my_documents declaration:
WCHAR my_documents[MAX_PATH];
//1st
const int size = WideCharToMultiByte(CP_UTF8, 0, my_documents, -1, NULL, 0, 0, NULL);
char *path = (char *)malloc( size );
WideCharToMultiByte(CP_UTF8, 0, my_documents, -1, path, size, 0, NULL);
//2nd
size_t i;
char *pMBBuffer = (char *)malloc( MAX_PATH );
cstombs_s(&i, pMBBuffer, MAX_PATH, my_documents, MAX_PATH-1 );
But when I write them to registry they are unreadable. And this is how I write them to registry:
BOOL SetKeyData(HKEY hRootKey, WCHAR *subKey, DWORD dwType, WCHAR *value, LPBYTE data, DWORD cbData)
{
HKEY hKey;
if(RegCreateKeyW(hRootKey, subKey, &hKey) != ERROR_SUCCESS)
return FALSE;
LSTATUS status = RegSetValueExW(hKey, value, 0, dwType, data, cbData);
if(status != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return FALSE;
}
RegCloseKey(hKey);
return TRUE;
}
SetKeyData(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", REG_SZ, L"My program", (LPBYTE)path, size)
There is no problem with conversion, but when I try to write this to registry I get some strange chars
When you are writing a string to the wide registry functions you should not convert but pass a normal WCHAR*, just cast to LPBYTE. Just remember to get the size correct. LPBYTE is really for when you write a binary blob, every other type has to be casted...

Leverging Remote Assistance in Vista

On Windows XP there is a known way to create a Remote Assistance Ticket.
http://msdn.microsoft.com/en-us/library/ms811079.aspx
But on Vista this does not appear to work. How does one do this on Vista or Windows 7?
There turns out to be two ways. The Microsoft API is called IRASrv and is documented here:
http://msdn.microsoft.com/en-us/library/cc240176(PROT.10).aspx
Another way is to simply call msra.exe. with password and novice params (e.g. msra.exe /saveasfile testfile thepassword). However that does prompt the user with the password dialog.
Here is example code for calling the IRASrv interface and generating a Remote Assistance Connection String.
COSERVERINFO si; ::ZeroMemory( &si, sizeof( si ) );
MULTI_QI qi; ::ZeroMemory( &qi, sizeof( qi ) );
HRESULT hr = S_OK;
BSTR bstrUserName = SysAllocString(L"jon");
BSTR bstrDomainName = SysAllocString(L"");
BSTR bstrPasswordStr = SysAllocString(L"testpass");
// Get the security information entered by the user
_bstr_t bstrUser(bstrUserName);
_bstr_t bstrDomain(bstrDomainName);
_bstr_t bstrPassword(bstrPasswordStr);
// Set AuthIdentity
SEC_WINNT_AUTH_IDENTITY_W AuthIdentity = {
(unsigned short*)bstrUserName,
bstrUser.length(),
(unsigned short*)bstrDomainName,
bstrDomain.length(),
(unsigned short*)bstrPasswordStr,
bstrPassword.length(),
SEC_WINNT_AUTH_IDENTITY_UNICODE
};
COAUTHINFO AuthInfo = {
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_DEFAULT,
NULL,
RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // The authentication level used
RPC_C_IMP_LEVEL_IMPERSONATE,
(COAUTHIDENTITY*)&AuthIdentity,
EOAC_NONE
};
si.pAuthInfo = &AuthInfo;
si.pwszName = bstrMachineName;
qi.pIID = &(__uuidof(RAServerLib::IRASrv));
hr = ::CoCreateInstanceEx(
__uuidof(RAServerLib::RASrv), NULL, CLSCTX_REMOTE_SERVER,
&si, 1, &qi );
if (FAILED(hr))
{
return hr;
}
CComPtr<RAServerLib::IRASrv> prasrv;
hr = qi.pItf->QueryInterface(__uuidof(RAServerLib::IRASrv), (void**)&prasrv);
if (FAILED(hr))
{
return hr;
}
LPWSTR pstr=NULL;
hr = prasrv->raw_GetNoviceUserInfo(&pstr);
if (FAILED(hr))
{
return hr;
}
pstr contains the Remote Assistance Connection String (type 2)

Resources