Ensure that sound was played after each clicking the mouse.
My idea is to create a thread that runs constantly.
#include <pthread.h>
music ding1("./ding1.wav");
music ding2("./ding2.wav");
void* pmusic(void* a)
{
while(1)
{
DWORD dw=WaitForSingleObject(hmusic, INFINITE) ;
if(ding1.busy)
{
ding2.play();
}else{
ding1.play();
}
ResetEvent(hmusic);
}
}
Create a public signal.
HANDLE hmusic=CreateEvent(nullptr,false,false,nullptr);
Play the sound using the playsound function,in music class
class music
{
public:
music(char* path)
{
//load the wav file to memory
fs.open(path...);
...
fs.readsome(buf...);
...
}
play()
{
busy=1;
PlaySoundA(buf,null,SND_MEMORY,SND_ASYNC,SND_NOSTOP,SND_NOWAIT);
busy=0;
}
char * buf;
int busy;
...
}
WndProc
LRESULT CALLBACK WndProc(hwnd,msg,wparam,lparam)
{
switch(msg)
case WM_LBUTTONDOWN:
{
SetEvent(hmusic);
break;
}
case WM_LBUTTONUP:
{
ResetEvent(hmusic);
break;
}
case WM_CREATE:
{
pthread_create(&tid,null,pmusic,null);
break;
}
}
It worked on Windows 10 after compiling, BY mingw32 with no problem.
Maybe there is another different way to achieve the above.
Thank you for sharing your wisdom and experience.
I suggest to read the doc for PlaySound.
According to that, SND_NOWAIT is not supported. The SND_NOSTOP will prevent you from playing a sound if another one is already playing, that goes against your plan. Also, the flags are combined with the bit-wise OR operator |, not comma:
PlaySoundA(buf, NULL, SND_MEMORY | SND_ASYNC);
As was pointed in the comments, you don't need a thread to play with SND_ASYNC.
Don't type the code into the question; copy/paste the working code from your editor; the one you have won't compile.
Here is what you may use:
LRESULT CALLBACK WndProc(hwnd,msg,wparam,lparam)
{
switch(msg) {
case WM_LBUTTONDOWN:
music();
break;
}
....
Where music() is:
void music()
{
if(ding1.busy)
ding2.play();
else
ding1.play();
}
Related
I need to catch and cancel any drag-and-drop event, and instead trigger a normal click on the initial coordinates where the mouse was clicked.
This is to help a disabled person with loss of motor function. Whenever she clicks on something, she keeps the button pressed and moves, registering a drag-and-drop event instead of a click.
I already tried software solutions (SteadyMouse, X-Mouse Button Control) but to no avail. Behavior modification is no longer an option due to her dementia.
I'm a webdev so not very familiar with Windows programming but I'm willing to learn if it can help her. Thanks for any ideas.
I suggest that you can immediately return to the release message event when the user presses the left mouse button.
Using SendInput and mouse hook,
C++ code sample,
#include <Windows.h>
#include <iostream>
#include <thread>
using namespace std;
HHOOK MouseHook;
BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType)
{
if (dwCtrlType == CTRL_CLOSE_EVENT)
{
UnhookWindowsHookEx(MouseHook);
}
return 1;
}
LRESULT __stdcall MouseHookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
INPUT input{};
input.type = INPUT_MOUSE;
input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
if (nCode >= 0)
{
switch (wParam)
{
case WM_LBUTTONDOWN:
{
SendInput(1, &input, sizeof(INPUT));
break;
}
}
}
return CallNextHookEx(MouseHook, nCode, wParam, lParam);
}
void SetHook()
{
if (!(MouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookCallback, NULL, 0)))
{
cout << "Failed to install MouseHook hook!" << endl;
}
}
int main()
{
SetConsoleCtrlHandler(HandlerRoutine, 1);
SetHook();
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Updated:
Here is quick gif demo and I have updated part of the code.
Newly added code:
BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType)
{
if (dwCtrlType == CTRL_CLOSE_EVENT)
{
UnhookWindowsHookEx(MouseHook);
}
return 1;
}
This callback function will be called when you close the console window, and the function contains the unhook code.
Note: After installing the hook, you need to uninstall the hook if you not need it. If you don't uninstall the hook in time, it will cause mouse stuck.
With this app, drag events will be blocked because the mouse will receive a release event immediately after it is pressed.
I just bumped into an obscure issue, while implementing a prototype for a native Win32 UI using Direct2D/DirectWrite for high performance text rendering. Things went fine and looked promising: Resizing the application window was devoid of any lag, and the entire text rendering was as solid as one could expect.
That is, until I decided to rename the binary to "ride.exe". At that point, the OS opted to force my application into "glitch mode". Resizing suddenly introduced a very noticeable lag, combined with gaps when sizing up, that would only eventually fill again. Plus, text output got all jumpy, with the perceived font size varying. Which is odd considering that I only ever create the font resource at application startup.
All those artifacts instantly go away, if I rename the binary to anything else, and instantly return, when I choose to call it "ride.exe" again. No recompilation or linking involved, it's literally just a rename operation.
I'm lost at this point, though it looks a lot like the OS is using some heuristic that involves the image name to decide, how to execute the code. So, what's going on here?
This is a complete repro to illustrate the issue:
#include <Windows.h>
#include <d2d1.h>
#include <d2d1_1helper.h>
#include <dwrite.h>
#pragma comment(lib, "D2d1.lib")
#pragma comment(lib, "Dwrite.lib")
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void create_graphics_resources(HWND const hwnd) noexcept;
void discard_graphics_resources() noexcept;
void resize_render_target(HWND const hwnd) noexcept;
void create_dw_resources() noexcept;
void discard_dw_resources() noexcept;
ID2D1Factory1* pd2d_factory { nullptr };
ID2D1HwndRenderTarget* prender_target { nullptr };
ID2D1SolidColorBrush* ptext_color_brush { nullptr };
IDWriteFactory* pdw_factory { nullptr };
IDWriteTextFormat* pdw_text_format { nullptr };
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int nCmdShow)
{
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
WNDCLASSEXW wcex {};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszClassName = L"d2d_mcve";
RegisterClassExW(&wcex);
auto const hWnd { CreateWindowExW(0, L"d2d_mcve", L"D2D MCVE", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT,
0, nullptr, nullptr, hInstance, nullptr) };
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg {};
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
CoUninitialize();
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE: {
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, D2D1_FACTORY_OPTIONS {}, &pd2d_factory);
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(pdw_factory),
reinterpret_cast<IUnknown**>(&pdw_factory));
}
break;
case WM_DESTROY:
discard_dw_resources();
discard_graphics_resources();
pdw_factory->Release();
pd2d_factory->Release();
PostQuitMessage(0);
break;
case WM_SIZE:
resize_render_target(hWnd);
InvalidateRect(hWnd, nullptr, FALSE);
break;
case WM_PAINT: {
PAINTSTRUCT ps {};
BeginPaint(hWnd, &ps);
create_graphics_resources(hWnd);
prender_target->BeginDraw();
prender_target->Clear(D2D1::ColorF(D2D1::ColorF::Black));
create_dw_resources();
auto const target_size { prender_target->GetSize() };
prender_target->SetTransform(D2D1::Matrix3x2F::Identity());
auto const& placeholder_text { L"Lorem ipsum dolor sit amet, consectetur adipiscing elit." };
prender_target->DrawTextW(placeholder_text, ARRAYSIZE(placeholder_text) - 1, pdw_text_format,
D2D1::RectF(0.0f, 0.0f, target_size.width, target_size.height),
ptext_color_brush);
auto const hr { prender_target->EndDraw() };
if (hr == D2DERR_RECREATE_TARGET)
{
discard_graphics_resources();
InvalidateRect(hWnd, nullptr, FALSE);
}
EndPaint(hWnd, &ps);
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
void create_graphics_resources(HWND const hwnd) noexcept
{
if (prender_target == nullptr)
{
RECT rc {};
GetClientRect(hwnd, &rc);
auto const size { D2D1::SizeU(static_cast<UINT32>(rc.right), static_cast<UINT32>(rc.bottom)) };
pd2d_factory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(hwnd, size), &prender_target);
prender_target->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White, 1.0f), &ptext_color_brush);
}
}
void discard_graphics_resources() noexcept
{
if (ptext_color_brush != nullptr)
{
ptext_color_brush->Release();
ptext_color_brush = nullptr;
}
if (prender_target != nullptr)
{
prender_target->Release();
prender_target = nullptr;
}
}
void resize_render_target(HWND const hwnd) noexcept
{
if (prender_target != nullptr)
{
RECT rc {};
GetClientRect(hwnd, &rc);
auto const size { D2D1::SizeU(static_cast<UINT32>(rc.right), static_cast<UINT32>(rc.bottom)) };
prender_target->Resize(size);
}
}
void create_dw_resources() noexcept
{
if (pdw_text_format == nullptr)
{
pdw_factory->CreateTextFormat(L"Courier New", nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL, 48.0f, L"en-US", &pdw_text_format);
}
}
void discard_dw_resources() noexcept
{
if (pdw_text_format != nullptr)
{
pdw_text_format->Release();
pdw_text_format = nullptr;
}
}
Save the source code as "main.cpp".
Compile the code using the following command line:
cl.exe /O2 /EHsc /D "NDEBUG" /D "UNICODE" /MD main.cpp user32.lib ole32.lib
Create a directory named "choosing_a_trident_for_a_buttplug_is_not_prudent" anywhere in the filesystem and copy "main.exe" into that directory.
Launch "main.exe" and observe the behavior of the application when resizing the main window.
Rename the copy of "main.exe" under "choosing_a_trident_for_a_buttplug_is_not_prudent" to "ride.exe", launch "ride.exe" and observe the behavior when resizing the main window.
The last step exhibits all sorts of visual glitches on my system (Windows 10 19041.330). The application instantly returns to normal operation when either renaming the executable image to anything but "ride.exe", or renaming every parent directory to no longer contain the phrase "ride". Casing doesn't make a difference.
I haven't done a thorough analysis on what exactly is happening, yet it appears that the system is using a - dare I say - somewhat (?) crude strategy to fix broken applications. As usual, the Hall of Shame is to be found in the registry:
On my system there's a key named 8e89aac5-6105-47bd-bfb3-6ed01bda07b0 under HKU\<sid>\System\GameConfigStore\Children. Leaving the obvious WTF aside for a minute, that GameConfigStore is seemingly a System-vital key for my user account, that key has values named ExeParentDirectory and Flags, with associated data RIDE (REG_SZ) and 0x11 (REG_DWORD), respectively.
The way I read this is: If a user identified by <sid> attempts to launch a binary called ride.exe (hardcoded, somewhere), that resides under a directory whose name contains RIDE, first apply the flags 0x11 to something, for sports, just to get their attention, before allowing the primary thread to execute. This is to ensure that broken app X continues to appear not broken, when <user> decides to change the environment that would otherwise exhibit the brokenness.
Even if this were to break other, properly written applications.
Now this may sound bad, but you have to give Microsoft credit where credit is due: Out of all possible combinations of characters that form a valid registry key name to communicate with us, devs, they have opted to keep this down to earth, matter of fact, professional, and use GUIDs.
I mean...
They could have just as well chosen to following:
Quality doesn't matter, ROI does
What do you mean, you did RTFM?!
Dude, what contractual guarantees? LOL, n00b
This is just a friendly FU. But no, we don't care about devs that actually TRY not to suck
But they didn't! So... thanks? I guess.
Question
What can I do to get a locking mechanism that provides minimal and stable latency while guaranteeing that a thread cannot reacquire a resource before another thread has acquired and released it?
The desirability of answers to this question are ranked as follows:
Some combination of built-in C++11 features that work in MinGW on Windows 7 (note that the <thread> and <mutex> libraries do not work on a Windows platform)
Some combination of Windows API features
A modification to the FairLock listed below, my own attempt at implementing such a mechanism
Some features provided by a free, open-source library that does not require a .configure/make/make install process, (getting that to work in MSYS is more of an adventure than I care for)
Background
I am writing an application which is effectively a multi-stage producer/consumer. One thread generates input consumed by another thread, which produces output consumed by yet another thread. The application uses pairs of buffers so that, after an initial delay, all threads can work nearly simultaneously.
Since I am writing a Windows 7 application, I had been using CriticalSections to guard the buffers. The problem with using CriticalSections (or, so far as I can tell, any other Windows or C++11-built-in synchronization object) is that it does not allow for any provision that a thread that just released a lock cannot reacquire it until another thread has done so first. Because of this, many of my test drivers for the middle thread (the Encoder) never gave the Encoder a chance to acquire the test input buffers and completed without having tested them. The end result was a ridiculous process of trying to determine an artificial wait time that stochastically worked for my machine.
Since the structure of my application requires that each stage waits for the other stage to have acquired, finished using, and released the necessary buffers for getting to use the buffer again, I need, for lack of a better term, a fair locking mechanism. I took a crack at writing one (the source code is provided below). In testing, this FairLock allows my test driver to run my Encoder at the same speeds that I was able to achieve using the CriticalSection maybe 60% of the runs. The other 40% of the runs take anywhere between 10 to 100 ms longer, which is not acceptable for my application.
FairLock
// FairLock.hpp
#ifndef FAIRLOCK_HPP
#define FAIRLOCK_HPP
#include <atomic>
using namespace std;
class FairLock {
private:
atomic_bool owned {false};
atomic<DWORD> lastOwner {0};
public:
FairLock(bool owned);
bool inline hasLock() const;
bool tryLock();
void seizeLock();
void tryRelease();
void waitForLock();
};
#endif
// FairLock.cpp
#include <windows.h>
#include "FairLock.hpp"
#define ID GetCurrentThreadId()
FairLock::FairLock(bool owned) {
if (owned) {
this->owned = true;
this->lastOwner = ID;
} else {
this->owned = false;
this->lastOwner = 0;
}
}
bool inline FairLock::hasLock() const {
return owned && lastOwner == ID;
}
bool FairLock::tryLock() {
bool success = false;
DWORD id = ID;
if (owned) {
success = lastOwner == id;
} else if (
lastOwner != id &&
owned.compare_exchange_strong(success, true)
) {
lastOwner = id;
success = true;
} else {
success = false;
}
return success;
}
void FairLock::seizeLock() {
bool success = false;
DWORD id = ID;
if (!(owned && lastOwner == id)) {
while (!owned.compare_exchange_strong(success, true)) {
success = false;
}
lastOwner = id;
}
}
void FairLock::tryRelease() {
if (hasLock()) {
owned = false;
}
}
void FairLock::waitForLock() {
bool success = false;
DWORD id = ID;
if (!(owned && lastOwner == id)) {
while (lastOwner == id); // spin
while (!owned.compare_exchange_strong(success, true)) {
success = false;
}
lastOwner = id;
}
}
EDIT
DO NOT USE THIS FairLock CLASS; IT DOES NOT GUARANTEE MUTUAL EXCLUSION!
I reviewed the above code to compare it against The C++ Programming Language: 4th Edition text I had not read carefully and what CouchDeveloper's recommended Synchronous Queue. I realized that there are several sequences in which the thread that just released the FairLock can be tricked into thinking it still owns it. All it takes is interleaving instructions as follows:
New owner: set owned to true
Old owner: is owned true? yes
Old owner: am I the last owner? yes
New owner: set me as the last owner
At this point, the old and new owners both enter their critical sections.
I am considering whether this problem has a solution and whether it is worth attempting to solve this at all. In the meantime, don't use this unless you see a fix.
I would implement this in C++11 using a condition_variable-per-thread setup so that I could choose exactly which thread to wake up when (Live demo at Coliru):
class FairMutex {
private:
class waitnode {
std::condition_variable cv_;
waitnode* next_ = nullptr;
FairMutex& fmtx_;
public:
waitnode(FairMutex& fmtx) : fmtx_(fmtx) {
*fmtx.tail_ = this;
fmtx.tail_ = &next_;
}
~waitnode() {
for (waitnode** p = &fmtx_.waiters_; *p; p = &(*p)->next_) {
if (*p == this) {
*p = next_;
if (!next_) {
fmtx_.tail_ = &fmtx_.waiters_;
}
break;
}
}
}
void wait(std::unique_lock<std::mutex>& lk) {
while (fmtx_.held_ || fmtx_.waiters_ != this) {
cv_.wait(lk);
}
}
void notify() {
cv_.notify_one();
}
};
waitnode* waiters_ = nullptr;
waitnode** tail_ = &waiters_;
std::mutex mtx_;
bool held_ = false;
public:
void lock() {
auto lk = std::unique_lock<std::mutex>{mtx_};
if (held_ || waiters_) {
waitnode{*this}.wait(lk);
}
held_ = true;
}
bool try_lock() {
if (mtx_.try_lock()) {
std::lock_guard<std::mutex> lk(mtx_, std::adopt_lock);
if (!held_ && !waiters_) {
held_ = true;
return true;
}
}
return false;
}
void unlock() {
std::lock_guard<std::mutex> lk(mtx_);
held_ = false;
if (waiters_ != nullptr) {
waiters_->notify();
}
}
};
FairMutex models the Lockable concept so it can be used like any other standard library mutex type. Put simply, it achieves fairness by inserting waiters into a list in arrival order, and passing the mutex to the first waiter in the list when unlocking.
If it's useful:
This demonstrates *) an implementation of a "synchronous queue" using semaphores as synchronization primitives.
Note: the actually implementation uses semaphores implemented with GCD (Grand Central Dispatch):
using gcd::mutex;
using gcd::semaphore;
// A blocking queue in which each put must wait for a get, and vice
// versa. A synchronous queue does not have any internal capacity,
// not even a capacity of one.
template <typename T>
class simple_synchronous_queue {
public:
typedef T value_type;
enum result_type {
OK = 0,
TIMEOUT_NOT_DELIVERED = -1,
TIMEOUT_NOT_PICKED = -2,
TIMEOUT_NOTHING_OFFERED = -3
};
simple_synchronous_queue()
: sync_(0), send_(1), recv_(0)
{
}
void put(const T& v) {
send_.wait();
new (address()) T(v);
recv_.signal();
sync_.wait();
}
result_type put(const T& v, double timeout) {
if (send_.wait(timeout)) {
new (storage_) T(v);
recv_.signal();
if (sync_.wait(timeout)) {
return OK;
}
else {
return TIMEOUT_NOT_PICKED;
}
}
else {
return TIMEOUT_NOT_DELIVERED;
}
}
T get() {
recv_.wait();
T result = *address();
address()->~T();
sync_.signal();
send_.signal();
return result;
}
std::pair<result_type, T> get(double timeout) {
if (recv_.wait(timeout)) {
std::pair<result_type, T> result =
std::pair<result_type, T>(OK, *address());
address()->~T();
sync_.signal();
send_.signal();
return result;
}
else {
return std::pair<result_type, T>(TIMEOUT_NOTHING_OFFERED, T());
}
}
private:
using storage_t = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
T* address() {
return static_cast<T*>(static_cast<void*>(&storage_));
}
storage_t storage_;
semaphore sync_;
semaphore send_;
semaphore recv_;
};
*) demonstrates: be carefully about potential issues, could be improved, etc. ... ;)
I accepted CouchDeveloper's answer since it pointed me down the right path. I wrote a Windows-specific C++11 implementation of a synchronous queue, and added this answer so that others could consider/use it if they so choose.
// SynchronousQueue.hpp
#ifndef SYNCHRONOUSQUEUE_HPP
#define SYNCHRONOUSQUEUE_HPP
#include <atomic>
#include <exception>
#include <windows>
using namespace std;
class CouldNotEnterException: public exception {};
class NoPairedCallException: public exception {};
template typename<T>
class SynchronousQueue {
private:
atomic_bool valueReady {false};
CRITICAL_SECTION getCriticalSection;
CRITICAL_SECTION putCriticalSection;
DWORD wait {0};
HANDLE getSemaphore;
HANDLE putSemaphore;
const T* address {nullptr};
public:
SynchronousQueue(DWORD waitMS): wait {waitMS}, address {nullptr} {
initializeCriticalSection(&getCriticalSection);
initializeCriticalSection(&putCriticalSection);
getSemaphore = CreateSemaphore(nullptr, 0, 1, nullptr);
putSemaphore = CreateSemaphore(nullptr, 0, 1, nullptr);
}
~SynchronousQueue() {
EnterCriticalSection(&getCriticalSection);
EnterCriticalSection(&putCriticalSection);
CloseHandle(getSemaphore);
CloseHandle(putSemaphore);
DeleteCriticalSection(&putCriticalSection);
DeleteCriticalSection(&getCriticalSection);
}
void put(const T& value) {
if (!TryEnterCriticalSection(&putCriticalSection)) {
throw CouldNotEnterException();
}
ReleaseSemaphore(putSemaphore, (LONG) 1, nullptr);
if (WaitForSingleObject(getSemaphore, wait) != WAIT_OBJECT_0) {
if (WaitForSingleObject(putSemaphore, 0) == WAIT_OBJECT_0) {
LeaveCriticalSection(&putCriticalSection);
throw NoPairedCallException();
} else {
WaitForSingleObject(getSemaphore, 0);
}
}
address = &value;
valueReady = true;
while (valueReady);
LeaveCriticalSection(&putCriticalSection);
}
T get() {
if (!TryEnterCriticalSection(&getCriticalSection)) {
throw CouldNotEnterException();
}
ReleaseSemaphore(getSemaphore, (LONG) 1, nullptr);
if (WaitForSingleObject(putSemaphore, wait) != WAIT_OBJECT_0) {
if (WaitForSingleObject(getSemaphore, 0) == WAIT_OBJECT_0) {
LeaveCriticalSection(&getCriticalSection);
throw NoPairedCallException();
} else {
WaitForSingleObject(putSemaphore, 0);
}
}
while (!valueReady);
T toReturn = *address;
valueReady = false;
LeaveCriticalSection(&getCriticalSection);
return toReturn;
}
};
#endif
I have looked at the Microsoft documentation but it says that there should be no difference.
Note that this is a virtual ListView, so I supply the state icon index in the code implementing the LVN_GETDISPINFO message, if the LVIF_STATE flag is set in LV_ITEM::mask.
Does anyone know of any subtle differences which may cause this difference in behavior?
Not posting any sample code in your question does not exactly help...
This code works for me:
#include <Windows.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
typedef struct {
LPTSTR text;
UINT icon;
UINT stateicon;
} MYITEM;
HWND g_hLV=NULL;
MYITEM g_myitems[2]={{"item1",0,0},{"item2",2,2}};
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
{
switch(msg)
{
case WM_NOTIFY:
if (lp)
{
NMLVDISPINFO*pLVDI=(NMLVDISPINFO*)lp;
NMLISTVIEW*&pLV=(NMLISTVIEW*&)pLVDI;
switch(pLVDI->hdr.code)
{
case LVN_GETDISPINFO:
if (LVIF_TEXT&pLVDI->item.mask) pLVDI->item.pszText=g_myitems[pLVDI->item.iItem].text;
if (LVIF_IMAGE&pLVDI->item.mask) pLVDI->item.iImage=g_myitems[pLVDI->item.iItem].icon;
if (LVIF_STATE&pLVDI->item.mask)
{
pLVDI->item.state=INDEXTOSTATEIMAGEMASK(1+g_myitems[pLVDI->item.iItem].stateicon);
pLVDI->item.stateMask=pLVDI->item.state;
}
return 0;
}
}
break;
case WM_CREATE:
{
g_hLV=CreateWindowEx(WS_EX_CLIENTEDGE,WC_LISTVIEW,0,WS_VISIBLE|WS_CHILD|LVS_OWNERDATA|LVS_REPORT|LVS_SHAREIMAGELISTS,0,0,0,0,hwnd,0,0,0);
LVCOLUMN lvc={LVCF_TEXT|LVCF_WIDTH};
lvc.pszText="dummy";
lvc.cx=99;
ListView_InsertColumn(g_hLV,0,&lvc);
SHFILEINFO sfi;
HIMAGELIST hil=(HIMAGELIST)SHGetFileInfo(".\\",FILE_ATTRIBUTE_DIRECTORY,&sfi,0,SHGFI_SMALLICON|SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES);
ListView_SetImageList(g_hLV,hil,LVSIL_SMALL);
ListView_SetImageList(g_hLV,hil,LVSIL_STATE);
g_myitems[1].stateicon=g_myitems[1].icon=sfi.iIcon;//assuming the imagelist has icons is wrong, so set at least one of them to a valid index
ListView_SetCallbackMask(g_hLV,LVIS_STATEIMAGEMASK);
ListView_SetItemCount(g_hLV,2);
}
return 0;
case WM_SIZE:
SetWindowPos(g_hLV,0,0,0,LOWORD(lp),HIWORD(lp),SWP_NOZORDER|SWP_NOACTIVATE);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd,msg,wp,lp);
}
int WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
InitCommonControls();
//This dialog subclassing is a ugly hack, but this is just sample code!
HWND hwnd=CreateWindowEx(0,WC_DIALOG,"LVTest",WS_OVERLAPPEDWINDOW,0,0,99,99,0,0,0,0);
SetWindowLongPtr(hwnd,GWLP_WNDPROC,(LONG_PTR)WndProc);
SendMessage(hwnd,WM_CREATE,0,0);
ShowWindow(hwnd,nShowCmd);
MSG msg;
while (GetMessage(&msg,0,0,0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
I have got following code:-
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
char ay[256]={0};//HWND hwnd= GetForegroundWindow();
if( GetClassName(hwnd,ay,256))
{
char x[70]={0};
GetWindowText(hwnd,x,70);
if(IsWindowVisible(hwnd))
{
// CaptureAnImage(hwNd,hwnd);
HINSTANCE hins= (HINSTANCE) GetWindowLong(hwnd,GWL_HINSTANCE);
WNDCLASSEX lpwcx;
GetClassInfoEx(hins,ay,&lpwcx);
if (MessageBox(0,
strcat(strcat(x, "\r\n"), lpwcx.lpszClassName),
"Info", 0x06L) == IDTRYAGAIN)
{
return false;
}
}
}
return true;
}
void cstm()
{
EnumWindows(EnumWindowsProc,0);
}
This runs fine on Codeblocks (with VS 2010 compiler(cl)) but VS2010 gives a corrupted lpwcx value, I have tried the Unicode as well as Ascii to tackle this but no good result at
all. The first lpwcx is correct but later they return class not found(1411) ,although the hinstance and class name is correct.
Please help.
strcat(strcat(x, "\r\n"), lpwcx.lpszClassName),
The odds that this will overflow the x buffer and stomp some local variable values, like *lpwcx", are very high. 70 chars is unreasonably frugal. If you don't want to use strcat_s() then at least make it bigger. And yes, initialize lpwcx.cbSize
Always fill in the cbSize member of data blocks before calling any API functions. Many of them rely upon this value to know which version of the data structure they should fill in.