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

📄 miniport.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 STRICT
#include <windows.h>

#include "miniport.h"
#include "aspi.h"
#include "../dvdproxy95/dvdproxy95.h"
#include "../include/dvdsynth-plugin.h"
#include "SharedPool.h"


/*******************************************************************\
\*******************************************************************/

#include <stdio.h>

extern DvsBasePluginCallbacks* g_callbacks;


/*******************************************************************\
\*******************************************************************/


// ASPI is only used to send DVDPROXY_CMD_THUNK_CALL requests to the
// kernel driver. I wish I could avoid this, but there doesn't seem to
// be any way to contact a SCSI miniport driver from ring 3 except by
// sending SCSI commands.

namespace ASPI {

   const SenseData default_sense = { 0x70, 0, 0, {0,0,0,0}, 10, {0,0,0,0}, 0, 0, 0, {0,0,0} };

   DWORD (*SendASPI32Command)(LPSRB) = 0;

   int dvdsynth_ha_id = -1;
   enum { dvdsynth_targ_id = 0 };

   scsi_result_t SendSCSICommand(int ha, int targ, int lun, const unsigned char* cdb, int cdblen, unsigned char* buffer, unsigned long* pbuflen, int inout, SenseData* sense) {
      // Creating a new event for each call seems wasteful, but I'd
      // rather that this function be thread-safe.
      HANDLE hCompleted = CreateEvent(NULL, TRUE, FALSE, NULL);
      SRB_ExecSCSICmd srb;
      memset(&srb, 0, sizeof(srb));
      srb.SRB_Cmd = SC_EXEC_SCSI_CMD;
      srb.SRB_HaId = ha;
      srb.SRB_Flags = SRB_EVENT_NOTIFY + SRB_ENABLE_RESIDUAL_COUNT + (inout==1 ? SRB_DIR_IN : inout==2 ? SRB_DIR_OUT : SRB_DIR_SCSI);
      srb.SRB_Target = targ;
      srb.SRB_Lun = lun;
      srb.SRB_BufLen = *pbuflen;
      srb.SRB_BufPointer = buffer;
      srb.SRB_SenseLen = 16;
      srb.SRB_CDBLen = cdblen;
      memcpy(srb.CDBByte, cdb, cdblen);
      srb.SRB_PostProc = hCompleted;
      if (SS_PENDING == SendASPI32Command(&srb)) {
         WaitForSingleObject(hCompleted, INFINITE);
      }
      CloseHandle(hCompleted);
      *pbuflen -= srb.SRB_BufLen;
      *sense = default_sense;
      memcpy(sense, srb.SenseArea, srb.SRB_SenseLen);

      return MAKE_SCSIRESULT(srb.SRB_Status, srb.SRB_TargStat, sense->sense_key, sense->asc, sense->ascq);
   }

   int GetHATargetMax(int ha) {
      SRB_HAInquiry srb;
      memset(&srb, 0, sizeof(srb));
      srb.SRB_Cmd = SC_HA_INQUIRY;
      srb.SRB_HaId = ha;
      SendASPI32Command(&srb);
      if (srb.SRB_Status != SS_COMP) {
         return 0;
      } else {
         return max(8, srb.HA_Unique[3]);
      }
   }

   int Init() {
      // Initialize ASPI
      HMODULE hASPI = LoadLibrary("wnaspi32.dll");
      if (!hASPI)
         return -1;

      DWORD (*GetASPI32SupportInfo)();

      GetASPI32SupportInfo = (DWORD (*)()) GetProcAddress(hASPI, "GetASPI32SupportInfo");
      SendASPI32Command = (DWORD (*)(LPSRB)) GetProcAddress(hASPI, "SendASPI32Command");
      if (GetASPI32SupportInfo == 0 || SendASPI32Command == 0)
         return -2;

      DWORD rtn = GetASPI32SupportInfo();
      if ((rtn & 0xFF00) != (SS_COMP * 256) || (rtn & 0xFF) == 0)
         return -3;

      int num_host_adapters = rtn & 0xFF;

      // Scan for the DVDSynth miniport by comparing INQUIRY data
      static const unsigned char cdb_inquiry[6] = { 0x12, 0, 0, 0, 36, 0 };
      for (int i=0; i<num_host_adapters; ++i) {
         unsigned char buf[36];
         memset(buf, 0xEE, 36);
         unsigned long buflen = 36;
         SenseData sense;
         if (SendSCSICommand(i, dvdsynth_targ_id, 0, cdb_inquiry, 6, buf, &buflen, 1, &sense) == SCSIRESULT_SUCCESS
            && memcmp(buf, dvdproxy_device_inquiry_data, 36) == 0)
         {
            dvdsynth_ha_id = i;
            return 0;
         }
      }
      MessageBox(NULL, "DVDProxy device not found.", "DVDSynth", MB_OK);
      return -4;
   }

   inline scsi_result_t SendMiniportCommand(const unsigned char* cdb, const void* buf, unsigned long buflen, int inout, SenseData* sense) {
      return ASPI::SendSCSICommand(dvdsynth_ha_id, dvdsynth_targ_id, 0, (BYTE*)cdb, 12, (BYTE*)buf, &buflen, inout, sense);
   }

/*
   unsigned char ASPIStatusToSRBStatus(unsigned char aspi_srb_status, unsigned char aspi_ha_status) {
      if (aspi_srb_status == SS_COMP) {
         // note: can get SS_COMP with HASTAT_DO_DU (data overrun/underrun) -- handle specially?
         return SRB_STATUS_SUCCESS;
      } else if (aspi_srb_status == SS_ERR) {
         if (aspi_ha_status == 0)
            return SRB_STATUS_ERROR;
         else if (aspi_ha_status == 0x11)
            return SRB_STATUS_SELECTION_TIMEOUT;
         else
            return aspi_ha_status;
      } else if (aspi_srb_status == SS_ABORTED || aspi_srb_status == SS_ABORT_FAIL) {
         return aspi_srb_status;
      } else if (aspi_srb_status >= SS_INVALID_CMD && aspi_srb_status <= SS_NO_DEVICE) {
         return aspi_srb_status - SS_INVALID_CMD + SRB_STATUS_INVALID_REQUEST;
      } else if (aspi_srb_status == SS_INVALID_SRB) {
         // SS_INVALID_SRB is returned for several different errors.
         // I'm assuming no one checks these codes too closely...
         return SRB_STATUS_INVALID_TARGET_ID;
      } else {
         return SRB_STATUS_BAD_FUNCTION;     // ???
      }
   }
*/

}


/*******************************************************************\
\*******************************************************************/


namespace Miniport {


void Hello() {
   static const CDB_Dvdproxy cdb = { DVDPROXY_SCSIOP, DVDPROXY_VERSION, DVDPROXY_CMD_HELLO };
   SenseData sense;
   scsi_result_t result = ASPI::SendMiniportCommand((const unsigned char*)&cdb, "", 0, 1, &sense);
}


void* DriverCall(void* module, const char* entry_name, const char* types, ...) {

   bool numerical_export = (unsigned(entry_name) < 65536);

   const char* printable_entry_name = entry_name;
   char printable_entry_name_buf[16];

   if (numerical_export) {
      g_callbacks->Sprint(printable_entry_name_buf, 16, "#%1", "d", entry_name);
      printable_entry_name = printable_entry_name_buf;
   }

   enum { max_args=16 };

   int num_args = strspn(types, "ips&<>E");
   if (types[num_args] != 0) {
      char buf[256];
      g_callbacks->Sprint(buf, 256, "\"%1\" had an argument of an unrecognized type (\"%2\").", "sc", entry_name, types[num_args]);
      MessageBox(NULL, buf, "DVDSynth", MB_OK);
   }

   if (num_args > max_args) {
      char buf[256];
      g_callbacks->Sprint(buf, 256, "DriverCall invoked with %1 arguments (max %2)", "dd", num_args, max_args);
      MessageBox(NULL, buf, "DVDSynth", MB_OK);
      return 0;
   }

   // get args
   void* args[max_args];
   void* original_args[max_args];
   {
      va_list val;
      va_start(val, types);
      for (int i=0; i<num_args; ++i) {
         // I'm assuming void* and int take the same amount of stack space...
         original_args[i] = args[i] = va_arg(val, void*);

         // also check for invalid buffer length while I'm at it
         if ((types[i] == '<' && i == 0)
          || (types[i] == '<' && types[i-1] != 'i' && types[i-1] != '&')
          || (types[i] == '>' && types[i+1] != 'i' && types[i+1] != '&'))
         {
            char buf[256];
            g_callbacks->Sprint(buf, 256, "DriverCall type '<' or '>' does not point to integer argument (in call of \"%1\" with args \"%2\")",
               0, printable_entry_name, types);
            MessageBox(NULL, buf, "DVDSynth", MB_OK);
            return 0;
         }
      }
      va_end(val);
   }

   // determine shared memory space needed
   bool need_pool = !numerical_export;
   unsigned object_sizes[max_args];

   for (int i=0; i<num_args; ++i) {
      unsigned object_size = 0;
      // Don't translate pointers in the range 0-65535; they probably
      // don't point to anything. And don't translate pointers with the
      // high bit set; either they don't point to anything or they
      // already point to a buffer in the system area.
      if (signed(args[i]) >= 65536) {
         switch (types[i]) {
         case '&':
            object_size = 4;
            break;
         case '<':
            object_size = (types[i-1] == '&') ? *(unsigned*)args[i-1] : (unsigned)args[i-1];
            break;
         case '>':
            object_size = (types[i+1] == '&') ? *(unsigned*)args[i+1] : (unsigned)args[i+1];
            break;
         case 's':
            object_size = lstrlen((const char*)args[i]) + 1;
            break;
         }
      }
      object_sizes[i] = object_size;
      if (object_size > 0) {
         need_pool = true;
      }
   }

   // NB: the SharedPool_* functions sometimes call DriverCall recursively.
   // But none of these calls requires the use of buffer_pool, so infinite
   // recursion is avoided by creating/using buffer_pool only when it's needed.

   static void* buffer_pool;

   if (need_pool) {
      if (buffer_pool == 0) {
         buffer_pool = SharedPool_Create(true);
      }
      if (!numerical_export) {
         int len = lstrlen(entry_name)+1;
         char* buf = (char*)SharedPool_Alloc(buffer_pool, len);
         memcpy(buf, entry_name, len);
         entry_name = buf;
      }
      for (int i=0; i<num_args; ++i) {
         if (object_sizes[i]) {
            args[i] = SharedPool_Alloc(buffer_pool, object_sizes[i]);
            memcpy(args[i], original_args[i], object_sizes[i]);
         }
      }
   }

   // set up the CDB
   CDB_Thunk_Call cdb;
   cdb.opcode = DVDPROXY_SCSIOP;
   cdb.version = DVDPROXY_VERSION;
   cdb.cmd = DVDPROXY_CMD_THUNK_CALL;
   cdb.reserved = 0;
   cdb.hmodule = module;
   cdb.export_name = entry_name;

   // send the SCSI command
   SenseData sense;
   scsi_result_t result = ASPI::SendMiniportCommand((const unsigned char*)&cdb, args, num_args*sizeof(void*), 2, &sense);

   // update buffers
   if (need_pool) {
      // copy the data back
      for (int i=0; i<num_args; ++i) {
         if (object_sizes[i] && types[i] != 's') {
            memcpy(original_args[i], args[i], object_sizes[i]);
         }
      }
      SharedPool_Clear(buffer_pool);
   }

   // unpack return value
   if (result == MAKE_SCSIRESULT_ERROR(DVDPROXY_ERROR_THUNK_CALL_SUCCEEDED)) {
      return *(void**)&sense.command_specific;
   } else if (result == MAKE_SCSIRESULT_ERROR(DVDPROXY_ERROR_EXPORT_NOT_FOUND)) {
      char buf[256];
      g_callbacks->Sprint(buf, 256, "Call to driver-exported function \"%1\" failed: the function was not found.", 0, entry_name);
      MessageBox(NULL, buf, "DVDSynth", MB_OK);
      return 0;
   } else {
      char buf[256];
      g_callbacks->Sprint(buf, 256, "Call to driver-exported function \"%1\" failed with error code %2.\n\nPlease report this as a DVDSynth bug.", "sX", entry_name, result);
      MessageBox(NULL, buf, "DVDSynth", MB_OK);
      return 0;
   }
}


int Init() {
   int aspi_init_result = ASPI::Init();
   if (aspi_init_result != 0)
      return aspi_init_result;
   Hello();
   DriverCall(miniport_handle, (char*)mpdfunc_Init, "p", g_callbacks->GetTaskbarHWND());
   return 0;
}


}

⌨️ 快捷键说明

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