Announcement
Collapse
No announcement yet.
Skin support for plugin window controls
Collapse
X
-
I'm assuming you've already checked the source code for the example embedded window plugin here: http://forums.winamp.com/showthread.php?t=322114
If you can, post your source code in a zip or 7z archive so I can see if I can find any obvious errors.
-
-
Originally Posted by thinktink View PostI'm assuming you've already checked the source code for the example embedded window plugin here
But all I could find was the need to handle messages of embedded dialog proc like this:
Now it works correct. Is everything right here?code:
case WM_CTLCOLORLISTBOX:
case WM_CTLCOLORDLG:
case WM_CTLCOLORBTN:
case WM_CTLCOLORSTATIC:
case WM_CTLCOLOREDIT:
case WM_DRAWITEM:
{
return WADlg_handleDialogMsgs(hwnd, msg, wParam, lParam);
}
Another one offtopic question: I added the plugin menu item to Winamp main menu using InsertMenuItem() function with text and shortcut:
By handling WM_COMMAND I process menu click. And it works. But when I press Alt+B shortcut associated with menu item - nothing happens.code:
wchar_t menu_caption[] = L"My plugin name\tAlt+B";
How to fix this?
Comment
-
-
I could have SWORN I downloaded that example plugin a long time ago but I still can't find it.
However, you can use the following for an example:
What is Winamp? Why is Winamp? How is Winamp? All these burning questions and issues discussed within.
It should have everything you need to learn standard skinning support. It also contains an example for shortcut handling.
Unfortunately, there is no native skinning support for radio buttons and checkboxes.
Your edit box doesn't look right. Before going on a tare, check the example I provided for that.
Comment
-
-
thinktink, thanks for example!
I have added this code:
on init():code:
api_application *WASABI_API_APP;
api_service *WASABI_API_SVC;
template <class api_T>
void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
{
if(WASABI_API_SVC)
{
waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid(factoryGUID_t);
if(factory)
{
api_t = (api_T*)factory->getInterface();
}
}
}
except WASABI_API_CREATEDIALOGW I still use: CreateDialogParam(...code:
WADlg_init(plugin.hwndParent);
WASABI_API_SVC = (api_service*)SendMessage(plugin.hwndParent, WM_WA_IPC, 0, IPC_GET_API_SERVICE);
if(WASABI_API_SVC != NULL)
{
ServiceBuild(WASABI_API_APP, applicationApiServiceGuid);
}
code:
ACCEL accel = {FVIRTKEY | FALT, 'A', MY_PLUGINMENU_ID};
HACCEL hAccel = CreateAcceleratorTable(&accel, 1);
WASABI_API_APP->app_addAccelerators(embedWnd, &hAccel, 1, TRANSLATE_MODE_NORMAL);
But when I press Alt+A nothing happens. Hotkey not work. Maybe I something missed?code:
DlgProc:
case WM_COMMAND:
{
if(LOWORD(wParam) == MY_PLUGINMENU_ID)
{
MessageBox(hwnd, L"This is hotkey!", L"", MB_OK);
}
break;
}
Comment
-
-
Another one question: thinktink, your project compiled succesfully, but when I try to compile my project compiler throws error:
error LNK2001: unresolved external symbol "class api_language * languageManager" (?languageManager@@3PAVapi_language@@A)
D:\Winamp_SDK;D:\Winamp_SDK\Wasabi;D:\Winamp_SDK\Agave;$(IncludePath)
Comment
-
-
Originally Posted by Ingvar View Postthinktink, thanks for example!
I have added this code:
on init():code:
api_application *WASABI_API_APP;
api_service *WASABI_API_SVC;
template <class api_T>
void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
{
if(WASABI_API_SVC)
{
waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid(factoryGUID_t);
if(factory)
{
api_t = (api_T*)factory->getInterface();
}
}
}
except WASABI_API_CREATEDIALOGW I still use: CreateDialogParam(...code:
WADlg_init(plugin.hwndParent);
WASABI_API_SVC = (api_service*)SendMessage(plugin.hwndParent, WM_WA_IPC, 0, IPC_GET_API_SERVICE);
if(WASABI_API_SVC != NULL)
{
ServiceBuild(WASABI_API_APP, applicationApiServiceGuid);
}
code:
ACCEL accel = {FVIRTKEY | FALT, 'A', MY_PLUGINMENU_ID};
HACCEL hAccel = CreateAcceleratorTable(&accel, 1);
WASABI_API_APP->app_addAccelerators(embedWnd, &hAccel, 1, TRANSLATE_MODE_NORMAL);
But when I press Alt+A nothing happens. Hotkey not work. Maybe I something missed?code:
DlgProc:
case WM_COMMAND:
{
if(LOWORD(wParam) == MY_PLUGINMENU_ID)
{
MessageBox(hwnd, L"This is hotkey!", L"", MB_OK);
}
break;
}
I do it with:
code:
MY_PLUGINMENU_ID=(UINT)::SendMessage(plugin.hwndParent,WM_WA_IPC,(WPARAM)0,IPC_REGISTER_LOWORD_COMMAND);
Comment
-
-
Originally Posted by Ingvar View Post...
But when I press Alt+A nothing happens. Hotkey not work. Maybe I something missed?code:
DlgProc:
case WM_COMMAND:
{
if(LOWORD(wParam) == MY_PLUGINMENU_ID)
{
MessageBox(hwnd, L"This is hotkey!", L"", MB_OK);
}
break;
}
Comment
-
-
Originally Posted by Ingvar View PostAnother one question: thinktink, your project compiled succesfully, but when I try to compile my project compiler throws error:
I add paths to Winamp SDK in PROJECT->my_project properties->VC++ Directories->Include Directories:
But compiler still error LNK2001: unresolved external symbol "class api_language * languageManager"
Open "gen_yourplugin" Property Pages
Select: All Configurations
Go to: Configuration Properties -> C/C++ -> General
Inspect "Additional Include Directories" and make sure the subfolders in the Winamp SDK folder labeled "Wasabi", "Agave", and "Winamp" are being included.
Attached Files
Comment
-
-
Originally Posted by thinktink View PostHow have you generated/set/defined "MY_PLUGINMENU_ID"?
code:
UINT MY_PLUGINMENU_ID = 0xa2bc;Originally Posted by Ingvar View Postbut when I try to compile my project compiler throws error: unresolved external symbol "class api_language * languageManager". When I was writing the code I wrote accidentally.
instead of:code:
api_language *WASAPI_API_LNG;
code:
api_language *WASABI_API_LNG;Originally Posted by Ingvar View PostBut when I press Alt+A nothing happens. And I found it while reading your project. I wrote:
instead of:code:
WASABI_API_APP->app_addAccelerators(dialogWnd, &hAccel, 1, TRANSLATE_MODE_NORMAL);
But I found a bug in your code toocode:
WASABI_API_APP->app_addAccelerators(dialogWnd, &hAccel, 1, TRANSLATE_MODE_GLOBAL);. Look at quit() function:
At this moment, the GetWindowLongPtr() function will return 0x00 because the parent window no longer exists. You can verify it using debugger.code:
// restores the original playlist window proc now that we are closing and if the window was subclassed
HWND pe_wnd = (HWND)SendMessage(plugin.hwndParent,WM_WA_IPC,IPC_GETWND_PE,IPC_GETWND);
if(GetWindowLongPtr(pe_wnd,GWLP_WNDPROC) == (LONG_PTR)SubclassPlaylistProc){
SetWindowLongPtr(pe_wnd,GWLP_WNDPROC,(LONG_PTR)oldPlaylistWndProc);
}
Therefore, this code should be moved to the parent window's dialog proc into the WM_DESTROY handler.
But now it's time to return to the main question of the topic.
I opened your "gen_classicart" project and edited the resource dialog: I placed some controls - button, text label and a edit control. Compile and run it in Winamp:
It looks like skin support isn't working for controls. I didn't modify source code except GEN_INIT_FAILURE replace with 1 (I didn't find a definition). So how to theme the controls?
Comment
-
-
Originally Posted by Ingvar View PostI didn't generate value for MY_PLUGINMENU_ID. Just assign a value:
code:
UINT MY_PLUGINMENU_ID = 0xa2bc;...
Originally Posted by Ingvar View Post...
But I found a bug in your code too. Look at quit() function:
At this moment, the GetWindowLongPtr() function will return 0x00 because the parent window no longer exists. You can verify it using debugger.code:
// restores the original playlist window proc now that we are closing and if the window was subclassed
HWND pe_wnd = (HWND)SendMessage(plugin.hwndParent,WM_WA_IPC,IPC_GETWND_PE,IPC_GETWND);
if(GetWindowLongPtr(pe_wnd,GWLP_WNDPROC) == (LONG_PTR)SubclassPlaylistProc){
SetWindowLongPtr(pe_wnd,GWLP_WNDPROC,(LONG_PTR)oldPlaylistWndProc);
}
Therefore, this code should be moved to the parent window's dialog proc into the WM_DESTROY handler.
Trying to "unsubclass" a shared window is problematic at best as not all plugins are guaranteed to be loaded and unloaded in the correct order to prevent subclass procedure chain breaks, which is very bad. If your subclass proceedure is unloaded (by dint of your plugin being unloaded) before the window it's connected to is destroyed it will cause Access Violations when the (now non-existent) procedure is called.
Originally Posted by Ingvar View Post
But now it's time to return to the main question of the topic.
I opened your "gen_classicart" project and edited the resource dialog: I placed some controls - button, text label and a edit control. Compile and run it in Winamp:
It looks like skin support isn't working for controls. I didn't modify source code except GEN_INIT_FAILURE replace with 1 (I didn't find a definition). So how to theme the controls?PHP Code:case WM_CTLCOLORLISTBOX:
case WM_CTLCOLORDLG:
case WM_CTLCOLORBTN:
case WM_CTLCOLORSTATIC:
case WM_CTLCOLOREDIT:
case WM_DRAWITEM:
{
return WADlg_handleDialogMsgs(hwnd, msg, wParam, lParam);
}
PHP Code:#define GEN_INIT_FAILURE 1
#define GEN_INIT_SUCCESS 0
Comment
-
-
Found it!
I finally found the example package.
Attached.
Comment
-
-
Originally Posted by thinktink View PostI finally found the example package
Originally Posted by thinktink View PostThat is actually a good thing, it means that the window is being destroyed BEFORE your plugin is unloaded from memory.
Originally Posted by thinktink View PostSince that window never had standard controls to skin, the original developer never put in the code to skin any. Go ahead and add the handler inside "art_dlgproc" switch/case statements
Originally Posted by thinktink View PostThose are defined in GEN.H in the Winamp SDK
While looking through your code and using the debugger, I found another one bug. Looks like it's a winamp bug.
Look at this code:
As I marked, this block runs 4 times when track changing or when you press ffwd/rwd. I think you need to handle another notification to monitor the track change.code:
else if(msg == WM_WA_IPC)
{
if(lParam == IPC_CB_MISC && (wParam == IPC_CB_MISC_TITLE || wParam == IPC_CB_MISC_TITLE_RATING))
{
//THIS BLOCK RUNS 4 TIMES !!!
// art change
PostMessage(myWndChild,WM_USER,0,0);
}
Offtopic. In Visual Studio 2012 I set configuration to "Release" and compiled my plugin dll. But Winamp loads it only on my PC.
I sent it to another PC and also tried it on a virtual system using the latest Winamp, but in these cases Winamp doesn't load my plugin.
In the "Preferences" window I see "NOT LOADED" message. And log file \AppData\Roaming\Winamp\winamp.log contains error:
[5.9.0.9999] [error] Error when loading the plugin 'gen_wa_plugin.dll'! Error code : 126!
What other project settings do I need to set to compile my plugin to distribute it on other PCs?
Comment
-
-
Originally Posted by Ingvar View PostThanks!
Originally Posted by Ingvar View PostI think you understood me correctly. Anyway it would be correct to move unsubclass code to the parent window's dialog proc at the WM_DESTROY.
Originally Posted by Ingvar View PostThanks! Now it looks right:
Originally Posted by Ingvar View PostIt's weird but I downloaded Winamp SDK 5.5 from here https://download.nullsoft.com/winamp...WA5.55_SDK.exe and Winamp/gen.h file contains only #define GEN_INIT_SUCCESS 0.PHP Code:#ifndef GEN_INIT_FAILURE
#define GEN_INIT_FAILURE 1
#endif //GEN_INIT_FAILURE
Originally Posted by Ingvar View PostWhile looking through your code and using the debugger, I found another one bug. Looks like it's a winamp bug.
Look at this code:
As I marked, this block runs 4 times when track changing or when you press ffwd/rwd. I think you need to handle another notification to monitor the track change.code:
else if(msg == WM_WA_IPC)
{
if(lParam == IPC_CB_MISC && (wParam == IPC_CB_MISC_TITLE || wParam == IPC_CB_MISC_TITLE_RATING))
{
//THIS BLOCK RUNS 4 TIMES !!!
// art change
PostMessage(myWndChild,WM_USER,0,0);
}
Originally Posted by Ingvar View PostOfftopic. In Visual Studio 2012 I set configuration to "Release" and compiled my plugin dll. But Winamp loads it only on my PC.
I sent it to another PC and also tried it on a virtual system using the latest Winamp, but in these cases Winamp doesn't load my plugin.
In the "Preferences" window I see "NOT LOADED" message. And log file \AppData\Roaming\Winamp\winamp.log contains error:
For example, gen_classicart.dll works fine.
What other project settings do I need to set to compile my plugin to distribute it on other PCs?
Comment
-
-
Originally Posted by thinktink View PostWinamp is not guaranteed to unload other plugins that also subclass the Winamp windows in the correct order.
Originally Posted by thinktink View PostThe checkboxes also aren't completely skinned
Originally Posted by thinktink View Postthere's currently no native support for skinning checkboxes or radio buttons
I used code to get skin HBITMAP and save it to file:
And skin HBITMAP contains this:code:
SendMessage(plugin.hwndParent, WM_WA_IPC, 0, IPC_GET_GENSKINBITMAP);
As we can see, there glyphs for push-button and scrollbar are only.
By the way, where is this image stored? In what file? I looked through all the graphic and resources files in the Winamp folder but didn't find these glyphs.
Originally Posted by thinktink View Postit looks like there's a white border around what looks like edit controls, which is not part of the selected skin
Here we can see specific themed borders at the bottom and right side of EDIT control. I tried to change the styles of the control, but I could not get such borders.
Is the source code of Jump to File plugin available? I can't find it. I would be able to see the implementation of the edit control.
Comment
-
Comment