Old 19th January 2002, 23:59   #1
Tuatara
Member
 
Tuatara's Avatar
 
Join Date: Jan 2002
Location: New Zealand
Posts: 75
Crash when using a hooked Main Winamp window

When using a window hook in a DSP plugin to capture mouse move messages on the main Winamp window (to simulate docking of plugins to Winamp), an access violation crash ocurrs on quit (pressing close box) ONLY when using the MSVC debug environment. When using the same compiled DSP plugin outside of MSVC, no crash ocurrs.

Getting quite frustrating when testing & debugging.

Example Call Stack (from DSP_ECHO.DLL crash)
02b011cc() [Invalid Memory]
c0000000() [Invalid Memory]
USER32! 77e12e98()
USER32! 77e14876()
USER32! 77e15709()
WINAMP! 00432c25()
18a16456()

Seems to be a timing problem again ... possibly related to the previous post (Bug when switching DSP Plugins while MP3 playing), in that it appears that while the quit function is called, there are 'dead' pointers still being used somewhere within Winamp.

Winamp 2.78c (x86) - Dec 9 2001, with patch applied.

Replicated on various machines including:
- Pentium 120, SoundBlaster PCI, Win98 (no updates)
- Pentium II Dual 433, Yamaha PCI, Win2K (latest updates)
- Pentium III 850, ESS Maestro PCI, Win2K (latest updates)

Regards,
Robert.

---

Example code to hook the window, which replicates the problem:
(Based on the DSP_ECHO example)

Testing from within Visual C++ 6.0 (latest update)
Project Settings
- Debug Tab
- Category: General
- Executable for Debug Session: C:\Program Files\Winamp\Winamp.exe
- Working Directory: C:\Program Files\Winamp\

[DSP_ECHO.C Code Changes]

WNDPROC pOrigWndProc = NULL;

static LRESULT CALLBACK DSP1_HookWinampWnd(HWND hwnd, _
UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_MOVE:
// Capture the mouse move messages
break;
}

// Call Original Winamp Window Procedure
return CallWindowProc(pOrigWndProc, hwnd, uMsg, wParam, lParam);
}

int init(struct winampDSPModule *this_mod)
{
// Hook Main Winamp Window to track window move messages
pOrigWndProc = (WNDPROC) SetWindowLong(this_mod->hwndParent, _
GWL_WNDPROC, (LONG) DSP1_HookWinampWnd);

return 0;
}

void quit(struct winampDSPModule *this_mod)
{
// If we had hooked the window, unhook it
if (pOrigWndProc)
{
SetWindowLong(this_mod->hwndParent, GWL_WNDPROC, _
(LONG) pOrigWndProc);
pOrigWndProc = NULL;
}
}
Tuatara is offline   Reply With Quote
Old 20th January 2002, 00:14   #2
peter
ist death
 
peter's Avatar
 
Join Date: May 2000
Posts: 3,704
sorry dude, that's your messup. when the window gets WM_DESTROY, it calls your windowproc, which is no longer there. you need to add a simple LoadLibrary() hack to increase your dll's reference cound to keep in memory until winamp process terminates.
peter is offline   Reply With Quote
Old 20th January 2002, 01:04   #3
Tuatara
Member
 
Tuatara's Avatar
 
Join Date: Jan 2002
Location: New Zealand
Posts: 75
When the WM_DESTROY message is sent to the Winamp window, the quit function has ALREADY been called, and the window has been successfully unhooked. I've checked this!

I also tried unhooking the window on the WM_DESTROY message, but this is never received before the quit function is called. Somewhere else the window may (again) be subclassed by something else, and this piece of code is restoring the incorrect windowproc (the one already unloaded in my plugin). Possibly the loading / unloading is being done in a reverse order?

I've tried your suggestion of a LoadLibrary() hack to keep the DLL loaded until winamp terminates and this method works. It's not the best solution - but it's an 'ok' workaround.
Tuatara is offline   Reply With Quote
Old 20th January 2002, 11:52   #4
peter
ist death
 
peter's Avatar
 
Join Date: May 2000
Posts: 3,704
all my gapless output plugins do the same, i don't know any better way. not a real prob anyway because output plugins are unloaded just before shutting down winamp process so if they even stay in memory until the process dies, it doesn't make real difference. looks like dsp ones are dynamically reloaded so LoadLibrary hack might do some evil things here. unhooking is no good because other plugins might be subclassing too.
peter is offline   Reply With Quote
Old 20th January 2002, 12:03   #5
Tuatara
Member
 
Tuatara's Avatar
 
Join Date: Jan 2002
Location: New Zealand
Posts: 75
I found that I could use the LoadLibrary() hack to keep it around until the winAmp application finally terminates, since I do a full cleanup when QUIT is called. This leaves the WindowProc in place and working as it was before. Not the best, but it works.

I've got another question for you ... posted in new thread - appearing soon!
Tuatara is offline   Reply With Quote
Old 18th February 2002, 02:45   #6
splitretina
Junior Member
 
Join Date: Feb 2002
Location: San Mateo, CA
Posts: 2
Send a message via AIM to splitretina Send a message via Yahoo to splitretina
so whats the code

I'm having the same problem in a dsp plugin. The LoadLibrary hack works fine, but I'm having to hardcode the name of the dll. Suppose this is fine, but isn't there an easy way to retrieve the name of the dll at runtime? i tried GetModuleName(), but that returns winamp.exe. I would be terribly appreciative for any help, i tired of the buggy MSDN site...

-s
splitretina is offline   Reply With Quote
Old 18th February 2002, 03:47   #7
Tuatara
Member
 
Tuatara's Avatar
 
Join Date: Jan 2002
Location: New Zealand
Posts: 75
// A duplicate copy of our DLL Module handle for reference count hack
static HMODULE hLibrary = NULL;

int init(struct winampDSPModule *this_mod)
{
char fname[512];

// Get the current module filename
GetModuleFileName(this_mod->hDllInstance, fname, sizeof(fname));

// LoadLibrary Hack to increase our reference count by one
// to handle window hooking and shutdown problems
if (hLibrary == NULL)
hLibrary = LoadLibrary(fname);

[etc...]
}

If you're coding in C++ (MFC), and you've got a destructor for the DLL instance, then add the following in the destructor to unload it nicely for the OS. Failing that, the OS will unload it for you anyways when Winamp quits. The if (hLibrary == NULL) test is important, otherwise you'd keep opening new DLL handles.

CWinampApp::~CWinampApp()
{
if (hLibrary)
FreeLibrary(hLibrary);
}

This should get you going again ...
Tuatara is offline   Reply With Quote
Old 18th February 2002, 15:26   #8
peter
ist death
 
peter's Avatar
 
Join Date: May 2000
Posts: 3,704
moved where it belongs
peter is offline   Reply With Quote
Old 19th February 2002, 01:39   #9
the7erm
Junior Member
 
Join Date: Feb 2001
Location: Wyoming
Posts: 5
Send a message via AIM to the7erm Send a message via Yahoo to the7erm
Time to ask the smart people a question ...

See this code?

int index = SendMessage(hwnd_winamp, WM_USER, 0, IPC_GETLISTPOS);
char *name = SendMessage(hwnd_winamp, WM_USER, index, IPC_GETPLAYLISTFILE);

Seems pretty simple huh? I'm using MicroSoft visual c++ 6 standard edition.

So why? Why is it a simple little thing like this doesn't work. This is the EXACT code from the FAQ I cut and paste it myself. So what I would like to know is ... is there a way to get around it?

main()
{
HWND hwnd_winamp = FindWindow("Winamp v1.x",NULL);
char TheKey;
long next = 40048;
int index = SendMessage(hwnd_winamp, WM_USER, 0, IPC_GETLISTPOS);
char *name = SendMessage(hwnd_winamp, WM_USER, index, IPC_GETPLAYLISTFILE);

cout << name << endl;
cin >> TheKey;

SendMessage(hwnd_winamp,WM_COMMAND, next,0);
return 0;
}

I know the code is stupid, but hey I'm just starting out.

This is them message I get.
--------------------Configuration: anykey - Win32 Debug--------------------
Compiling...
anykey.cpp
C:\Program Files\Microsoft Visual Studio\MyProjects\AnyKey\anykey.cpp(16) : error C2440: 'initializing' : cannot convert from 'long' to 'char *'
Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
Error executing cl.exe.

anykey.obj - 1 error(s), 0 warning(s)
the7erm is offline   Reply With Quote
Old 20th February 2002, 18:20   #10
Gourou
Senior Member
 
Gourou's Avatar
 
Join Date: Feb 2002
Location: The backside of the universe on the trailing edge of eternity
Posts: 238
try this line instead of the one you have:

char *name = (char *)SendMessage(hwnd_winamp, WM_USER, index, IPC_GETPLAYLISTFILE);

also try changing the name of the 'name' variable, dont gimme a funny look, just trust the voice of experience
Gourou is offline   Reply With Quote
Reply
Go Back   Winamp & Shoutcast Forums > Developer Center > Winamp Development

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump