⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mirrordrive2k.cpp

📁 DVD工具dvdsynth的源码
💻 CPP
字号:
/***********************************************************************
 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 <http://www.gnu.org/copyleft/gpl.html>.
***********************************************************************/


#define WIN32_LEAN_AND_MEAN
#define _WIN32_IE 0x300
#include <windows.h>
#include <commctrl.h>
#include "resource.h"
#include "../include/dvdsynth-device.h"
#include "../dvdsynth2k/scsipt.h"
#include <stddef.h>
#include <stdio.h>


HINSTANCE g_hinstance;
DvsDockingBayGlobal* g_callback;

struct DeviceInfo {
   unsigned char port, path, target, lun;
   char devname[8];
   unsigned char type;
   char model[27];
};

const int MAX_DEVICES = 64;
DeviceInfo g_device_info[MAX_DEVICES];
int g_num_devices;

HWND g_hlistview;


scsi_result_t SendScsiCommand(HANDLE hdevice, const unsigned char* cdb, int cdblen, unsigned char* buffer, unsigned long* pbuflen, int inout, SenseData* sense) {
   SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
   memset(&swb, 0, sizeof(swb));
   swb.spt.Length = sizeof(SCSI_PASS_THROUGH);
   swb.spt.CdbLength = cdblen;
   swb.spt.DataIn = inout==1 ? SCSI_IOCTL_DATA_IN : inout==2 ? SCSI_IOCTL_DATA_OUT : SCSI_IOCTL_DATA_UNSPECIFIED;
   swb.spt.DataTransferLength = *pbuflen;
   swb.spt.TimeOutValue = 60;
   swb.spt.DataBuffer = swb.spt.DataTransferLength ? buffer : NULL;
   swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
   swb.spt.SenseInfoLength = 18;
   memcpy(swb.ucSenseBuf, sense, swb.spt.SenseInfoLength);
   memcpy(swb.spt.Cdb, cdb, cdblen);
   ULONG length = sizeof(swb);
   ULONG returned;
   if (DeviceIoControl(hdevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &swb, length, &swb, length, &returned, NULL)) {
      *pbuflen = swb.spt.DataTransferLength;
      memcpy(sense, swb.ucSenseBuf, swb.spt.SenseInfoLength);
      if (swb.spt.ScsiStatus) {
         return MAKE_SCSIRESULT(SRB_STATUS_ERROR, swb.spt.ScsiStatus, sense->sense_key, sense->asc, sense->ascq);
      } else {
         return SCSIRESULT_SUCCESS;
      }
   } else {
      DWORD error = GetLastError();
      UCHAR srb_status; // Why can't the damned ioctl return this???
      // It's impossible to recover the original value because many
      // different codes are collapsed into the same Win32 error. Is
      // this even worth it?
      switch (error) {
      case 37:
         srb_status = SRB_STATUS_INVALID_TARGET_ID;
         break;
      case 79:
         srb_status = SRB_STATUS_TIMEOUT;
         break;
      case 1167:
         srb_status = SRB_STATUS_SELECTION_TIMEOUT;
         break;
      default:
         printf("DeviceIoControl: got error %d\n", error);
         srb_status = SRB_STATUS_BUS_RESET;  // no clue here...
         break;
      }
      return MAKE_SCSIRESULT(srb_status, 0, 0, 0, 0);
   }
}


class MirrorInstance : public DvsDeviceUser, public DvsDeviceKernel {
   DvsDockingBay* bay;
   HANDLE hdevice;
   bool need_not_ready_to_ready;
public:
   MirrorInstance(DvsDockingBay* _bay, HANDLE _hdevice) {
      static DvsDeviceUser_vtable vt = {
         0,
         0,
         StaticDelete,
      };
      vtable = &vt;
      ScsiCommand = StaticScsiCommand;
      bay = _bay; hdevice = _hdevice;
      need_not_ready_to_ready = false;
   }
   ~MirrorInstance() {
      CloseHandle(hdevice);
   }

   scsi_result_t _ScsiCommand(const BYTE* cdb, int cdblen, unsigned char* buffer, unsigned long* pbuflen, int inout, SenseData* sense) {
      scsi_result_t result = SendScsiCommand(hdevice, cdb, cdblen, buffer, pbuflen, inout, sense);
      if (result == SCSIRESULT_SUCCESS) {
         if (need_not_ready_to_ready) {
            result = MAKE_SCSIRESULT_ERROR(0x62800);  // NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED
            need_not_ready_to_ready = false;
         }
      } else if (result == MAKE_SCSIRESULT_ERROR(0x62800)) {
         need_not_ready_to_ready = false;
      } else if ((result & 0xFFFFFF00) == MAKE_SCSIRESULT_ERROR(0x23A00)) {
         need_not_ready_to_ready = true;
      }
      return result;
   }
//   scsi_result_t ScsiCommand(const BYTE* cdb, int cdblen, unsigned char* buffer, unsigned long* pbuflen, int inout, SenseData* sense) {
//      return g_callback->SendScsiCommand(ha, targ, lun, cdb, cdblen, buffer, pbuflen, inout, sense);
//   }

   static void StaticDelete(DvsDeviceUser* self) {
      delete (MirrorInstance*)self;
   }

   static scsi_result_t StaticScsiCommand(DvsDeviceKernel* self, const BYTE* cdb, int cdblen, unsigned char* buffer, unsigned long* pbuflen, int inout, SenseData* sense) {
      return ((MirrorInstance*)self)->_ScsiCommand(cdb, cdblen, buffer, pbuflen, inout, sense);
   }
};


void SetModelField(char* dst, const unsigned char* src) {
   // copy vendor ID field
   memcpy(dst, src, 8);
   char* p;

   // lop off trailing spaces
   p = dst+8;
   while (p > dst && p[-1] == ' ')
      --p;

   // copy product ID field, with delimiting space
   *p++ = ' ';
   memcpy(p, src+8, 16);

   // lop off trailing spaces
   p += 16;
   while (p > dst && p[-1] == ' ')
      --p;
   *p = 0;
}


HANDLE OpenScsiDevice(const char* name) {
   char buf[32];
   wsprintf(buf, "\\\\.\\%s", name);
   return CreateFile(buf, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
}


void ScanDevice(const char* name) {
   if (g_num_devices >= MAX_DEVICES) return;
   HANDLE hdevice = OpenScsiDevice(name);
   if (hdevice == INVALID_HANDLE_VALUE) return;

   SCSI_ADDRESS sa;
   ULONG returned;
   memset(&sa, 0, sizeof(sa));
   if (!DeviceIoControl(hdevice, IOCTL_SCSI_GET_ADDRESS, NULL, 0, &sa, sizeof(sa), &returned, NULL)) {
      CloseHandle(hdevice);
      return;
   }

   for (int n=0; n<g_num_devices; ++n) {
      if (g_device_info[n].port == sa.PortNumber
       && g_device_info[n].path == sa.PathId
       && g_device_info[n].target == sa.TargetId
       && g_device_info[n].lun == sa.Lun)
      {
         CloseHandle(hdevice);
         return;
      }
   }

   static const unsigned char cdb_inquiry[6] = { 0x12, 0, 0, 0, 36, 0 };
   unsigned char inquiry_buf[36];
   memset(inquiry_buf, 0, sizeof(inquiry_buf));
   unsigned long buflen = 36;
   SenseData sense;
   if (SCSIRESULT_SUCCESS != SendScsiCommand(hdevice, cdb_inquiry, 6, inquiry_buf, &buflen, 1, &sense)) {
      CloseHandle(hdevice);
      return;
   }

   DeviceInfo& di = g_device_info[g_num_devices++];
   di.port = sa.PortNumber;
   di.path = sa.PathId;
   di.target = sa.TargetId;
   di.lun = sa.Lun;
   lstrcpy(di.devname, name);
   di.type = inquiry_buf[0];
   SetModelField(di.model, inquiry_buf+8);

   CloseHandle(hdevice);
}


void ScanForDevices() {
   // first try drive letters
   DWORD drive_mask = GetLogicalDrives();
   for (int i=2; i<26; ++i) {
      if (drive_mask & (1<<i)) {
         char buf[16];
         wsprintf(buf, "%c:\\", i + 'A');
         if (GetDriveType(buf) != DRIVE_REMOTE) {
            wsprintf(buf, "%c:", i + 'A');
            ScanDevice(buf);
         }
      }
   }
   // Next try CdromNN devices. On my system there were at one time
   // three such devices, numbered Cdrom0, Cdrom1 and Cdrom13. So I
   // guess I can't stop when I find a nonexistent one. :-(
   for (int j=0; j<100; ++j) {
      char buf[16];
      wsprintf(buf, "Cdrom%d", j);
      ScanDevice(buf);
   }
}
//   HWND hlv = (HWND)arg;
//        if (g_hlistview != hlv)
//            return;


void AddListViewColumn(HWND hlv, int index, const char* text, int width) {
   LVCOLUMN lvc;
   lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
   lvc.fmt = 0;
   lvc.cx = width;
   lvc.pszText = (LPTSTR)text;
   ListView_InsertColumn(hlv, index, &lvc);
}


BOOL NewInstanceDialog_InitDialog(HWND hdlg) {
   HWND hlist = GetDlgItem(hdlg, IDC_DEVICELIST);
   ListView_SetExtendedListViewStyle(hlist, LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP);
   // get the width of the list view and size its columns proportionally
   RECT r;
   GetClientRect(hlist, &r);
   unsigned width = r.right;
   unsigned divider1 = width*14/32;
   unsigned divider2 = width*21/32;
   unsigned divider3 = width*27/32;
   AddListViewColumn(hlist, 0, "Make and model", divider1);
   AddListViewColumn(hlist, 1, "Type", divider2-divider1);
   AddListViewColumn(hlist, 2, "Name", divider3-divider2);
   AddListViewColumn(hlist, 3, "Address", width-divider3);
   g_hlistview = hlist;
   g_num_devices = 0;
   ScanForDevices();
   ListView_SetItemCount(hlist, g_num_devices);
   return TRUE;
}


int GetLVSelection(HWND hlv) {
   return ListView_GetNextItem(hlv, (unsigned)-1, LVNI_SELECTED);
}


const char* scsi_device_type[] = {
   "Disk drive",
   "Tape drive",
   "Printer",
   "Processor",
   "WORM drive",
   "CD/DVD drive",
   "Scanner",
   "Optical drive",
   "Medium changer",
   "Network device",
   "ASCIT8",
   "ASCIT8",
   "Array",
   "Enclosure",
   "RBC",
   "Card reader",
   "Bridge"
};


void GetDispInfo(LVITEM* plvi) {
   if (!(plvi->mask & LVIF_TEXT))
      return;
   int i = plvi->iItem, c = plvi->iSubItem;
   if (i < 0 || i >= g_num_devices || i >= MAX_DEVICES)
      return;

   char buf[32];
   const char* text;

   const DeviceInfo& di = g_device_info[i];

   switch (c) {
   case 0:
      text = di.model;
      break;
   case 1:
      if (di.type <= sizeof(scsi_device_type)/sizeof(scsi_device_type[0])) {
         text = scsi_device_type[di.type];
      } else {
         wsprintf(buf, "unknown (0x%02X)", di.type);
         text = buf;
      }
      break;
   case 2:
      text = di.devname;
      break;
   case 3:
      if (di.path) {
         wsprintf(buf, "%d.%d:%d:%d", di.port, di.path, di.target, di.lun);
      } else {
         wsprintf(buf, "%d:%d:%d", di.port, di.target, di.lun);
      }
      text = buf;
      break;
   default:
      return;
   }

   lstrcpyn(plvi->pszText, text, plvi->cchTextMax);
   plvi->pszText[plvi->cchTextMax-1] = 0;
}

BOOL CALLBACK NewInstanceDialogProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) {
   switch (msg) {
   case WM_INITDIALOG:
      return NewInstanceDialog_InitDialog(hdlg);
   case WM_COMMAND:
      switch (LOWORD(wparam)) {
      case IDOK:
         EndDialog(hdlg, GetLVSelection(GetDlgItem(hdlg, IDC_DEVICELIST)));
         return TRUE;
      case IDCANCEL:
         EndDialog(hdlg, -1);
         return TRUE;
      }
      break;
   case WM_NOTIFY:
      if (wparam == IDC_DEVICELIST) {
         LPNMHDR pnmh = (LPNMHDR)lparam;
         if (pnmh->code == LVN_GETDISPINFO) {
            GetDispInfo(&((LV_DISPINFO*)pnmh)->item);
            return TRUE;
         } else if (pnmh->code == LVN_ITEMCHANGED) {
            EnableWindow(GetDlgItem(hdlg, IDOK), ListView_GetSelectedCount(pnmh->hwndFrom));
            return TRUE;
         } else if (pnmh->code == LVN_ITEMACTIVATE) {
            EndDialog(hdlg, GetLVSelection(GetDlgItem(hdlg, IDC_DEVICELIST)));
            return TRUE;
         }
      }
      break;
   }
   return FALSE;
}


void CreateNewInstance(void*, int) {
   DvsDockingBay* bay = g_callback->ReserveDockingBay();
   if (!bay) return;
   int selection = DialogBox(g_hinstance, MAKEINTRESOURCE(IDD_CHOOSEDEVICE), NULL, NewInstanceDialogProc);
   if (selection >= 0 && selection < g_num_devices) {
      HANDLE hdevice = OpenScsiDevice(g_device_info[selection].devname);
      if (hdevice != INVALID_HANDLE_VALUE) {
         MirrorInstance* instance = new MirrorInstance(bay, hdevice);
         bay->vtable->SetHandlers(bay, instance, instance);
      } else {
         MessageBox(NULL, "Unable to connect to the drive!", "Mirror Drive", MB_OK);
      }
   }
}


void AddNewMenuItems(DvsMenu* menu) {
   menu->vtable->AddItem(menu, "Mirror Drive", false, CreateNewInstance, 0, 0);
}

void AddAboutMenuItems(DvsMenu* menu) {}


DvsDeviceGlobal global_funcs = {
   AddNewMenuItems,
   AddAboutMenuItems,
   0,//AddMainMenuItems,
   0
};


extern "C"
DvsDeviceGlobal* DvdsynthDevicePluginEntry(DvsDockingBayGlobal* bays) {
   if (bays->Is95())
      return 0;
   g_callback = bays;
   return &global_funcs;
}


extern "C"
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID) {
   g_hinstance = hinst;
   return TRUE;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -