/*********************************************************************** Copyright 2002 Ben Rudiak-Gould. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA, or visit . ***********************************************************************/ #define WIN32_LEAN_AND_MEAN #include #include #include "../include/dvdsynth-filter.h" #include "resource.h" HINSTANCE g_hinstance; DvsDockingBayGlobal* g_callbacks; struct Filter { DvsFilterGlobal* funcs; Filter* next; }; Filter* all_filters; struct FilterInstance { DvsDeviceUser* dev; FilterInstance* next; }; struct FilterDialog { Filter* active_filters; Filter* all_filters; void Init(HWND hwnd); void Add(HWND hwnd); void Remove(HWND hwnd); void MoveUpDown(HWND hwnd, bool down); Filter** GetSelectedActiveFilter(HWND hwnd, bool one_prev); }; bool Includes(Filter* list, DvsFilterGlobal* filter) { for (Filter* f = list; f; f = f->next) if (f->funcs == filter) return true; return false; } void FilterDialog::Init(HWND hwnd) { Filter* f; HWND active_list = GetDlgItem(hwnd, IDC_ACTIVELIST); for (f = active_filters; f; f = f->next) { int index = ListBox_InsertString(active_list, 0, f->funcs->visible_name); ListBox_SetItemData(active_list, index, f->funcs); } ListBox_InsertString(active_list, 0, "(raw device)"); HWND avail_list = GetDlgItem(hwnd, IDC_AVAILLIST); for (f = all_filters; f; f = f->next) { if ((f->funcs->flags & DVDSYNTH_FILTER_ONLY_ONE) && Includes(active_filters, f->funcs)) { // filter already in list; no action } else { int index = ListBox_AddString(avail_list, f->funcs->visible_name); ListBox_SetItemData(avail_list, index, f->funcs); } } } void FilterDialog::Add(HWND hwnd) { HWND active_list = GetDlgItem(hwnd, IDC_ACTIVELIST); HWND avail_list = GetDlgItem(hwnd, IDC_AVAILLIST); int avail_index = ListBox_GetCurSel(avail_list); if (avail_index == LB_ERR) return; DvsFilterGlobal* filter = (DvsFilterGlobal*)ListBox_GetItemData(avail_list, avail_index); if (filter->flags & DVDSYNTH_FILTER_ONLY_ONE) ListBox_DeleteString(avail_list, avail_index); int active_index = ListBox_AddString(active_list, filter->visible_name); ListBox_SetItemData(active_list, active_index, filter); Filter* f = new Filter; f->funcs = filter; f->next = active_filters; active_filters = f; } void FilterDialog::Remove(HWND hwnd) { HWND active_list = GetDlgItem(hwnd, IDC_ACTIVELIST); HWND avail_list = GetDlgItem(hwnd, IDC_AVAILLIST); int active_index = ListBox_GetCurSel(active_list); if (active_index == LB_ERR || active_index == 0) return; int pos = ListBox_GetCount(active_list) - 1; Filter** pf = &active_filters; while (pos > active_index && *pf != 0) { pf = &(*pf)->next; --pos; } Filter* f = *pf; DvsFilterGlobal* filter = (DvsFilterGlobal*)ListBox_GetItemData(active_list, active_index); if (f == 0 || f->funcs != filter) return; ListBox_DeleteString(active_list, active_index); *pf = f->next; delete f; if (filter->flags & DVDSYNTH_FILTER_ONLY_ONE) { int avail_index = ListBox_AddString(avail_list, filter->visible_name); ListBox_SetItemData(avail_list, avail_index, filter); } } Filter** FilterDialog::GetSelectedActiveFilter(HWND hwnd, bool one_prev) { HWND active_list = GetDlgItem(hwnd, IDC_ACTIVELIST); int active_index = ListBox_GetCurSel(active_list); if (active_index <= 0) return 0; active_index += one_prev; int pos = ListBox_GetCount(active_list) - 1; if (active_index > pos) return 0; Filter** pf = &active_filters; while (pos > active_index && *pf != 0) { pf = &(*pf)->next; --pos; } Filter* f = *pf; DvsFilterGlobal* filter = (DvsFilterGlobal*)ListBox_GetItemData(active_list, active_index); if (f == 0 || f->funcs != filter) return 0; return pf; } void FilterDialog::MoveUpDown(HWND hwnd, bool down) { Filter** pplower = GetSelectedActiveFilter(hwnd, down); if (!pplower) return; Filter* plower = *pplower; Filter* pupper = plower->next; if (!pupper) return; HWND active_list = GetDlgItem(hwnd, IDC_ACTIVELIST); int active_index = ListBox_GetCurSel(active_list); int inactive_index = active_index + (down ? +1 : -1); DvsFilterGlobal* other_filter = (DvsFilterGlobal*)ListBox_GetItemData(active_list, inactive_index); ListBox_DeleteString(active_list, inactive_index); ListBox_InsertString(active_list, active_index, other_filter->visible_name); ListBox_SetItemData(active_list, active_index, other_filter); *pplower = pupper; plower->next = pupper->next; pupper->next = plower; } BOOL CALLBACK FilterSelectDialogProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { if (msg == WM_INITDIALOG) { SetWindowLong(hwnd, DWL_USER, (LONG)lparam); ((FilterDialog*)lparam)->Init(hwnd); return TRUE; } else if (msg == WM_COMMAND) { FilterDialog* fd = (FilterDialog*)GetWindowLong(hwnd, DWL_USER); switch (LOWORD(wparam)) { case IDOK: EndDialog(hwnd, 0); return TRUE; case IDC_ADD: fd->Add(hwnd); return TRUE; case IDC_REMOVE: fd->Remove(hwnd); return TRUE; case IDC_MOVEUP: fd->MoveUpDown(hwnd, false); return TRUE; case IDC_MOVEDOWN: fd->MoveUpDown(hwnd, true); return TRUE; } } return FALSE; } void FilterSelectDialog(Filter** currently_selected, Filter* all_filters) { FilterDialog fd = { *currently_selected, all_filters }; DialogBoxParam(g_hinstance, MAKEINTRESOURCE(IDD_FILTERS), NULL, FilterSelectDialogProc, (LPARAM)&fd); *currently_selected = fd.active_filters; } class MyDevice : public DvsDeviceUser { FilterInstance* filter_instances; // last in list is actual device static Filter* active_filters; void Hook(Filter* f, DvsDeviceUser* user, DvsDeviceKernel** pkernel, DvsDockingBay* bay); static void StaticAddDeviceMenuItems(DvsDeviceUser* self, DvsMenu* menu); static int StaticQueryUnplug(DvsDeviceUser* self); static void StaticDelete(DvsDeviceUser* self); public: MyDevice(DvsDeviceUser* user, DvsDeviceKernel** pkernel, DvsDockingBay* bay); }; Filter* MyDevice::active_filters = 0; void AddDeviceMenuItems(FilterInstance* i, DvsMenu* menu) { if (i->next) AddDeviceMenuItems(i->next, menu); if (i->dev->vtable->AddDeviceMenuItems) i->dev->vtable->AddDeviceMenuItems(i->dev, menu); } void MyDevice::StaticAddDeviceMenuItems(DvsDeviceUser* self, DvsMenu* menu) { AddDeviceMenuItems(((MyDevice*)self)->filter_instances, menu); } int MyDevice::StaticQueryUnplug(DvsDeviceUser* self) { int result = 0; for (FilterInstance* i = ((MyDevice*)self)->filter_instances; i; i = i->next) { if (i->dev->vtable->QueryUnplug) { result = i->dev->vtable->QueryUnplug(i->dev); if (result < 0) break; } } return result; } void MyDevice::StaticDelete(DvsDeviceUser* self) { FilterInstance* i = ((MyDevice*)self)->filter_instances; while (i) { if (i->dev->vtable->Delete) i->dev->vtable->Delete(i->dev); FilterInstance* j = i->next; delete i; i = j; } delete ((MyDevice*)self); } void MyDevice::Hook(Filter* f, DvsDeviceUser* user, DvsDeviceKernel** pkernel, DvsDockingBay* bay) { if (!f) return; Hook(f->next, user, pkernel, bay); DvsDeviceUser* old_user_device = filter_instances->dev; DvsDeviceUser* new_user_device = f->funcs->HookDevice(pkernel, bay); if (new_user_device != 0 && new_user_device != old_user_device) { FilterInstance* fi = new FilterInstance; fi->next = filter_instances; fi->dev = new_user_device; filter_instances = fi; } } MyDevice::MyDevice(DvsDeviceUser* user, DvsDeviceKernel** pkernel, DvsDockingBay* bay) { static DvsDeviceUser_vtable vt = { StaticAddDeviceMenuItems, StaticQueryUnplug, StaticDelete }; vtable = &vt; FilterSelectDialog(&active_filters, all_filters); filter_instances = new FilterInstance; filter_instances->next = 0; filter_instances->dev = user; Hook(active_filters, user, pkernel, bay); } class MyDockingBay : public DvsDockingBay { DvsDockingBay* child; public: MyDockingBay(DvsDockingBay* _child) { child = _child; static DvsDockingBay_vtable vt = { StaticSetHandlers, StaticRequestUnplug, StaticSharedPool_Alloc, StaticGetScsiID, StaticGetDriveLetters }; vtable = &vt; } void SetHandlers(DvsDeviceUser* user_handler, DvsDeviceKernel* kernel_handler) { DvsDeviceUser* my_user_handler = new MyDevice(user_handler, &kernel_handler, child); child->vtable->SetHandlers(child, my_user_handler, kernel_handler); } void RequestUnplug() { child->vtable->RequestUnplug(child); } void* SharedPool_Alloc(unsigned len) { return child->vtable->SharedPool_Alloc(child, len); } int GetScsiID() { return child->vtable->GetScsiID(child); } unsigned GetDriveLetters() { return child->vtable->GetDriveLetters(child); } static void StaticSetHandlers(DvsDockingBay* self, DvsDeviceUser* user_handler, DvsDeviceKernel* kernel_handler) { ((MyDockingBay*)self)->SetHandlers(user_handler, kernel_handler); } static void StaticRequestUnplug(DvsDockingBay* self) { ((MyDockingBay*)self)->RequestUnplug(); } static void* StaticSharedPool_Alloc(DvsDockingBay* self, unsigned len) { return ((MyDockingBay*)self)->SharedPool_Alloc(len); } static int StaticGetScsiID(DvsDockingBay* self) { return ((MyDockingBay*)self)->GetScsiID(); } static unsigned StaticGetDriveLetters(DvsDockingBay* self) { return ((MyDockingBay*)self)->GetDriveLetters(); } }; struct DvsDockingBay* HookDockingBay(DvsDockingBay* original_docking_bay) { return new MyDockingBay(original_docking_bay); } void LoadPlugins() { WIN32_FIND_DATA wfd; HANDLE h = FindFirstFile("*.dll", &wfd); if (h != INVALID_HANDLE_VALUE) { do { HMODULE hmod = LoadLibrary(wfd.cFileName); if (hmod != NULL) { typedef DvsFilterGlobal* __cdecl DFPE_func(DvsDockingBayGlobal*); DFPE_func* DvdsynthFilterPluginEntry = (DFPE_func*)GetProcAddress(hmod, "DvdsynthFilterPluginEntry"); if (DvdsynthFilterPluginEntry) { DvsFilterGlobal* plugin = DvdsynthFilterPluginEntry(g_callbacks); for (; plugin; plugin = plugin->next) { Filter* f = new Filter; f->next = all_filters; f->funcs = plugin; all_filters = f; } } else { FreeLibrary(hmod); } } } while (FindNextFile(h, &wfd)); FindClose(h); } } DvsDeviceGlobal plugin_functions = { 0, 0, 0, HookDockingBay }; extern "C" DvsDeviceGlobal* __cdecl DvdsynthDevicePluginEntry(DvsDockingBayGlobal* callbacks) { if (g_callbacks == 0) { g_callbacks = callbacks; LoadPlugins(); } return &plugin_functions; } extern "C" BOOL WINAPI DllMain(HINSTANCE hinst, DWORD, LPVOID) { g_hinstance = hinst; return TRUE; }