2019/07/25

Video and Graphic windows driver 驅動程式開發筆記

* 前情提要之本文另一篇: Windows Driver 開發學習筆記
* Graphic driver要了解一下
* Umd kmd 基本概念要懂
* 會寫程式 XD

關於 WDF 、WDK、WDM、DDK 介紹

(轉自: DDK與WDK的區別與聯繫)
最近嘗試去了解WINDOWS下的驅動開發,現在總結一下最近看到的資料。

1. 專門的開發包

首先,先從基礎的東西說起,開發WINDOWS下的驅動程序,需要一個專門的開發包
如:

  • 開發 JAVA 程序,我們可能需要一個JDK
  • 開發 WINDOWS 應用程式(Applications),我們需要WINDOWS的SDK
  • 開發 WINDOWS 下的驅動程序(Drivers),我們需要一個DDK/WDK。

2. DDK(Driver Developer Kit)和 WDK(Windows Driver Kit)的區別:

這個要說說驅動相關的一些歷史:

  • (1). 95/98/ME下,驅動模型為:Vxd, 相關資料可以看《編程高手箴言》的前幾個章節,裡面有很詳細的介紹,雖然這個東西已經過時,但大概看看還是會增長見識的。
  • (2). 2000/XP/2003下,Windows採用WDM驅動模型(Windows Driver Model),開發2000/XP/2003的驅動開發包為:DDK。
  • (3). Vista及以後版本,採用了WDF驅動模型(Windows Driver Foudation),對應的開發包:WDK。

其實WDK可以看做是DDK的升級版本,現在一般的WDK是包含以前DDK相關的功能,現在XP下也可以用WDK開發驅動,WDK能編譯出2000-2008的各種驅動。

3. 副檔名的區別

  • Vxd驅動文件擴展名為:.vxd。
  • WDM和WDF驅動文件擴展名為:.sys。

4. 相關的名詞解釋

  • DDK——Driver Developer Kit,設備驅動程序開發包。
  • WDK——Windows Driver Kit,Windows驅動程序開發包,就是DDK升級改名了。
  • VxD——Virtual Device Driver,虛擬設備驅動程序,9X中的一種驅動程序。
  • WDM——Windows Driver Model,Windows驅動程序模型,98以上版本的一種驅動程序。
  • WDF——Windows Driver Frameworks, 驅動程序包括兩個類型,一個是內核級的,稱為KMDF(Kernel-Mode Driver Framework),為SYS文件;另一個是用戶級的,稱為UMDF(User-Mode Driver Framework),為DLL文件。
  • 驅動程序的文件格式都是PE格式。

windows驅動開發: 比較 WDM 與 WDF

(轉載自 yinaiyun52)

如所周知,自Windows 2000開始,開發驅動程序必以WDM為基礎的,但其開發難度之大,根本不能奢望像用戶模式應用程序開發那樣容易。為改善這種局面,微軟推出了新的驅動程序開發環境 – WDF驅動模型。

WDF驅動框架對WDM進行了一次封裝
WDF框架就好像C++中的基類一樣,且這個基類中的model, IO model ,pnp和電源管理模型;且提供了一些與操作系統相關的處理函數,這些函數好像C++中的虛函數一樣,WDF驅動中能夠對這些函數進行override;特別是Pnp管理和電源管理!基本上都由WDF框架做了,而WDF的功能驅動幾乎不要對它進行特殊的處理;

要預先指出的是,WDF這不是另起爐灶改弦更張,而是以WDM為基礎進行了建模和封裝,顯著特點是降低了開發難度。
因為:
1、 將原來普通程序設計中基於對象的技術應用到了驅動開發中。 WDM中雖也有對像模型,但與真正的基於對象技術根本就不是一回事。為了實現基於對象的技術,微軟精心設計了對像模型並進行了封裝。屬性、方法、事件等等“一個都不能少”。

2、 無論內核模式的驅動程序或者用戶模式的驅動程序,都採用同一套對像模型構建,採用同一個基礎承載。這個基礎就是WDF。 WDF雖然已經是經過封裝和定義的對像模型,但對內核模式和用戶模式對象來說,WDF又是兩者的父對象。換言之兩者都是繼承了WDF才得到的,或者都是從WDF派生而來的。相對於內核模式,派生出的對象稱為“KMD框架”即KMDF;相對於用戶模式,派生出的模型稱為“UMD框架”即UMDF。無論何種模式的框架,其內部封裝的方法、執行的行為其實還是用WDM完成的。

3、 更重要的,也是微軟反复炫耀的是封裝了驅動程序中的某些共同行為:例如即插即用和電源管理就屬於這種共同行為。因為大多數驅動程序中都需要處理即插即用和電源管理問題,據說這大概要上千行的代碼,況且,沒有相當水平還不一定能處理好。為了一勞永逸,WDF乾脆將即插即用和電源管理封裝了進了對象之內,一舉成了對象的缺省(默認)行為。

4、 改變了操作系統內核與驅動程序之間的關係,WDM驅動程序中,一方面要處理硬件,另一方面要處理驅動程序與操作系統內核的交互。現在WDF則將驅動程序與操作系統內核之間進行了分離,驅動程序與操作系統交互工作交給框架內封裝的方法(函數)完成,這樣驅動開發者只需專注處理硬件的行為即可。這不僅避免了顧此失彼兩面不周的弊端,也由於雙方的分離,對操作系統內的某些改動,硬件製造商配套驅動程序的開發都有莫大的好處。

5、 兩種模式的驅動程序(KMDF、UMDF)都使用同一環境進行構建,這一環境稱為WDK。
即KMDF,UMDF的開發環境為WDK。
Windows Device Kit (WDK): 把測試套件(test suites)集成進來,DDK 就成了WDK。 WDK是針對微軟操作系統系列的驅動器集成開發系統。它組合了Windows DDK和Hardware Compatibility Test (HCT) kits(硬件兼容性測試工具),同時提供了微軟內部用來測試Windows操作系統穩定性和可靠性的測試套件。

6、 雖然經過封裝並引入基於對象的技術,所開發的驅動程序在執行效率上並不比原來遜色。
WDF和WDM的關係有點類似於MFC和Windows SDK的關係。 WDF只是在WDM上面加了一層,來簡化driver的開發,特別是PNP,power和IO cancellation 等幾個方面有很大改進。

現在學習WDF最好的資料還是DDK帶的sample code。 WHDC有一些資料:
http://www.microsoft.com/whdc/driver/wdf/default.mspx

再繼續說新舊時代

關鍵的visual studio 2012, 新時代忽然就來了, VS2012是Win8發布之後才出來的,有很多針對Win8的特性,但也能在Win7/Vista系統上運行。

舊時代

近期的win8與win10的系統出現以前, 也就是含win7之前的系統, 如果要開發kernel/driver的驅動程式, 環境的準備比較繁瑣, 首先需要手動下載WDK並安裝, 因為開發環境是在安裝好的WDK當中。WDK是Windows Driver Kit縮寫,即Windows驅動開發包。它提供的開發環境非常簡陋,不是一個便於開發的IDE環境,而僅僅是一些散裝的編譯工具包。

新時代

基本上必須要安裝三個軟體:
1. 我這裡使用 visual studio 2015版本 (或2012之後的版本)
2. WDK 10 (或Win8之後的版本)
3. Win10 SDK

請您先下載安裝 VS2015, 再安裝 Win10 的 WDK, 然後WDK的編譯環境就會自動整合進去 VS2015裡面, 所以重新開啟VS2015的時候, 在new project 新項目嚮導裡面, 就能夠找到driver(內核驅動)項目了。

開啟 Visual Studio 2015,選擇 New Project 建立新專案:
選擇 Visual C++ > Windows Driver > WDF

跳出的分別是有自動生成代碼的KMDF和沒有自動代碼的KMDF(empty),以及UMDF
我們選擇 Kernel Mode Driver (KMDF),直接按 OK 用預設值建立一個簡單的 driver 專案

測試安裝好的 Visual Studio 2015 + Windows SDK 10 + Windows Driver Kit 10
正常的話, 可以編譯通過successfully!

微軟釋出的 Driver samples for Windows 10 – 擷取video 部分

網址: https://github.com/microsoft/Windows-driver-samples/tree/master/video/KMDOD
目前我使用的為visual studio 2015 + (WinSDK)Windows Software Development kit 10.0.14393.33 + (WDK)Windows Driver kit 10.0.14393.0

資源指令碼檔案 .rc
包含目前專案中的資源所適用之指令碼的資源指令碼檔。 .aps 檔會在您每次存檔時覆寫此檔案。
原始檔控制中包含此檔案。

/*++Copyright (c) 2011 Microsoft CorporationModule Name:    SampleDisplay.rcAbstract:    This modules contains the version information for the Sample Display DriverEnvironment:    Kernel mode only--*/#include #include #define VER_FILETYPE                VFT_DRV#define VER_FILESUBTYPE             VFT2_DRV_DISPLAY#define VER_FILEDESCRIPTION_STR     "Microsoft Sample Display Driver"#define VER_INTERNALNAME_STR        "SampleDisplay.sys"#define VER_ORIGINALFILENAME_STR    "SampleDisplay.sys"#define VER_LANGNEUTRAL#include "common.ver"

驅動程式檔案 .inf
.INF是 Device Information File 的縮寫,是微軟為供硬體製造商散佈其設備驅動程式而發展, .INF 檔是一種具有特定格式的純文字檔,我們可說它是種安裝腳本檔(Setup Script)。為甚麼當我們在檔案總管對 .INF 檔按右鍵後,快顯功能表會出現「安裝」指令呢? 這是因為微軟已在其作業系統 Windows 中提供了 Setup API(註一),程式設計師只需用任何文書編輯軟體撰寫 .INF 檔,便可完成大部份的安裝工作。

;++;; Copyright (c) 2011 Microsoft Corporation;; Module Name:;;    SampleDisplay.inf;; Abstract:;;    Inf file for Kernel mode display only sample driver;;--[Version]Signature = "$Windows NT$"Class=DisplayClassGUID={4d36e968-e325-11ce-bfc1-08002be10318}Provider=%ProviderString%DriverVer= 03/15/2011, 0.03.15.0011CatalogFile=SampleDisplay.cat[DestinationDirs]KDODSamp.Files = 12[SourceDisksNames]0=%SampleDisk%[SourceDisksFiles]SampleDisplay.sys=0[Manufacturer]%ManufacturerName%=Standard,NTx86,NTamd64,NTarm,NTarm64;;    Allow the driver to be loaded on VGA and XGA exposed by PCI bus and ACPI;[Standard.NTx86]%SampleDeviceName% = KDODSamp_Inst, PCI\CC_0300%SampleDeviceName% = KDODSamp_Inst, PCI\CC_0301%SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0000%SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0001[Standard.NTamd64]%SampleDeviceName% = KDODSamp_Inst, PCI\CC_0300%SampleDeviceName% = KDODSamp_Inst, PCI\CC_0301%SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0000%SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0001[Standard.NTarm]%SampleDeviceName% = KDODSamp_Inst, PCI\CC_0300%SampleDeviceName% = KDODSamp_Inst, PCI\CC_0301%SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0000%SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0001[Standard.NTarm64]%SampleDeviceName% = KDODSamp_Inst, PCI\CC_0300%SampleDeviceName% = KDODSamp_Inst, PCI\CC_0301%SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0000%SampleDeviceName% = KDODSamp_Inst, ACPI\CLS_0003&SUBCLS_0001[KDODSamp_Inst]FeatureScore=F9CopyFiles = KDODSamp.Files;;   Install driver service;[KDODSamp_Inst.Services]AddService = KDODSamp,0x00000002,KDODSamp_Service_Inst,KDODSamp_EventLog_Inst[KDODSamp_Service_Inst]ServiceType = %SERVICE_KERNEL_DRIVER%StartType = %SERVICE_DEMAND_START%ErrorControl = %SERVICE_ERROR_IGNORE%ServiceBinary = %12%\SampleDisplay.sys;;   Display Adapter Specific Settings;[KDODSamp.Files]SampleDisplay.sys[KDODSamp_EventLog_Inst]AddReg = KDODSamp_EventLog_Inst.AddReg[KDODSamp_EventLog_Inst.AddReg]HKR,,EventMessageFile,%REG_EXPAND_SZ%,"%%SystemRoot%%\System32\IoLogMsg.dll"HKR,,TypesSupported,%REG_DWORD%,7[Strings];  *******Localizable Strings*******ProviderString="TODO-Set-Provider"ManufacturerName="TODO-Set-Manufacturer"SampleDisk = "Sample Disk"SampleDeviceName = "Kernel mode display only sample driver";  *******Non Localizable Strings*******SERVICE_BOOT_START = 0x0SERVICE_SYSTEM_START = 0x1SERVICE_AUTO_START = 0x2SERVICE_DEMAND_START = 0x3SERVICE_DISABLED = 0x4SERVICE_KERNEL_DRIVER = 0x1SERVICE_ERROR_IGNORE = 0x0SERVICE_ERROR_NORMAL = 0x1SERVICE_ERROR_SEVERE = 0x2SERVICE_ERROR_CRITICAL = 0x3REG_MULTI_SZ   = 0x00010000REG_EXPAND_SZ = 0x00020000REG_DWORD = 0x00010001

C++程式標頭檔案 bdd.hxx

/******************************Module*Header*******************************\* Module Name: BDD.hxx** Basic Display Driver header file*** Copyright (c) 2010 Microsoft Corporation\**************************************************************************/#ifndef _BDD_HXX_#define _BDD_HXX_extern "C"{    #define __CPLUSPLUS    // Standard C-runtime headers    #include     #include     #include     #include     #include     #include     // NTOS headers    #include     #ifndef FAR    #define FAR    #endif    // Windows headers    #include     #include     // Windows GDI headers    #include     // Windows DDI headers    #include     #include     #include     #include     #include     #include     #include };#define EDID_V1_BLOCK_SIZE 128#include "BDD_ErrorLog.hxx"#define MIN_WIDTH                    640#define MIN_HEIGHT                   480#define MIN_BITS_PER_PIXEL_ALLOWED     8#define MIN_BYTES_PER_PIXEL_REPORTED   4#define DEFAULT_WIDTH               1024#define DEFAULT_HEIGHT               768#define MAX_INVALID_INHERITED_WIDTH 1024#define MAX_INVALID_INHERITED_HEIGHT 768#define BITS_PER_BYTE                  8typedef struct _BLT_INFO{    PVOID pBits;    UINT Pitch;    UINT BitsPerPel;    POINT Offset; // To unrotated top-left of dirty rects    D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation;    UINT Width; // For the unrotated image    UINT Height; // For the unrotated image} BLT_INFO;#define MAX_CHILDREN                   1#define MAX_VIEWS                      1typedef struct _BDD_FLAGS{    UINT DriverStarted           : 1; // ( 1) 1 after StartDevice and 0 after StopDevice    UINT EDID_Retrieved          : 1; // ( 2) EDID was successfully retrieved    UINT EDID_ValidChecksum      : 1; // ( 3) Retrieved EDID has a valid checksum    UINT EDID_ValidHeader        : 1; // ( 4) Retrieved EDID has a valid header    UINT EDID_Attempted          : 1; // ( 5) 1 if an attempt was made to retrieve the EDID, successful or not    // IMPORTANT: All new flags must be added to just before _LastFlag (i.e. right above this comment), this allows different versions of diagnostics to still be useful.    UINT _LastFlag               : 1; // ( 6) Always set to 1, is used to ensure that diagnostic version matches binary version    UINT Unused                  : 26;} BDD_FLAGS;// Represents the current mode, may not always be set (i.e. frame buffer mapped) if representing the mode passed in on single mode setups.typedef struct _CURRENT_BDD_MODE{    // The source mode currently set for HW Framebuffer    // For sample driver this info filled in StartDevice by the OS and never changed.    DXGK_DISPLAY_INFORMATION             DispInfo;    // The rotation of the current mode. Rotation is performed in software during Present call    D3DKMDT_VIDPN_PRESENT_PATH_ROTATION  Rotation;    D3DKMDT_VIDPN_PRESENT_PATH_SCALING Scaling;    // This mode might be different from one which are supported for HW frame buffer    // Scaling/displasment might be needed (if supported)    UINT SrcModeWidth;    UINT SrcModeHeight;    // Various boolean flags the struct uses    struct _CURRENT_BDD_MODE_FLAGS    {        UINT SourceNotVisible     : 1; // 0 if source is visible        UINT FullscreenPresent    : 1; // 0 if should use dirty rects for present        UINT FrameBufferIsActive  : 1; // 0 if not currently active (i.e. target not connected to source)        UINT DoNotMapOrUnmap      : 1; // 1 if the FrameBuffer should not be (un)mapped during normal execution        UINT IsInternal           : 1; // 1 if it was determined (i.e. through ACPI) that an internal panel is being driven        UINT Unused               : 27;    } Flags;    // The start and end of physical memory known to be all zeroes. Used to optimize the BlackOutScreen function to not write    // zeroes to memory already known to be zero. (Physical address is located in DispInfo)    PHYSICAL_ADDRESS ZeroedOutStart;    PHYSICAL_ADDRESS ZeroedOutEnd;    // Linear frame buffer pointer    // A union with a ULONG64 is used here to ensure this struct looks the same on 32bit and 64bit builds    // since the size of a VOID* changes depending on the build.    union    {        VOID*                            Ptr;        ULONG64                          Force8Bytes;    } FrameBuffer;} CURRENT_BDD_MODE;class BASIC_DISPLAY_DRIVER;class BDD_HWBLT{public:    D3DDDI_VIDEO_PRESENT_SOURCE_ID  m_SourceId;    BASIC_DISPLAY_DRIVER*           m_DevExt;    BOOLEAN                         m_SynchExecution;    HANDLE                          m_hPresentWorkerThread;    PVOID                           m_pPresentWorkerThread;    //  Events to contol thread execution    KEVENT                          m_hThreadStartupEvent;    KEVENT                          m_hThreadSuspendEvent;    BDD_HWBLT();    ~BDD_HWBLT();    void Initialize(_In_ BASIC_DISPLAY_DRIVER* DevExt, _In_ UINT IdSrc) { m_DevExt = DevExt; m_SourceId = IdSrc; }    void SetPresentWorkerThreadInfo(HANDLE hWorkerThread);    NTSTATUS ExecutePresentDisplayOnly(_In_ BYTE*             DstAddr,                                       _In_ UINT              DstBitPerPixel,                                       _In_ BYTE*             SrcAddr,                                       _In_ UINT              SrcBytesPerPixel,                                       _In_ LONG              SrcPitch,                                       _In_ ULONG             NumMoves,                                       _In_ D3DKMT_MOVE_RECT* pMoves,                                       _In_ ULONG             NumDirtyRects,                                       _In_ RECT*             pDirtyRect,                                       _In_ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation);};class BASIC_DISPLAY_DRIVER{private:    DEVICE_OBJECT* m_pPhysicalDevice;    DXGKRNL_INTERFACE m_DxgkInterface;    // Information passed in by StartDevice DDI    DXGK_START_INFO m_StartInfo;    // Array of EDIDs, currently only supporting base block, hence EDID_V1_BLOCK_SIZE for size of each EDID    BYTE m_EDIDs[MAX_CHILDREN][EDID_V1_BLOCK_SIZE];    CURRENT_BDD_MODE m_CurrentModes[MAX_VIEWS];    BDD_HWBLT        m_HardwareBlt[MAX_VIEWS];    // Current monitorpower state (this needs to be changed if MAX_CHILDREN != 1)    DEVICE_POWER_STATE m_MonitorPowerState;    // Current adapter power state    DEVICE_POWER_STATE m_AdapterPowerState;    // Source ID to be used by SystemDisplay functions    D3DDDI_VIDEO_PRESENT_SOURCE_ID m_SystemDisplaySourceId;    // Various boolean flags the class uses    BDD_FLAGS m_Flags;    // Device information    DXGK_DEVICE_INFO m_DeviceInfo;public:    BASIC_DISPLAY_DRIVER(_In_ DEVICE_OBJECT* pPhysicalDeviceObject);    ~BASIC_DISPLAY_DRIVER();#pragma code_seg(push)#pragma code_seg()    BOOLEAN IsDriverActive() const    {        return m_Flags.DriverStarted;    }#pragma code_seg(pop)    NTSTATUS StartDevice(_In_  DXGK_START_INFO*   pDxgkStartInfo,                         _In_  DXGKRNL_INTERFACE* pDxgkInterface,                         _Out_ ULONG*             pNumberOfViews,                         _Out_ ULONG*             pNumberOfChildren);    NTSTATUS StopDevice(VOID);    // Must be Non-Paged    VOID ResetDevice(VOID);    const CURRENT_BDD_MODE* GetCurrentMode(UINT SourceId) const    {        return (SourceId < MAX_VIEWS)?&m_CurrentModes[SourceId]:NULL;    }    const DXGKRNL_INTERFACE* GetDxgkInterface() const { return &m_DxgkInterface;}    // Not implemented since no IOCTLs currently handled.    NTSTATUS DispatchIoRequest(_In_  ULONG                 VidPnSourceId,                               _In_  VIDEO_REQUEST_PACKET* pVideoRequestPacket);    // Used to either turn off/on monitor (if possible), or mark that system is going into hibernate    NTSTATUS SetPowerState(_In_  ULONG              HardwareUid,                           _In_  DEVICE_POWER_STATE DevicePowerState,                           _In_  POWER_ACTION       ActionType);    // Report back child capabilities    NTSTATUS QueryChildRelations(_Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations,                                 _In_                             ULONG                  ChildRelationsSize);    NTSTATUS QueryChildStatus(_Inout_ DXGK_CHILD_STATUS* pChildStatus,                              _In_    BOOLEAN            NonDestructiveOnly);    // Return EDID if previously retrieved    NTSTATUS QueryDeviceDescriptor(_In_    ULONG                   ChildUid,                                   _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor);    // Must be Non-Paged    // BDD doesn't have interrupts, so just returns false    BOOLEAN InterruptRoutine(_In_  ULONG MessageNumber);    VOID DpcRoutine(VOID);    // Return DriverCaps, doesn't support other queries though    NTSTATUS QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo);    NTSTATUS SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition);    NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape);    NTSTATUS PresentDisplayOnly(_In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly);    NTSTATUS IsSupportedVidPn(_Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn);    NTSTATUS RecommendFunctionalVidPn(_In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn);    NTSTATUS RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology);    NTSTATUS RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes);    NTSTATUS EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality);    NTSTATUS SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility);    NTSTATUS CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn);    NTSTATUS UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath);    NTSTATUS QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps);    // Part of PnPStop (PnP instance only), returns current mode information (which will be passed to fallback instance by dxgkrnl)    NTSTATUS StopDeviceAndReleasePostDisplayOwnership(_In_  D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,                                                      _Out_ DXGK_DISPLAY_INFORMATION*      pDisplayInfo);    // Must be Non-Paged    // Call to initialize as part of bugcheck    NTSTATUS SystemDisplayEnable(_In_  D3DDDI_VIDEO_PRESENT_TARGET_ID       TargetId,                                 _In_  PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,                                 _Out_ UINT*                                pWidth,                                 _Out_ UINT*                                pHeight,                                 _Out_ D3DDDIFORMAT*                        pColorFormat);    // Must be Non-Paged    // Write out pixels as part of bugcheck    VOID SystemDisplayWrite(_In_reads_bytes_(SourceHeight * SourceStride) VOID* pSource,                            _In_                                     UINT  SourceWidth,                            _In_                                     UINT  SourceHeight,                            _In_                                     UINT  SourceStride,                            _In_                                     INT   PositionX,                            _In_                                     INT   PositionY);private:    VOID CleanUp();    NTSTATUS CommonStart();    NTSTATUS GetEdid(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId);    // Given pixel format, give back the bits per pixel. Only supports pixel formats expected by BDD    // (i.e. the ones found below in PixelFormatFromBPP or that may come in from FallbackStart)    // This is because these two functions combine to allow BDD to store the bpp of a VBE mode in the    // ColorFormat field of a DispInfo    UINT BPPFromPixelFormat(D3DDDIFORMAT Format) const    {        switch (Format)        {            case D3DDDIFMT_UNKNOWN: return 0;            case D3DDDIFMT_P8: return 8;            case D3DDDIFMT_R5G6B5: return 16;            case D3DDDIFMT_R8G8B8: return 24;            case D3DDDIFMT_X8R8G8B8: // fall through            case D3DDDIFMT_A8R8G8B8: return 32;            default: BDD_LOG_ASSERTION1("Unknown D3DDDIFORMAT 0x%I64x", Format); return 0;        }    }    // Given bits per pixel, return the pixel format at the same bpp    D3DDDIFORMAT PixelFormatFromBPP(UINT BPP) const    {        switch (BPP)        {            case  8: return D3DDDIFMT_P8;            case 16: return D3DDDIFMT_R5G6B5;            case 24: return D3DDDIFMT_R8G8B8;            case 32: return D3DDDIFMT_X8R8G8B8;            default: BDD_LOG_ASSERTION1("A bit per pixel of 0x%I64x is not supported.", BPP); return D3DDDIFMT_UNKNOWN;        }    }    // These two functions make checks on the values of some of the fields of their respective structures to ensure    // that the specified fields are supported by BDD, i.e. gamma ramp must be D3DDDI_GAMMARAMP_DEFAULT    NTSTATUS IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const;    NTSTATUS IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const;    VOID BlackOutScreen(D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId);    // Returns the index into gBddBiosData.BddModes of the VBE mode that matches the given VidPnSourceMode.    // If such a mode cannot be found, returns a number outside of [0, gBddBiosData.CountBddModes)    UINT FindMatchingVBEMode(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const;    // Must be Non-Paged    // Returns the SourceId that has TargetId as a valid frame buffer or D3DDDI_ID_UNINITIALIZED if no such SourceId exists    D3DDDI_VIDEO_PRESENT_SOURCE_ID FindSourceForTarget(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, BOOLEAN DefaultToZero);    // Set the given source mode on the given path    NTSTATUS SetSourceModeAndPath(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode,                                  CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath);    // Add the current mode to the given monitor source mode set    NTSTATUS AddSingleMonitorMode(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes);    // Add the current mode to the given VidPn source mode set    NTSTATUS AddSingleSourceMode(_In_ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface,                                 D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet,                                 D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId);    // Add the current mode (or the matching to pinned source mode) to the give VidPn target mode set    NTSTATUS AddSingleTargetMode(_In_ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface,                                 D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet,                                 _In_opt_ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo,                                 D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId);    // Check that the hardware the driver is running on is hardware it is capable of driving.    NTSTATUS CheckHardware();    // Helper function for RegisterHWInfo    NTSTATUS WriteHWInfoStr(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue);    // Set the information in the registry as described here: http://msdn.microsoft.com/en-us/library/windows/hardware/ff569240(v=vs.85).aspx    NTSTATUS RegisterHWInfo();};//// Blt functions//// Must be Non-PagedVOID BltBits(    BLT_INFO* pDst,    CONST BLT_INFO* pSrc,    UINT  NumRects,    _In_reads_(NumRects) CONST RECT *pRects);//// Driver Entry point//extern "C"DRIVER_INITIALIZE DriverEntry;//// PnP DDIs//VOIDBddDdiUnload(VOID);// If uncommenting ENABLE_DXGK_SAL in the sources file, all the below function prototypes should be updated to use// the function typedef's from the header files. Additionally, annotations on the function definitions can be removed// as they are inherited from the prototype definition here. As an example the entire 4-line prototype for BddDdiAddDevice// is replaced by the single commented line below:// DXGKDDI_ADD_DEVICE BddDdiAddDevice;NTSTATUSBddDdiAddDevice(    _In_ DEVICE_OBJECT* pPhysicalDeviceObject,    _Outptr_ PVOID*  ppDeviceContext);NTSTATUSBddDdiRemoveDevice(    _In_  VOID* pDeviceContext);NTSTATUSBddDdiStartDevice(    _In_  VOID*              pDeviceContext,    _In_  DXGK_START_INFO*   pDxgkStartInfo,    _In_  DXGKRNL_INTERFACE* pDxgkInterface,    _Out_ ULONG*             pNumberOfViews,    _Out_ ULONG*             pNumberOfChildren);NTSTATUSBddDdiStopDevice(    _In_  VOID* pDeviceContext);VOIDBddDdiResetDevice(    _In_  VOID* pDeviceContext);NTSTATUSBddDdiDispatchIoRequest(    _In_  VOID*                 pDeviceContext,    _In_  ULONG                 VidPnSourceId,    _In_  VIDEO_REQUEST_PACKET* pVideoRequestPacket);NTSTATUSBddDdiSetPowerState(    _In_  VOID*              pDeviceContext,    _In_  ULONG              HardwareUid,    _In_  DEVICE_POWER_STATE DevicePowerState,    _In_  POWER_ACTION       ActionType);NTSTATUSBddDdiQueryChildRelations(    _In_                             VOID*                  pDeviceContext,    _Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations,    _In_                             ULONG                  ChildRelationsSize);NTSTATUSBddDdiQueryChildStatus(    _In_    VOID*              pDeviceContext,    _Inout_ DXGK_CHILD_STATUS* pChildStatus,    _In_    BOOLEAN            NonDestructiveOnly);NTSTATUSBddDdiQueryDeviceDescriptor(    _In_  VOID*                     pDeviceContext,    _In_  ULONG                     ChildUid,    _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor);// Must be Non-PagedBOOLEANBddDdiInterruptRoutine(    _In_  VOID* pDeviceContext,    _In_  ULONG MessageNumber);VOIDBddDdiDpcRoutine(    _In_  VOID* pDeviceContext);//// WDDM Display Only Driver DDIs//NTSTATUSAPIENTRYBddDdiQueryAdapterInfo(    _In_ CONST HANDLE                         hAdapter,    _In_ CONST DXGKARG_QUERYADAPTERINFO*      pQueryAdapterInfo);NTSTATUSAPIENTRYBddDdiSetPointerPosition(    _In_ CONST HANDLE                         hAdapter,    _In_ CONST DXGKARG_SETPOINTERPOSITION*    pSetPointerPosition);NTSTATUSAPIENTRYBddDdiSetPointerShape(    _In_ CONST HANDLE                         hAdapter,    _In_ CONST DXGKARG_SETPOINTERSHAPE*       pSetPointerShape);NTSTATUSAPIENTRYBddDdiPresentDisplayOnly(    _In_ CONST HANDLE                         hAdapter,    _In_ CONST DXGKARG_PRESENT_DISPLAYONLY*   pPresentDisplayOnly);NTSTATUSAPIENTRYBddDdiIsSupportedVidPn(    _In_ CONST HANDLE                         hAdapter,    _Inout_ DXGKARG_ISSUPPORTEDVIDPN*         pIsSupportedVidPn);NTSTATUSAPIENTRYBddDdiRecommendFunctionalVidPn(    _In_ CONST HANDLE                                   hAdapter,    _In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST  pRecommendFunctionalVidPn);NTSTATUSAPIENTRYBddDdiRecommendVidPnTopology(    _In_ CONST HANDLE                                 hAdapter,    _In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST  pRecommendVidPnTopology);NTSTATUSAPIENTRYBddDdiRecommendMonitorModes(    _In_ CONST HANDLE                                hAdapter,    _In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST  pRecommendMonitorModes);NTSTATUSAPIENTRYBddDdiEnumVidPnCofuncModality(    _In_ CONST HANDLE                                  hAdapter,    _In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST  pEnumCofuncModality);NTSTATUSAPIENTRYBddDdiSetVidPnSourceVisibility(    _In_ CONST HANDLE                             hAdapter,    _In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY*  pSetVidPnSourceVisibility);NTSTATUSAPIENTRYBddDdiCommitVidPn(    _In_ CONST HANDLE                         hAdapter,    _In_ CONST DXGKARG_COMMITVIDPN* CONST     pCommitVidPn);NTSTATUSAPIENTRYBddDdiUpdateActiveVidPnPresentPath(    _In_ CONST HANDLE                                       hAdapter,    _In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST  pUpdateActiveVidPnPresentPath);NTSTATUSAPIENTRYBddDdiQueryVidPnHWCapability(    _In_ CONST HANDLE                         hAdapter,    _Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY*   pVidPnHWCaps);NTSTATUSAPIENTRYBddDdiStopDeviceAndReleasePostDisplayOwnership(    _In_  VOID*                          pDeviceContext,    _In_  D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,    _Out_ DXGK_DISPLAY_INFORMATION*      DisplayInfo);// Must be Non-PagedNTSTATUSAPIENTRYBddDdiSystemDisplayEnable(    _In_  VOID* pDeviceContext,    _In_  D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,    _In_  PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,    _Out_ UINT* Width,    _Out_ UINT* Height,    _Out_ D3DDDIFORMAT* ColorFormat);// Must be Non-PagedVOIDAPIENTRYBddDdiSystemDisplayWrite(    _In_  VOID* pDeviceContext,    _In_  VOID* Source,    _In_  UINT  SourceWidth,    _In_  UINT  SourceHeight,    _In_  UINT  SourceStride,    _In_  UINT  PositionX,    _In_  UINT  PositionY);//// Frame buffer map/unmap//NTSTATUSMapFrameBuffer(    _In_                       PHYSICAL_ADDRESS    PhysicalAddress,    _In_                       ULONG               Length,    _Outptr_result_bytebuffer_(Length) VOID**              VirtualAddress);NTSTATUSUnmapFrameBuffer(    _In_reads_bytes_(Length) VOID* VirtualAddress,    _In_                ULONG Length);BOOLEANIsEdidHeaderValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid);BOOLEANIsEdidChecksumValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid);//// Memory handling//// Defaulting the value of PoolType means that any call to new Foo()// will raise a compiler error for being ambiguous. This is to help keep// any calls to allocate memory from accidentally NOT going through// these functions._When_((PoolType & NonPagedPoolMustSucceed) != 0,    __drv_reportError("Must succeed pool allocations are forbidden. "            "Allocation failures cause a system crash"))void* __cdecl operator new(size_t Size, POOL_TYPE PoolType = PagedPool);_When_((PoolType & NonPagedPoolMustSucceed) != 0,    __drv_reportError("Must succeed pool allocations are forbidden. "            "Allocation failures cause a system crash"))void* __cdecl operator new[](size_t Size, POOL_TYPE PoolType = PagedPool);void  __cdecl operator delete(void* pObject);void  __cdecl operator delete(void* pObject, size_t s);void  __cdecl operator delete[](void* pObject);// Pool allocation tag for the Sample Display Driver. All allocations use this tag.#define BDDTAG 'DDBS'#endif // _BDD_HXX_

C++程式檔案 bdd.cxx

/******************************Module*Header*******************************\* Module Name: bdd.cxx** Basic Display Driver functions implementation*** Copyright (c) 2010 Microsoft Corporation\**************************************************************************/#include "BDD.hxx"#pragma code_seg("PAGE")BASIC_DISPLAY_DRIVER::BASIC_DISPLAY_DRIVER(_In_ DEVICE_OBJECT* pPhysicalDeviceObject) : m_pPhysicalDevice(pPhysicalDeviceObject),                                                                                        m_MonitorPowerState(PowerDeviceD0),                                                                                        m_AdapterPowerState(PowerDeviceD0){    PAGED_CODE();    *((UINT*)&m_Flags) = 0;    m_Flags._LastFlag = TRUE;    RtlZeroMemory(&m_DxgkInterface, sizeof(m_DxgkInterface));    RtlZeroMemory(&m_StartInfo, sizeof(m_StartInfo));    RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes));    RtlZeroMemory(&m_DeviceInfo, sizeof(m_DeviceInfo));    for (UINT i=0;iChildUid < MAX_CHILDREN);    switch (pChildStatus->Type)    {        case StatusConnection:        {            // HpdAwarenessInterruptible was reported since HpdAwarenessNone is deprecated.            // However, BDD has no knowledge of HotPlug events, so just always return connected.            pChildStatus->HotPlug.Connected = IsDriverActive();            return STATUS_SUCCESS;        }        case StatusRotation:        {            // D3DKMDT_MOA_NONE was reported, so this should never be called            BDD_LOG_ERROR0("Child status being queried for StatusRotation even though D3DKMDT_MOA_NONE was reported");            return STATUS_INVALID_PARAMETER;        }        default:        {            BDD_LOG_WARNING1("Unknown pChildStatus->Type (0x%I64x) requested.", pChildStatus->Type);            return STATUS_NOT_SUPPORTED;        }    }}// EDID retrievalNTSTATUS BASIC_DISPLAY_DRIVER::QueryDeviceDescriptor(_In_    ULONG                   ChildUid,                                                     _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor){    PAGED_CODE();    BDD_ASSERT(pDeviceDescriptor != NULL);    BDD_ASSERT(ChildUid < MAX_CHILDREN);    // If we haven't successfully retrieved an EDID yet (invalid ones are ok, so long as it was retrieved)    if (!m_Flags.EDID_Attempted)    {        GetEdid(ChildUid);    }    if (!m_Flags.EDID_Retrieved || !m_Flags.EDID_ValidHeader || !m_Flags.EDID_ValidChecksum)    {        // Report no EDID if a valid one wasn't retrieved        return STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED;    }    else if (pDeviceDescriptor->DescriptorOffset == 0)    {        // Only the base block is supported        RtlCopyMemory(pDeviceDescriptor->DescriptorBuffer,                      m_EDIDs[ChildUid],                      min(pDeviceDescriptor->DescriptorLength, EDID_V1_BLOCK_SIZE));        return STATUS_SUCCESS;    }    else    {        return STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA;    }}NTSTATUS BASIC_DISPLAY_DRIVER::QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo){    PAGED_CODE();    BDD_ASSERT(pQueryAdapterInfo != NULL);    switch (pQueryAdapterInfo->Type)    {        case DXGKQAITYPE_DRIVERCAPS:        {            if (pQueryAdapterInfo->OutputDataSize < sizeof(DXGK_DRIVERCAPS))            {                BDD_LOG_ERROR2("pQueryAdapterInfo->OutputDataSize (0x%I64x) is smaller than sizeof(DXGK_DRIVERCAPS) (0x%I64x)", pQueryAdapterInfo->OutputDataSize, sizeof(DXGK_DRIVERCAPS));                return STATUS_BUFFER_TOO_SMALL;            }            DXGK_DRIVERCAPS* pDriverCaps = (DXGK_DRIVERCAPS*)pQueryAdapterInfo->pOutputData;            // Nearly all fields must be initialized to zero, so zero out to start and then change those that are non-zero.            // Fields are zero since BDD is Display-Only and therefore does not support any of the render related fields.            // It also doesn't support hardware interrupts, gamma ramps, etc.            RtlZeroMemory(pDriverCaps, sizeof(DXGK_DRIVERCAPS));            pDriverCaps->WDDMVersion = DXGKDDI_WDDMv1_2;            pDriverCaps->HighestAcceptableAddress.QuadPart = -1;            pDriverCaps->SupportNonVGA = TRUE;            pDriverCaps->SupportSmoothRotation = TRUE;            return STATUS_SUCCESS;        }        case DXGKQAITYPE_DISPLAY_DRIVERCAPS_EXTENSION:        {            DXGK_DISPLAY_DRIVERCAPS_EXTENSION* pDriverDisplayCaps;            if (pQueryAdapterInfo->OutputDataSize < sizeof(*pDriverDisplayCaps))            {                BDD_LOG_ERROR2("pQueryAdapterInfo->OutputDataSize (0x%I64x) is smaller than sizeof(DXGK_DISPLAY_DRIVERCAPS_EXTENSION) (0x%I64x)",                               pQueryAdapterInfo->OutputDataSize,                               sizeof(DXGK_DISPLAY_DRIVERCAPS_EXTENSION));                return STATUS_INVALID_PARAMETER;            }            pDriverDisplayCaps = (DXGK_DISPLAY_DRIVERCAPS_EXTENSION*)pQueryAdapterInfo->pOutputData;            // Reset all caps values            RtlZeroMemory(pDriverDisplayCaps, pQueryAdapterInfo->OutputDataSize);            // We claim to support virtual display mode.            pDriverDisplayCaps->VirtualModeSupport = 1;            return STATUS_SUCCESS;        }        default:        {            // BDD does not need to support any other adapter information types            BDD_LOG_WARNING1("Unknown QueryAdapterInfo Type (0x%I64x) requested", pQueryAdapterInfo->Type);            return STATUS_NOT_SUPPORTED;        }    }}NTSTATUS BASIC_DISPLAY_DRIVER::CheckHardware(){    PAGED_CODE();    NTSTATUS Status;    ULONG VendorID;    ULONG DeviceID;// TODO: If developing a driver for PCI based hardware, then use the second method to retrieve Vendor/Device IDs.// If developing for non-PCI based hardware (i.e. ACPI based hardware), use the first method to retrieve the IDs.#if 1 // ACPI-based device    // Get the Vendor & Device IDs on non-PCI system    ACPI_EVAL_INPUT_BUFFER_COMPLEX AcpiInputBuffer = {0};    AcpiInputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE;    AcpiInputBuffer.MethodNameAsUlong = ACPI_METHOD_HARDWARE_ID;    AcpiInputBuffer.Size = 0;    AcpiInputBuffer.ArgumentCount = 0;    BYTE OutputBuffer[sizeof(ACPI_EVAL_OUTPUT_BUFFER) + 0x10];    RtlZeroMemory(OutputBuffer, sizeof(OutputBuffer));    ACPI_EVAL_OUTPUT_BUFFER* pAcpiOutputBuffer = reinterpret_cast(&OutputBuffer);    Status = m_DxgkInterface.DxgkCbEvalAcpiMethod(m_DxgkInterface.DeviceHandle,                                                  DISPLAY_ADAPTER_HW_ID,                                                  &AcpiInputBuffer,                                                  sizeof(AcpiInputBuffer),                                                  pAcpiOutputBuffer,                                                  sizeof(OutputBuffer));    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR1("DxgkCbReadDeviceSpace failed to get hardware IDs with status 0x%I64x", Status);        return Status;    }    VendorID = ((ULONG*)(pAcpiOutputBuffer->Argument[0].Data))[0];    DeviceID = ((ULONG*)(pAcpiOutputBuffer->Argument[0].Data))[1];#else // PCI-based device    // Get the Vendor & Device IDs on PCI system    PCI_COMMON_HEADER Header = {0};    ULONG BytesRead;    Status = m_DxgkInterface.DxgkCbReadDeviceSpace(m_DxgkInterface.DeviceHandle,                                                   DXGK_WHICHSPACE_CONFIG,                                                   &Header,                                                   0,                                                   sizeof(Header),                                                   &BytesRead);    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR1("DxgkCbReadDeviceSpace failed with status 0x%I64x", Status);        return Status;    }    VendorID = Header.VendorID;    DeviceID = Header.DeviceID;#endif    // TODO: Replace 0x1414 with your Vendor ID    if (VendorID == 0x1414)    {        switch (DeviceID)        {            // TODO: Replace the case statements below with the Device IDs supported by this driver            case 0x0000:            case 0xFFFF: return STATUS_SUCCESS;        }    }    return STATUS_GRAPHICS_DRIVER_MISMATCH;}// Even though Sample Basic Display Driver does not support hardware cursors, and reports such// in QueryAdapterInfo. This function can still be called to set the pointer to not visibleNTSTATUS BASIC_DISPLAY_DRIVER::SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition){    PAGED_CODE();    BDD_ASSERT(pSetPointerPosition != NULL);    BDD_ASSERT(pSetPointerPosition->VidPnSourceId < MAX_VIEWS);    if (!(pSetPointerPosition->Flags.Visible))    {        return STATUS_SUCCESS;    }    else    {        BDD_LOG_ASSERTION0("SetPointerPosition should never be called to set the pointer to visible since BDD doesn't support hardware cursors.");        return STATUS_UNSUCCESSFUL;    }}// Basic Sample Display Driver does not support hardware cursors, and reports such// in QueryAdapterInfo. Therefore this function should never be called.NTSTATUS BASIC_DISPLAY_DRIVER::SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape){    PAGED_CODE();    BDD_ASSERT(pSetPointerShape != NULL);    BDD_LOG_ASSERTION0("SetPointerShape should never be called since BDD doesn't support hardware cursors.");    return STATUS_NOT_IMPLEMENTED;}NTSTATUS BASIC_DISPLAY_DRIVER::PresentDisplayOnly(_In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly){    PAGED_CODE();    BDD_ASSERT(pPresentDisplayOnly != NULL);    BDD_ASSERT(pPresentDisplayOnly->VidPnSourceId < MAX_VIEWS);    if (pPresentDisplayOnly->BytesPerPixel < MIN_BYTES_PER_PIXEL_REPORTED)    {        // Only >=32bpp modes are reported, therefore this Present should never pass anything less than 4 bytes per pixel        BDD_LOG_ERROR1("pPresentDisplayOnly->BytesPerPixel is 0x%I64x, which is lower than the allowed.", pPresentDisplayOnly->BytesPerPixel);        return STATUS_INVALID_PARAMETER;    }    // If it is in monitor off state or source is not supposed to be visible, don't present anything to the screen    if ((m_MonitorPowerState > PowerDeviceD0) ||        (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Flags.SourceNotVisible))    {        return STATUS_SUCCESS;    }    // Present is only valid if the target is actively connected to this source    if (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Flags.FrameBufferIsActive)    {        // If actual pixels are coming through, will need to completely zero out physical address next time in BlackOutScreen        m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].ZeroedOutStart.QuadPart = 0;        m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].ZeroedOutEnd.QuadPart = 0;        D3DKMDT_VIDPN_PRESENT_PATH_ROTATION RotationNeededByFb = pPresentDisplayOnly->Flags.Rotate ?                                                                 m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Rotation :                                                                 D3DKMDT_VPPR_IDENTITY;            BYTE* pDst = (BYTE*)m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].FrameBuffer.Ptr;            UINT DstBitPerPixel = BPPFromPixelFormat(m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.ColorFormat);            if (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Scaling == D3DKMDT_VPPS_CENTERED)            {                UINT CenterShift = (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Height -                    m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].SrcModeHeight)*m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Pitch;                CenterShift += (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Width -                    m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].SrcModeWidth)*DstBitPerPixel/8;                pDst += (int)CenterShift/2;            }            return m_HardwareBlt[pPresentDisplayOnly->VidPnSourceId].ExecutePresentDisplayOnly(pDst,                                                                    DstBitPerPixel,                                                                    (BYTE*)pPresentDisplayOnly->pSource,                                                                    pPresentDisplayOnly->BytesPerPixel,                                                                    pPresentDisplayOnly->Pitch,                                                                    pPresentDisplayOnly->NumMoves,                                                                    pPresentDisplayOnly->pMoves,                                                                    pPresentDisplayOnly->NumDirtyRects,                                                                    pPresentDisplayOnly->pDirtyRect,                                                                    RotationNeededByFb);    }    return STATUS_SUCCESS;}NTSTATUS BASIC_DISPLAY_DRIVER::StopDeviceAndReleasePostDisplayOwnership(_In_  D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,                                                                        _Out_ DXGK_DISPLAY_INFORMATION*      pDisplayInfo){    PAGED_CODE();    BDD_ASSERT(TargetId < MAX_CHILDREN);    D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId = FindSourceForTarget(TargetId, TRUE);    // In case BDD is the next driver to run, the monitor should not be off, since    // this could cause the BIOS to hang when the EDID is retrieved on Start.    if (m_MonitorPowerState > PowerDeviceD0)    {        SetPowerState(TargetId, PowerDeviceD0, PowerActionNone);    }    // The driver has to black out the display and ensure it is visible when releasing ownership    BlackOutScreen(SourceId);    *pDisplayInfo = m_CurrentModes[SourceId].DispInfo;    return StopDevice();}NTSTATUS BASIC_DISPLAY_DRIVER::QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps){    PAGED_CODE();    BDD_ASSERT(pVidPnHWCaps != NULL);    BDD_ASSERT(pVidPnHWCaps->SourceId < MAX_VIEWS);    BDD_ASSERT(pVidPnHWCaps->TargetId < MAX_CHILDREN);    pVidPnHWCaps->VidPnHWCaps.DriverRotation             = 1; // BDD does rotation in software    pVidPnHWCaps->VidPnHWCaps.DriverScaling              = 0; // BDD does not support scaling    pVidPnHWCaps->VidPnHWCaps.DriverCloning              = 0; // BDD does not support clone    pVidPnHWCaps->VidPnHWCaps.DriverColorConvert         = 1; // BDD does color conversions in software    pVidPnHWCaps->VidPnHWCaps.DriverLinkedAdapaterOutput = 0; // BDD does not support linked adapters    pVidPnHWCaps->VidPnHWCaps.DriverRemoteDisplay        = 0; // BDD does not support remote displays    return STATUS_SUCCESS;}NTSTATUS BASIC_DISPLAY_DRIVER::GetEdid(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId){    PAGED_CODE();    BDD_ASSERT_CHK(!m_Flags.EDID_Attempted);    NTSTATUS Status = STATUS_SUCCESS;    RtlZeroMemory(m_EDIDs[TargetId], sizeof(m_EDIDs[TargetId]));    m_Flags.EDID_Attempted = TRUE;    return Status;}VOID BASIC_DISPLAY_DRIVER::BlackOutScreen(D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId){    PAGED_CODE();    UINT ScreenHeight = m_CurrentModes[SourceId].DispInfo.Height;    UINT ScreenPitch = m_CurrentModes[SourceId].DispInfo.Pitch;    PHYSICAL_ADDRESS NewPhysAddrStart = m_CurrentModes[SourceId].DispInfo.PhysicAddress;    PHYSICAL_ADDRESS NewPhysAddrEnd;    NewPhysAddrEnd.QuadPart = NewPhysAddrStart.QuadPart + (ScreenHeight * ScreenPitch);    if (m_CurrentModes[SourceId].Flags.FrameBufferIsActive)    {        BYTE* MappedAddr = reinterpret_cast(m_CurrentModes[SourceId].FrameBuffer.Ptr);        // Zero any memory at the start that hasn't been zeroed recently        if (NewPhysAddrStart.QuadPart < m_CurrentModes[SourceId].ZeroedOutStart.QuadPart)        {            if (NewPhysAddrEnd.QuadPart < m_CurrentModes[SourceId].ZeroedOutStart.QuadPart)            {                // No overlap                RtlZeroMemory(MappedAddr, ScreenHeight * ScreenPitch);            }            else            {                RtlZeroMemory(MappedAddr, (UINT)(m_CurrentModes[SourceId].ZeroedOutStart.QuadPart - NewPhysAddrStart.QuadPart));            }        }        // Zero any memory at the end that hasn't been zeroed recently        if (NewPhysAddrEnd.QuadPart > m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart)        {            if (NewPhysAddrStart.QuadPart > m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart)            {                // No overlap                // NOTE: When actual pixels were the most recent thing drawn, ZeroedOutStart & ZeroedOutEnd will both be 0                // and this is the path that will be used to black out the current screen.                RtlZeroMemory(MappedAddr, ScreenHeight * ScreenPitch);            }            else            {                RtlZeroMemory(MappedAddr, (UINT)(NewPhysAddrEnd.QuadPart - m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart));            }        }    }    m_CurrentModes[SourceId].ZeroedOutStart.QuadPart = NewPhysAddrStart.QuadPart;    m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart = NewPhysAddrEnd.QuadPart;}NTSTATUS BASIC_DISPLAY_DRIVER::WriteHWInfoStr(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue){    PAGED_CODE();    NTSTATUS Status;    ANSI_STRING AnsiStrValue;    UNICODE_STRING UnicodeStrValue;    UNICODE_STRING UnicodeStrValueName;    // ZwSetValueKey wants the ValueName as a UNICODE_STRING    RtlInitUnicodeString(&UnicodeStrValueName, pszwValueName);    // REG_SZ is for WCHARs, there is no equivalent for CHARs    // Use the ansi/unicode conversion functions to get from PSTR to PWSTR    RtlInitAnsiString(&AnsiStrValue, pszValue);    Status = RtlAnsiStringToUnicodeString(&UnicodeStrValue, &AnsiStrValue, TRUE);    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR1("RtlAnsiStringToUnicodeString failed with Status: 0x%I64x", Status);        return Status;    }    // Write the value to the registry    Status = ZwSetValueKey(DevInstRegKeyHandle,                           &UnicodeStrValueName,                           0,                           REG_SZ,                           UnicodeStrValue.Buffer,                           UnicodeStrValue.MaximumLength);    // Free the earlier allocated unicode string    RtlFreeUnicodeString(&UnicodeStrValue);    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR1("ZwSetValueKey failed with Status: 0x%I64x", Status);    }    return Status;}NTSTATUS BASIC_DISPLAY_DRIVER::RegisterHWInfo(){    PAGED_CODE();    NTSTATUS Status;    // TODO: Replace these strings with proper information    PCSTR StrHWInfoChipType = "Replace with the chip name";    PCSTR StrHWInfoDacType = "Replace with the DAC name or identifier (ID)";    PCSTR StrHWInfoAdapterString = "Replace with the name of the adapter";    PCSTR StrHWInfoBiosString = "Replace with information about the BIOS";    HANDLE DevInstRegKeyHandle;    Status = IoOpenDeviceRegistryKey(m_pPhysicalDevice, PLUGPLAY_REGKEY_DRIVER, KEY_SET_VALUE, &DevInstRegKeyHandle);    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR2("IoOpenDeviceRegistryKey failed for PDO: 0x%I64x, Status: 0x%I64x", m_pPhysicalDevice, Status);        return Status;    }    Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.ChipType", StrHWInfoChipType);    if (!NT_SUCCESS(Status))    {        return Status;    }    Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.DacType", StrHWInfoDacType);    if (!NT_SUCCESS(Status))    {        return Status;    }    Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.AdapterString", StrHWInfoAdapterString);    if (!NT_SUCCESS(Status))    {        return Status;    }    Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.BiosString", StrHWInfoBiosString);    if (!NT_SUCCESS(Status))    {        return Status;    }    // MemorySize is a ULONG, unlike the others which are all strings    UNICODE_STRING ValueNameMemorySize;    RtlInitUnicodeString(&ValueNameMemorySize, L"HardwareInformation.MemorySize");    DWORD MemorySize = 0; // BDD has no access to video memory    Status = ZwSetValueKey(DevInstRegKeyHandle,                           &ValueNameMemorySize,                           0,                           REG_DWORD,                           &MemorySize,                           sizeof(MemorySize));    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR1("ZwSetValueKey for MemorySize failed with Status: 0x%I64x", Status);        return Status;    }    return Status;}//// Non-Paged Code//#pragma code_seg(push)#pragma code_seg()D3DDDI_VIDEO_PRESENT_SOURCE_ID BASIC_DISPLAY_DRIVER::FindSourceForTarget(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, BOOLEAN DefaultToZero){    UNREFERENCED_PARAMETER(TargetId);    BDD_ASSERT_CHK(TargetId < MAX_CHILDREN);    for (UINT SourceId = 0; SourceId < MAX_VIEWS; ++SourceId)    {        if (m_CurrentModes[SourceId].FrameBuffer.Ptr != NULL)        {            return SourceId;        }    }    return DefaultToZero ? 0 : D3DDDI_ID_UNINITIALIZED;}VOID BASIC_DISPLAY_DRIVER::DpcRoutine(VOID){    m_DxgkInterface.DxgkCbNotifyDpc((HANDLE)m_DxgkInterface.DeviceHandle);}BOOLEAN BASIC_DISPLAY_DRIVER::InterruptRoutine(_In_  ULONG MessageNumber){    UNREFERENCED_PARAMETER(MessageNumber);    // BDD cannot handle interrupts    return FALSE;}VOID BASIC_DISPLAY_DRIVER::ResetDevice(VOID){}// Must be Non-Paged, as it sets up the display for a bugcheckNTSTATUS BASIC_DISPLAY_DRIVER::SystemDisplayEnable(_In_  D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,                                                   _In_  PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,                                                   _Out_ UINT* pWidth,                                                   _Out_ UINT* pHeight,                                                   _Out_ D3DDDIFORMAT* pColorFormat){    UNREFERENCED_PARAMETER(Flags);    m_SystemDisplaySourceId = D3DDDI_ID_UNINITIALIZED;    BDD_ASSERT((TargetId < MAX_CHILDREN) || (TargetId == D3DDDI_ID_UNINITIALIZED));    // Find the frame buffer for displaying the bugcheck, if it was successfully mapped    if (TargetId == D3DDDI_ID_UNINITIALIZED)    {        for (UINT SourceIdx = 0; SourceIdx < MAX_VIEWS; ++SourceIdx)        {            if (m_CurrentModes[SourceIdx].FrameBuffer.Ptr != NULL)            {                m_SystemDisplaySourceId = SourceIdx;                break;            }        }    }    else    {        m_SystemDisplaySourceId = FindSourceForTarget(TargetId, FALSE);    }    if (m_SystemDisplaySourceId == D3DDDI_ID_UNINITIALIZED)    {        {            return STATUS_UNSUCCESSFUL;        }    }    if ((m_CurrentModes[m_SystemDisplaySourceId].Rotation == D3DKMDT_VPPR_ROTATE90) ||        (m_CurrentModes[m_SystemDisplaySourceId].Rotation == D3DKMDT_VPPR_ROTATE270))    {        *pHeight = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width;        *pWidth = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height;    }    else    {        *pWidth = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width;        *pHeight = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height;    }    *pColorFormat = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.ColorFormat;    return STATUS_SUCCESS;}// Must be Non-Paged, as it is called to display the bugcheck screenVOID BASIC_DISPLAY_DRIVER::SystemDisplayWrite(_In_reads_bytes_(SourceHeight * SourceStride) VOID* pSource,                                              _In_ UINT SourceWidth,                                              _In_ UINT SourceHeight,                                              _In_ UINT SourceStride,                                              _In_ INT PositionX,                                              _In_ INT PositionY){    // Rect will be Offset by PositionX/Y in the src to reset it back to 0    RECT Rect;    Rect.left = PositionX;    Rect.top = PositionY;    Rect.right =  Rect.left + SourceWidth;    Rect.bottom = Rect.top + SourceHeight;    // Set up destination blt info    BLT_INFO DstBltInfo;    DstBltInfo.pBits = m_CurrentModes[m_SystemDisplaySourceId].FrameBuffer.Ptr;    DstBltInfo.Pitch = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Pitch;    DstBltInfo.BitsPerPel = BPPFromPixelFormat(m_CurrentModes[m_SystemDisplaySourceId].DispInfo.ColorFormat);    DstBltInfo.Offset.x = 0;    DstBltInfo.Offset.y = 0;    DstBltInfo.Rotation = m_CurrentModes[m_SystemDisplaySourceId].Rotation;    DstBltInfo.Width = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width;    DstBltInfo.Height = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height;    // Set up source blt info    BLT_INFO SrcBltInfo;    SrcBltInfo.pBits = pSource;    SrcBltInfo.Pitch = SourceStride;    SrcBltInfo.BitsPerPel = 32;    SrcBltInfo.Offset.x = -PositionX;    SrcBltInfo.Offset.y = -PositionY;    SrcBltInfo.Rotation = D3DKMDT_VPPR_IDENTITY;    SrcBltInfo.Width = SourceWidth;    SrcBltInfo.Height = SourceHeight;    BltBits(&DstBltInfo,            &SrcBltInfo,            1, // NumRects            &Rect);}#pragma code_seg(pop) // End Non-Paged Code

C++程式檔案 bdd_ddi.cxx

/******************************Module*Header*******************************\* Module Name: BDD_DDI.cxx** Basic Display Driver DDI entry points redirects*** Copyright (c) 2010 Microsoft Corporation\**************************************************************************/#include "BDD.hxx"#pragma code_seg(push)#pragma code_seg("INIT")// BEGIN: Init Code//// Driver Entry point//extern "C"NTSTATUSDriverEntry(    _In_  DRIVER_OBJECT*  pDriverObject,    _In_  UNICODE_STRING* pRegistryPath){    PAGED_CODE();    // Initialize DDI function pointers and dxgkrnl    KMDDOD_INITIALIZATION_DATA InitialData = {0};    InitialData.Version = DXGKDDI_INTERFACE_VERSION;    InitialData.DxgkDdiAddDevice                    = BddDdiAddDevice;    InitialData.DxgkDdiStartDevice                  = BddDdiStartDevice;    InitialData.DxgkDdiStopDevice                   = BddDdiStopDevice;    InitialData.DxgkDdiResetDevice                  = BddDdiResetDevice;    InitialData.DxgkDdiRemoveDevice                 = BddDdiRemoveDevice;    InitialData.DxgkDdiDispatchIoRequest            = BddDdiDispatchIoRequest;    InitialData.DxgkDdiInterruptRoutine             = BddDdiInterruptRoutine;    InitialData.DxgkDdiDpcRoutine                   = BddDdiDpcRoutine;    InitialData.DxgkDdiQueryChildRelations          = BddDdiQueryChildRelations;    InitialData.DxgkDdiQueryChildStatus             = BddDdiQueryChildStatus;    InitialData.DxgkDdiQueryDeviceDescriptor        = BddDdiQueryDeviceDescriptor;    InitialData.DxgkDdiSetPowerState                = BddDdiSetPowerState;    InitialData.DxgkDdiUnload                       = BddDdiUnload;    InitialData.DxgkDdiQueryAdapterInfo             = BddDdiQueryAdapterInfo;    InitialData.DxgkDdiSetPointerPosition           = BddDdiSetPointerPosition;    InitialData.DxgkDdiSetPointerShape              = BddDdiSetPointerShape;    InitialData.DxgkDdiIsSupportedVidPn             = BddDdiIsSupportedVidPn;    InitialData.DxgkDdiRecommendFunctionalVidPn     = BddDdiRecommendFunctionalVidPn;    InitialData.DxgkDdiEnumVidPnCofuncModality      = BddDdiEnumVidPnCofuncModality;    InitialData.DxgkDdiSetVidPnSourceVisibility     = BddDdiSetVidPnSourceVisibility;    InitialData.DxgkDdiCommitVidPn                  = BddDdiCommitVidPn;    InitialData.DxgkDdiUpdateActiveVidPnPresentPath = BddDdiUpdateActiveVidPnPresentPath;    InitialData.DxgkDdiRecommendMonitorModes        = BddDdiRecommendMonitorModes;    InitialData.DxgkDdiQueryVidPnHWCapability       = BddDdiQueryVidPnHWCapability;    InitialData.DxgkDdiPresentDisplayOnly           = BddDdiPresentDisplayOnly;    InitialData.DxgkDdiStopDeviceAndReleasePostDisplayOwnership = BddDdiStopDeviceAndReleasePostDisplayOwnership;    InitialData.DxgkDdiSystemDisplayEnable          = BddDdiSystemDisplayEnable;    InitialData.DxgkDdiSystemDisplayWrite           = BddDdiSystemDisplayWrite;    NTSTATUS Status = DxgkInitializeDisplayOnlyDriver(pDriverObject, pRegistryPath, &InitialData);    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR1("DxgkInitializeDisplayOnlyDriver failed with Status: 0x%I64x", Status);        return Status;    }    return Status;}// END: Init Code#pragma code_seg(pop)#pragma code_seg(push)#pragma code_seg("PAGE")//// PnP DDIs//VOIDBddDdiUnload(VOID){    PAGED_CODE();}NTSTATUSBddDdiAddDevice(    _In_ DEVICE_OBJECT* pPhysicalDeviceObject,    _Outptr_ PVOID*  ppDeviceContext){    PAGED_CODE();    if ((pPhysicalDeviceObject == NULL) ||        (ppDeviceContext == NULL))    {        BDD_LOG_ERROR2("One of pPhysicalDeviceObject (0x%I64x), ppDeviceContext (0x%I64x) is NULL",                        pPhysicalDeviceObject, ppDeviceContext);        return STATUS_INVALID_PARAMETER;    }    *ppDeviceContext = NULL;    BASIC_DISPLAY_DRIVER* pBDD = new(NonPagedPoolNx) BASIC_DISPLAY_DRIVER(pPhysicalDeviceObject);    if (pBDD == NULL)    {        BDD_LOG_LOW_RESOURCE0("pBDD failed to be allocated");        return STATUS_NO_MEMORY;    }    *ppDeviceContext = pBDD;    return STATUS_SUCCESS;}NTSTATUSBddDdiRemoveDevice(    _In_  VOID* pDeviceContext){    PAGED_CODE();    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext);    if (pBDD)    {        delete pBDD;        pBDD = NULL;    }    return STATUS_SUCCESS;}NTSTATUSBddDdiStartDevice(    _In_  VOID*              pDeviceContext,    _In_  DXGK_START_INFO*   pDxgkStartInfo,    _In_  DXGKRNL_INTERFACE* pDxgkInterface,    _Out_ ULONG*             pNumberOfViews,    _Out_ ULONG*             pNumberOfChildren){    PAGED_CODE();    BDD_ASSERT_CHK(pDeviceContext != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext);    return pBDD->StartDevice(pDxgkStartInfo, pDxgkInterface, pNumberOfViews, pNumberOfChildren);}NTSTATUSBddDdiStopDevice(    _In_  VOID* pDeviceContext){    PAGED_CODE();    BDD_ASSERT_CHK(pDeviceContext != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext);    return pBDD->StopDevice();}NTSTATUSBddDdiDispatchIoRequest(    _In_  VOID*                 pDeviceContext,    _In_  ULONG                 VidPnSourceId,    _In_  VIDEO_REQUEST_PACKET* pVideoRequestPacket){    PAGED_CODE();    BDD_ASSERT_CHK(pDeviceContext != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext);    if (!pBDD->IsDriverActive())    {        BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);        return STATUS_UNSUCCESSFUL;    }    return pBDD->DispatchIoRequest(VidPnSourceId, pVideoRequestPacket);}NTSTATUSBddDdiSetPowerState(    _In_  VOID*              pDeviceContext,    _In_  ULONG              HardwareUid,    _In_  DEVICE_POWER_STATE DevicePowerState,    _In_  POWER_ACTION       ActionType){    PAGED_CODE();    BDD_ASSERT_CHK(pDeviceContext != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext);    if (!pBDD->IsDriverActive())    {        // If the driver isn't active, SetPowerState can still be called, however in BDD's case        // this shouldn't do anything, as it could for instance be called on BDD Fallback after        // Fallback has been stopped and BDD PnP is being started. Fallback doesn't have control        // of the hardware in this case.        return STATUS_SUCCESS;    }    return pBDD->SetPowerState(HardwareUid, DevicePowerState, ActionType);}NTSTATUSBddDdiQueryChildRelations(    _In_                             VOID*                  pDeviceContext,    _Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations,    _In_                             ULONG                  ChildRelationsSize){    PAGED_CODE();    BDD_ASSERT_CHK(pDeviceContext != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext);    return pBDD->QueryChildRelations(pChildRelations, ChildRelationsSize);}NTSTATUSBddDdiQueryChildStatus(    _In_    VOID*              pDeviceContext,    _Inout_ DXGK_CHILD_STATUS* pChildStatus,    _In_    BOOLEAN            NonDestructiveOnly){    PAGED_CODE();    BDD_ASSERT_CHK(pDeviceContext != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext);    return pBDD->QueryChildStatus(pChildStatus, NonDestructiveOnly);}NTSTATUSBddDdiQueryDeviceDescriptor(    _In_  VOID*                     pDeviceContext,    _In_  ULONG                     ChildUid,    _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor){    PAGED_CODE();    BDD_ASSERT_CHK(pDeviceContext != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext);    if (!pBDD->IsDriverActive())    {        // During stress testing of PnPStop, it is possible for BDD Fallback to get called to start then stop in quick succession.        // The first call queues a worker thread item indicating that it now has a child device, the second queues a worker thread        // item that it no longer has any child device. This function gets called based on the first worker thread item, but after        // the driver has been stopped. Therefore instead of asserting like other functions, we only warn.        BDD_LOG_WARNING1("BDD (0x%I64x) is being called when not active!", pBDD);        return STATUS_UNSUCCESSFUL;    }    return pBDD->QueryDeviceDescriptor(ChildUid, pDeviceDescriptor);}//// WDDM Display Only Driver DDIs//NTSTATUSAPIENTRYBddDdiQueryAdapterInfo(    _In_ CONST HANDLE                    hAdapter,    _In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo){    PAGED_CODE();    BDD_ASSERT_CHK(hAdapter != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter);    return pBDD->QueryAdapterInfo(pQueryAdapterInfo);}NTSTATUSAPIENTRYBddDdiSetPointerPosition(    _In_ CONST HANDLE                      hAdapter,    _In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition){    PAGED_CODE();    BDD_ASSERT_CHK(hAdapter != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter);    if (!pBDD->IsDriverActive())    {        BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);        return STATUS_UNSUCCESSFUL;    }    return pBDD->SetPointerPosition(pSetPointerPosition);}NTSTATUSAPIENTRYBddDdiSetPointerShape(    _In_ CONST HANDLE                   hAdapter,    _In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape){    PAGED_CODE();    BDD_ASSERT_CHK(hAdapter != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter);    if (!pBDD->IsDriverActive())    {        BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);        return STATUS_UNSUCCESSFUL;    }    return pBDD->SetPointerShape(pSetPointerShape);}NTSTATUSAPIENTRYBddDdiPresentDisplayOnly(    _In_ CONST HANDLE                       hAdapter,    _In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly){    PAGED_CODE();    BDD_ASSERT_CHK(hAdapter != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter);    if (!pBDD->IsDriverActive())    {        BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);        return STATUS_UNSUCCESSFUL;    }    return pBDD->PresentDisplayOnly(pPresentDisplayOnly);}NTSTATUSAPIENTRYBddDdiStopDeviceAndReleasePostDisplayOwnership(    _In_  VOID*                          pDeviceContext,    _In_  D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,    _Out_ DXGK_DISPLAY_INFORMATION*      DisplayInfo){    PAGED_CODE();    BDD_ASSERT_CHK(pDeviceContext != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext);    return pBDD->StopDeviceAndReleasePostDisplayOwnership(TargetId, DisplayInfo);}NTSTATUSAPIENTRYBddDdiIsSupportedVidPn(    _In_ CONST HANDLE                 hAdapter,    _Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn){    PAGED_CODE();    BDD_ASSERT_CHK(hAdapter != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter);    if (!pBDD->IsDriverActive())    {        // This path might hit because win32k/dxgport doesn't check that an adapter is active when taking the adapter lock.        // The adapter lock is the main thing BDD Fallback relies on to not be called while it's inactive. It is still a rare        // timing issue around PnpStart/Stop and isn't expected to have any effect on the stability of the system.        BDD_LOG_WARNING1("BDD (0x%I64x) is being called when not active!", pBDD);        return STATUS_UNSUCCESSFUL;    }    return pBDD->IsSupportedVidPn(pIsSupportedVidPn);}NTSTATUSAPIENTRYBddDdiRecommendFunctionalVidPn(    _In_ CONST HANDLE                                  hAdapter,    _In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn){    PAGED_CODE();    BDD_ASSERT_CHK(hAdapter != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter);    if (!pBDD->IsDriverActive())    {        BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);        return STATUS_UNSUCCESSFUL;    }    return pBDD->RecommendFunctionalVidPn(pRecommendFunctionalVidPn);}NTSTATUSAPIENTRYBddDdiRecommendVidPnTopology(    _In_ CONST HANDLE                                 hAdapter,    _In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST  pRecommendVidPnTopology){    PAGED_CODE();    BDD_ASSERT_CHK(hAdapter != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter);    if (!pBDD->IsDriverActive())    {        BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);        return STATUS_UNSUCCESSFUL;    }    return pBDD->RecommendVidPnTopology(pRecommendVidPnTopology);}NTSTATUSAPIENTRYBddDdiRecommendMonitorModes(    _In_ CONST HANDLE                                hAdapter,    _In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST  pRecommendMonitorModes){    PAGED_CODE();    BDD_ASSERT_CHK(hAdapter != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter);    if (!pBDD->IsDriverActive())    {        BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);        return STATUS_UNSUCCESSFUL;    }    return pBDD->RecommendMonitorModes(pRecommendMonitorModes);}NTSTATUSAPIENTRYBddDdiEnumVidPnCofuncModality(    _In_ CONST HANDLE                                 hAdapter,    _In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality){    PAGED_CODE();    BDD_ASSERT_CHK(hAdapter != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter);    if (!pBDD->IsDriverActive())    {        BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);        return STATUS_UNSUCCESSFUL;    }    return pBDD->EnumVidPnCofuncModality(pEnumCofuncModality);}NTSTATUSAPIENTRYBddDdiSetVidPnSourceVisibility(    _In_ CONST HANDLE                            hAdapter,    _In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility){    PAGED_CODE();    BDD_ASSERT_CHK(hAdapter != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter);    if (!pBDD->IsDriverActive())    {        BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);        return STATUS_UNSUCCESSFUL;    }    return pBDD->SetVidPnSourceVisibility(pSetVidPnSourceVisibility);}NTSTATUSAPIENTRYBddDdiCommitVidPn(    _In_ CONST HANDLE                     hAdapter,    _In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn){    PAGED_CODE();    BDD_ASSERT_CHK(hAdapter != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter);    if (!pBDD->IsDriverActive())    {        BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);        return STATUS_UNSUCCESSFUL;    }    return pBDD->CommitVidPn(pCommitVidPn);}NTSTATUSAPIENTRYBddDdiUpdateActiveVidPnPresentPath(    _In_ CONST HANDLE                                      hAdapter,    _In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath){    PAGED_CODE();    BDD_ASSERT_CHK(hAdapter != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter);    if (!pBDD->IsDriverActive())    {        BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);        return STATUS_UNSUCCESSFUL;    }    return pBDD->UpdateActiveVidPnPresentPath(pUpdateActiveVidPnPresentPath);}NTSTATUSAPIENTRYBddDdiQueryVidPnHWCapability(    _In_ CONST HANDLE                       hAdapter,    _Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps){    PAGED_CODE();    BDD_ASSERT_CHK(hAdapter != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(hAdapter);    if (!pBDD->IsDriverActive())    {        BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);        return STATUS_UNSUCCESSFUL;    }    return pBDD->QueryVidPnHWCapability(pVidPnHWCaps);}//END: Paged Code#pragma code_seg(pop)#pragma code_seg(push)#pragma code_seg()// BEGIN: Non-Paged CodeVOIDBddDdiDpcRoutine(    _In_  VOID* pDeviceContext){    BDD_ASSERT_CHK(pDeviceContext != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext);    if (!pBDD->IsDriverActive())    {        BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);        return;    }    pBDD->DpcRoutine();}BOOLEANBddDdiInterruptRoutine(    _In_  VOID* pDeviceContext,    _In_  ULONG MessageNumber){    BDD_ASSERT_CHK(pDeviceContext != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext);    return pBDD->InterruptRoutine(MessageNumber);}VOIDBddDdiResetDevice(    _In_  VOID* pDeviceContext){    BDD_ASSERT_CHK(pDeviceContext != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext);    pBDD->ResetDevice();}NTSTATUSAPIENTRYBddDdiSystemDisplayEnable(    _In_  VOID* pDeviceContext,    _In_  D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,    _In_  PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,    _Out_ UINT* Width,    _Out_ UINT* Height,    _Out_ D3DDDIFORMAT* ColorFormat){    BDD_ASSERT_CHK(pDeviceContext != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext);    return pBDD->SystemDisplayEnable(TargetId, Flags, Width, Height, ColorFormat);}VOIDAPIENTRYBddDdiSystemDisplayWrite(    _In_  VOID* pDeviceContext,    _In_  VOID* Source,    _In_  UINT  SourceWidth,    _In_  UINT  SourceHeight,    _In_  UINT  SourceStride,    _In_  UINT  PositionX,    _In_  UINT  PositionY){    BDD_ASSERT_CHK(pDeviceContext != NULL);    BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast(pDeviceContext);    pBDD->SystemDisplayWrite(Source, SourceWidth, SourceHeight, SourceStride, PositionX, PositionY);}// END: Non-Paged Code#pragma code_seg(pop)

C++程式檔案 bdd_dmm.cxx

/******************************Module*Header*******************************\* Module Name: bdd_dmm.hxx** Basic Display Driver display-mode management (DMM) function implementations*** Copyright (c) 2010 Microsoft Corporation\**************************************************************************/#include "BDD.hxx"#pragma code_seg("PAGE")// Display-Only Devices can only return display modes of D3DDDIFMT_A8R8G8B8.// Color conversion takes place if the app's fullscreen backbuffer has different format.// Full display drivers can add more if the hardware supports them.D3DDDIFORMAT gBddPixelFormats[] = {    D3DDDIFMT_A8R8G8B8};// TODO: Need to also check pinned modes and the path parameters, not just topologyNTSTATUS BASIC_DISPLAY_DRIVER::IsSupportedVidPn(_Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn){    PAGED_CODE();    BDD_ASSERT(pIsSupportedVidPn != NULL);    if (pIsSupportedVidPn->hDesiredVidPn == 0)    {        // A null desired VidPn is supported        pIsSupportedVidPn->IsVidPnSupported = TRUE;        return STATUS_SUCCESS;    }    // Default to not supported, until shown it is supported    pIsSupportedVidPn->IsVidPnSupported = FALSE;    CONST DXGK_VIDPN_INTERFACE* pVidPnInterface;    NTSTATUS Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pIsSupportedVidPn->hDesiredVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR2("DxgkCbQueryVidPnInterface failed with Status = 0x%I64x, hDesiredVidPn = 0x%I64x", Status, pIsSupportedVidPn->hDesiredVidPn);        return Status;    }    D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology;    CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface;    Status = pVidPnInterface->pfnGetTopology(pIsSupportedVidPn->hDesiredVidPn, &hVidPnTopology, &pVidPnTopologyInterface);    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR2("pfnGetTopology failed with Status = 0x%I64x, hDesiredVidPn = 0x%I64x", Status, pIsSupportedVidPn->hDesiredVidPn);        return Status;    }    // For every source in this topology, make sure they don't have more paths than there are targets    for (D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId = 0; SourceId < MAX_VIEWS; ++SourceId)    {        SIZE_T NumPathsFromSource = 0;        Status = pVidPnTopologyInterface->pfnGetNumPathsFromSource(hVidPnTopology, SourceId, &NumPathsFromSource);        if (Status == STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY)        {            continue;        }        else if (!NT_SUCCESS(Status))        {            BDD_LOG_ERROR3("pfnGetNumPathsFromSource failed with Status = 0x%I64x. hVidPnTopology = 0x%I64x, SourceId = 0x%I64x",                           Status, hVidPnTopology, SourceId);            return Status;        }        else if (NumPathsFromSource > MAX_CHILDREN)        {            // This VidPn is not supported, which has already been set as the default            return STATUS_SUCCESS;        }    }    // All sources succeeded so this VidPn is supported    pIsSupportedVidPn->IsVidPnSupported = TRUE;    return STATUS_SUCCESS;}NTSTATUS BASIC_DISPLAY_DRIVER::RecommendFunctionalVidPn(_In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn){    PAGED_CODE();    BDD_ASSERT(pRecommendFunctionalVidPn == NULL);    return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN;}NTSTATUS BASIC_DISPLAY_DRIVER::RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology){    PAGED_CODE();    BDD_ASSERT(pRecommendVidPnTopology == NULL);    return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN;}NTSTATUS BASIC_DISPLAY_DRIVER::RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes){    PAGED_CODE();    // This is always called to recommend modes for the monitor. The sample driver doesn't provide EDID for a monitor, so     // the OS prefills the list with default monitor modes. Since the required mode might not be in the list, it should     // be provided as a recommended mode.    return AddSingleMonitorMode(pRecommendMonitorModes);}// Tell DMM about all the modes, etc. that are supportedNTSTATUS BASIC_DISPLAY_DRIVER::EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality){    PAGED_CODE();    BDD_ASSERT(pEnumCofuncModality != NULL);    D3DKMDT_HVIDPNTOPOLOGY                   hVidPnTopology = 0;    D3DKMDT_HVIDPNSOURCEMODESET              hVidPnSourceModeSet = 0;    D3DKMDT_HVIDPNTARGETMODESET              hVidPnTargetModeSet = 0;    CONST DXGK_VIDPN_INTERFACE*              pVidPnInterface = NULL;    CONST DXGK_VIDPNTOPOLOGY_INTERFACE*      pVidPnTopologyInterface = NULL;    CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface = NULL;    CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface = NULL;    CONST D3DKMDT_VIDPN_PRESENT_PATH*        pVidPnPresentPath = NULL;    CONST D3DKMDT_VIDPN_PRESENT_PATH*        pVidPnPresentPathTemp = NULL; // Used for AcquireNextPathInfo    CONST D3DKMDT_VIDPN_SOURCE_MODE*         pVidPnPinnedSourceModeInfo = NULL;    CONST D3DKMDT_VIDPN_TARGET_MODE*         pVidPnPinnedTargetModeInfo = NULL;    // Get the VidPn Interface so we can get the 'Source Mode Set', 'Target Mode Set' and 'VidPn Topology' interfaces    NTSTATUS Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pEnumCofuncModality->hConstrainingVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR2("DxgkCbQueryVidPnInterface failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn);        return Status;    }    // Get the VidPn Topology interface so we can enumerate all paths    Status = pVidPnInterface->pfnGetTopology(pEnumCofuncModality->hConstrainingVidPn, &hVidPnTopology, &pVidPnTopologyInterface);    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR2("pfnGetTopology failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn);        return Status;    }    // Get the first path before we start looping through them    Status = pVidPnTopologyInterface->pfnAcquireFirstPathInfo(hVidPnTopology, &pVidPnPresentPath);    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR2("pfnAcquireFirstPathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology);        return Status;    }    // Loop through all available paths.    while (Status != STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET)    {        // Get the Source Mode Set interface so the pinned mode can be retrieved        Status = pVidPnInterface->pfnAcquireSourceModeSet(pEnumCofuncModality->hConstrainingVidPn,                                                          pVidPnPresentPath->VidPnSourceId,                                                          &hVidPnSourceModeSet,                                                          &pVidPnSourceModeSetInterface);        if (!NT_SUCCESS(Status))        {            BDD_LOG_ERROR3("pfnAcquireSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x",                           Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId);            break;        }        // Get the pinned mode, needed when VidPnSource isn't pivot, and when VidPnTarget isn't pivot        Status = pVidPnSourceModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnSourceModeSet, &pVidPnPinnedSourceModeInfo);        if (!NT_SUCCESS(Status))        {            BDD_LOG_ERROR2("pfnAcquirePinnedModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet);            break;        }        // SOURCE MODES: If this source mode isn't the pivot point, do work on the source mode set        if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_VIDPNSOURCE) &&              (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId)))        {            // If there's no pinned source add possible modes (otherwise they've already been added)            if (pVidPnPinnedSourceModeInfo == NULL)            {                // Release the acquired source mode set, since going to create a new one to put all modes in                Status = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);                if (!NT_SUCCESS(Status))                {                    BDD_LOG_ERROR3("pfnReleaseSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnSourceModeSet = 0x%I64x",                                   Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);                    break;                }                hVidPnSourceModeSet = 0; // Successfully released it                // Create a new source mode set which will be added to the constraining VidPn with all the possible modes                Status = pVidPnInterface->pfnCreateNewSourceModeSet(pEnumCofuncModality->hConstrainingVidPn,                                                                    pVidPnPresentPath->VidPnSourceId,                                                                    &hVidPnSourceModeSet,                                                                    &pVidPnSourceModeSetInterface);                if (!NT_SUCCESS(Status))                {                    BDD_LOG_ERROR3("pfnCreateNewSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x",                                   Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId);                    break;                }                // Add the appropriate modes to the source mode set                {                    Status = AddSingleSourceMode(pVidPnSourceModeSetInterface, hVidPnSourceModeSet, pVidPnPresentPath->VidPnSourceId);                }                if (!NT_SUCCESS(Status))                {                    break;                }                // Give DMM back the source modes just populated                Status = pVidPnInterface->pfnAssignSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, hVidPnSourceModeSet);                if (!NT_SUCCESS(Status))                {                    BDD_LOG_ERROR4("pfnAssignSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x, hVidPnSourceModeSet = 0x%I64x",                                   Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, hVidPnSourceModeSet);                    break;                }                hVidPnSourceModeSet = 0; // Successfully assigned it (equivalent to releasing it)            }        }// End: SOURCE MODES        // TARGET MODES: If this target mode isn't the pivot point, do work on the target mode set        if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_VIDPNTARGET) &&              (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId)))        {            // Get the Target Mode Set interface so modes can be added if necessary            Status = pVidPnInterface->pfnAcquireTargetModeSet(pEnumCofuncModality->hConstrainingVidPn,                                                              pVidPnPresentPath->VidPnTargetId,                                                              &hVidPnTargetModeSet,                                                              &pVidPnTargetModeSetInterface);            if (!NT_SUCCESS(Status))            {                BDD_LOG_ERROR3("pfnAcquireTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x",                               Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId);                break;            }            Status = pVidPnTargetModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnTargetModeSet, &pVidPnPinnedTargetModeInfo);            if (!NT_SUCCESS(Status))            {                BDD_LOG_ERROR2("pfnAcquirePinnedModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", Status, hVidPnTargetModeSet);                break;            }            // If there's no pinned target add possible modes (otherwise they've already been added)            if (pVidPnPinnedTargetModeInfo == NULL)            {                // Release the acquired target mode set, since going to create a new one to put all modes in                Status = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);                if (!NT_SUCCESS(Status))                {                    BDD_LOG_ASSERTION3("pfnReleaseTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnTargetModeSet = 0x%I64x",                                       Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);                    break;                }                hVidPnTargetModeSet = 0; // Successfully released it                // Create a new target mode set which will be added to the constraining VidPn with all the possible modes                Status = pVidPnInterface->pfnCreateNewTargetModeSet(pEnumCofuncModality->hConstrainingVidPn,                                                                    pVidPnPresentPath->VidPnTargetId,                                                                    &hVidPnTargetModeSet,                                                                    &pVidPnTargetModeSetInterface);                if (!NT_SUCCESS(Status))                {                    BDD_LOG_ERROR3("pfnCreateNewTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x",                                   Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId);                    break;                }                Status = AddSingleTargetMode(pVidPnTargetModeSetInterface, hVidPnTargetModeSet, pVidPnPinnedSourceModeInfo, pVidPnPresentPath->VidPnSourceId);                if (!NT_SUCCESS(Status))                {                    break;                }                // Give DMM back the source modes just populated                Status = pVidPnInterface->pfnAssignTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, hVidPnTargetModeSet);                if (!NT_SUCCESS(Status))                {                    BDD_LOG_ERROR4("pfnAssignTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x, hVidPnTargetModeSet = 0x%I64x",                                   Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, hVidPnTargetModeSet);                    break;                }                hVidPnTargetModeSet = 0; // Successfully assigned it (equivalent to releasing it)            }            else            {                // Release the pinned target as there's no other work to do                Status = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo);                if (!NT_SUCCESS(Status))                {                    BDD_LOG_ASSERTION3("pfnReleaseModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x, pVidPnPinnedTargetModeInfo = 0x%I64x",                                        Status, hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo);                    break;                }                pVidPnPinnedTargetModeInfo = NULL; // Successfully released it                // Release the acquired target mode set, since it is no longer needed                Status = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);                if (!NT_SUCCESS(Status))                {                    BDD_LOG_ASSERTION3("pfnReleaseTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnTargetModeSet = 0x%I64x",                                       Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);                    break;                }                hVidPnTargetModeSet = 0; // Successfully released it            }        }// End: TARGET MODES        // Nothing else needs the pinned source mode so release it        if (pVidPnPinnedSourceModeInfo != NULL)        {            Status = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo);            if (!NT_SUCCESS(Status))            {                BDD_LOG_ASSERTION3("pfnReleaseModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x, pVidPnPinnedSourceModeInfo = 0x%I64x",                                    Status, hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo);                break;            }            pVidPnPinnedSourceModeInfo = NULL; // Successfully released it        }        // With the pinned source mode now released, if the source mode set hasn't been released, release that as well        if (hVidPnSourceModeSet != 0)        {            Status = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);            if (!NT_SUCCESS(Status))            {                BDD_LOG_ERROR3("pfnReleaseSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnSourceModeSet = 0x%I64x",                               Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);                break;            }            hVidPnSourceModeSet = 0; // Successfully released it        }        // If modifying support fields, need to modify a local version of a path structure since the retrieved one is const        D3DKMDT_VIDPN_PRESENT_PATH LocalVidPnPresentPath = *pVidPnPresentPath;        BOOLEAN SupportFieldsModified = FALSE;        // SCALING: If this path's scaling isn't the pivot point, do work on the scaling support        if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_SCALING) &&              (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId) &&              (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId)))        {            // If the scaling is unpinned, then modify the scaling support field            if (pVidPnPresentPath->ContentTransformation.Scaling == D3DKMDT_VPPS_UNPINNED)            {                // Identity and centered scaling are supported, but not any stretch modes                RtlZeroMemory(&(LocalVidPnPresentPath.ContentTransformation.ScalingSupport), sizeof(D3DKMDT_VIDPN_PRESENT_PATH_SCALING_SUPPORT));                LocalVidPnPresentPath.ContentTransformation.ScalingSupport.Identity = 1;                LocalVidPnPresentPath.ContentTransformation.ScalingSupport.Centered = 1;                SupportFieldsModified = TRUE;            }        } // End: SCALING        // ROTATION: If this path's rotation isn't the pivot point, do work on the rotation support        if (!((pEnumCofuncModality->EnumPivotType != D3DKMDT_EPT_ROTATION) &&              (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId) &&              (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId)))        {            // If the rotation is unpinned, then modify the rotation support field            if (pVidPnPresentPath->ContentTransformation.Rotation == D3DKMDT_VPPR_UNPINNED)            {                LocalVidPnPresentPath.ContentTransformation.RotationSupport.Identity = 1;                // Sample supports only Rotate90                LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate90 = 1;                LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate180 = 0;                LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate270 = 0;                // Since clone is not supported, should not support path-independent rotations                LocalVidPnPresentPath.ContentTransformation.RotationSupport.Offset0 = 1;                SupportFieldsModified = TRUE;            }        } // End: ROTATION        if (SupportFieldsModified)        {            // The correct path will be found by this function and the appropriate fields updated            Status = pVidPnTopologyInterface->pfnUpdatePathSupportInfo(hVidPnTopology, &LocalVidPnPresentPath);            if (!NT_SUCCESS(Status))            {                BDD_LOG_ERROR2("pfnUpdatePathSupportInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology);                break;            }        }        // Get the next path...        // (NOTE: This is the value of Status that will return STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET when it's time to quit the loop)        pVidPnPresentPathTemp = pVidPnPresentPath;        Status = pVidPnTopologyInterface->pfnAcquireNextPathInfo(hVidPnTopology, pVidPnPresentPathTemp, &pVidPnPresentPath);        if (!NT_SUCCESS(Status))        {            BDD_LOG_ERROR3("pfnAcquireNextPathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, pVidPnPresentPathTemp = 0x%I64x", Status, hVidPnTopology, pVidPnPresentPathTemp);            break;        }        // ...and release the last path        NTSTATUS TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPathTemp);        if (!NT_SUCCESS(TempStatus))        {            BDD_LOG_ERROR3("pfnReleasePathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, pVidPnPresentPathTemp = 0x%I64x", TempStatus, hVidPnTopology, pVidPnPresentPathTemp);            Status = TempStatus;            break;        }        pVidPnPresentPathTemp = NULL; // Successfully released it    }// End: while loop for paths in topology    // If quit the while loop normally, set the return value to success    if (Status == STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET)    {        Status = STATUS_SUCCESS;    }    // Release any resources hanging around because the loop was quit early.    // Since in normal execution everything should be released by this point, TempStatus is initialized to a bogus error to be used as an    //  assertion that if anything had to be released now (TempStatus changing) Status isn't successful.    NTSTATUS TempStatus = STATUS_NOT_FOUND;    if ((pVidPnSourceModeSetInterface != NULL) &&        (pVidPnPinnedSourceModeInfo != NULL))    {        TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo);        BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));    }    if ((pVidPnTargetModeSetInterface != NULL) &&        (pVidPnPinnedTargetModeInfo != NULL))    {        TempStatus = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo);        BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));    }    if (pVidPnPresentPath != NULL)    {        TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath);        BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));    }    if (pVidPnPresentPathTemp != NULL)    {        TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPathTemp);        BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));    }    if (hVidPnSourceModeSet != 0)    {        TempStatus = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);        BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));    }    if (hVidPnTargetModeSet != 0)    {        TempStatus = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);        BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));    }    BDD_ASSERT_CHK(TempStatus == STATUS_NOT_FOUND || Status != STATUS_SUCCESS);    return Status;}NTSTATUS BASIC_DISPLAY_DRIVER::SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility){    PAGED_CODE();    BDD_ASSERT(pSetVidPnSourceVisibility != NULL);    BDD_ASSERT((pSetVidPnSourceVisibility->VidPnSourceId < MAX_VIEWS) ||               (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL));    UINT StartVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? 0 : pSetVidPnSourceVisibility->VidPnSourceId;    UINT MaxVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? MAX_VIEWS : pSetVidPnSourceVisibility->VidPnSourceId + 1;    for (UINT SourceId = StartVidPnSourceId; SourceId < MaxVidPnSourceId; ++SourceId)    {        if (pSetVidPnSourceVisibility->Visible)        {            m_CurrentModes[SourceId].Flags.FullscreenPresent = TRUE;        }        else        {            BlackOutScreen(SourceId);        }        // Store current visibility so it can be dealt with during Present call        m_CurrentModes[SourceId].Flags.SourceNotVisible = !(pSetVidPnSourceVisibility->Visible);    }    return STATUS_SUCCESS;}// NOTE: The value of pCommitVidPn->MonitorConnectivityChecks is ignored, since BDD is unable to recognize whether a monitor is connected or not// The value of pCommitVidPn->hPrimaryAllocation is also ignored, since BDD is a display only driver and does not deal with allocationsNTSTATUS BASIC_DISPLAY_DRIVER::CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn){    PAGED_CODE();    BDD_ASSERT(pCommitVidPn != NULL);    BDD_ASSERT(pCommitVidPn->AffectedVidPnSourceId < MAX_VIEWS);    NTSTATUS                                 Status;    SIZE_T                                   NumPaths = 0;    D3DKMDT_HVIDPNTOPOLOGY                   hVidPnTopology = 0;    D3DKMDT_HVIDPNSOURCEMODESET              hVidPnSourceModeSet = 0;    CONST DXGK_VIDPN_INTERFACE*              pVidPnInterface = NULL;    CONST DXGK_VIDPNTOPOLOGY_INTERFACE*      pVidPnTopologyInterface = NULL;    CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface = NULL;    CONST D3DKMDT_VIDPN_PRESENT_PATH*        pVidPnPresentPath = NULL;    CONST D3DKMDT_VIDPN_SOURCE_MODE*         pPinnedVidPnSourceModeInfo = NULL;    // Check this CommitVidPn is for the mode change notification when monitor is in power off state.    if (pCommitVidPn->Flags.PathPoweredOff)    {        // Ignore the commitVidPn call for the mode change notification when monitor is in power off state.        Status = STATUS_SUCCESS;        goto CommitVidPnExit;    }    // Get the VidPn Interface so we can get the 'Source Mode Set' and 'VidPn Topology' interfaces    Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pCommitVidPn->hFunctionalVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR2("DxgkCbQueryVidPnInterface failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn);        goto CommitVidPnExit;    }    // Get the VidPn Topology interface so can enumerate paths from source    Status = pVidPnInterface->pfnGetTopology(pCommitVidPn->hFunctionalVidPn, &hVidPnTopology, &pVidPnTopologyInterface);    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR2("pfnGetTopology failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn);        goto CommitVidPnExit;    }    // Find out the number of paths now, if it's 0 don't bother with source mode set and pinned mode, just clear current and then quit    Status = pVidPnTopologyInterface->pfnGetNumPaths(hVidPnTopology, &NumPaths);    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR2("pfnGetNumPaths failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology);        goto CommitVidPnExit;    }    if (NumPaths != 0)    {        // Get the Source Mode Set interface so we can get the pinned mode        Status = pVidPnInterface->pfnAcquireSourceModeSet(pCommitVidPn->hFunctionalVidPn,                                                          pCommitVidPn->AffectedVidPnSourceId,                                                          &hVidPnSourceModeSet,                                                          &pVidPnSourceModeSetInterface);        if (!NT_SUCCESS(Status))        {            BDD_LOG_ERROR3("pfnAcquireSourceModeSet failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x, SourceId = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn, pCommitVidPn->AffectedVidPnSourceId);            goto CommitVidPnExit;        }        // Get the mode that is being pinned        Status = pVidPnSourceModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnSourceModeSet, &pPinnedVidPnSourceModeInfo);        if (!NT_SUCCESS(Status))        {            BDD_LOG_ERROR2("pfnAcquirePinnedModeInfo failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn);            goto CommitVidPnExit;        }    }    else    {        // This will cause the successful quit below        pPinnedVidPnSourceModeInfo = NULL;    }    if (m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr &&        !m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].Flags.DoNotMapOrUnmap)    {        Status = UnmapFrameBuffer(m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr,                                  m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].DispInfo.Pitch * m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].DispInfo.Height);        m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr = NULL;        m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].Flags.FrameBufferIsActive = FALSE;        if (!NT_SUCCESS(Status))        {            goto CommitVidPnExit;        }    }    if (pPinnedVidPnSourceModeInfo == NULL)    {        // There is no mode to pin on this source, any old paths here have already been cleared        Status = STATUS_SUCCESS;        goto CommitVidPnExit;    }    Status = IsVidPnSourceModeFieldsValid(pPinnedVidPnSourceModeInfo);    if (!NT_SUCCESS(Status))    {        goto CommitVidPnExit;    }    // Get the number of paths from this source so we can loop through all paths    SIZE_T NumPathsFromSource = 0;    Status = pVidPnTopologyInterface->pfnGetNumPathsFromSource(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, &NumPathsFromSource);    if (!NT_SUCCESS(Status))    {        BDD_LOG_ERROR2("pfnGetNumPathsFromSource failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology);        goto CommitVidPnExit;    }    // Loop through all paths to set this mode    for (SIZE_T PathIndex = 0; PathIndex < NumPathsFromSource; ++PathIndex)    {        // Get the target id for this path        D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId = D3DDDI_ID_UNINITIALIZED;        Status = pVidPnTopologyInterface->pfnEnumPathTargetsFromSource(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, PathIndex, &TargetId);        if (!NT_SUCCESS(Status))        {            BDD_LOG_ERROR4("pfnEnumPathTargetsFromSource failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, SourceId = 0x%I64x, PathIndex = 0x%I64x",                            Status, hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, PathIndex);            goto CommitVidPnExit;        }        // Get the actual path info        Status = pVidPnTopologyInterface->pfnAcquirePathInfo(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, TargetId, &pVidPnPresentPath);        if (!NT_SUCCESS(Status))        {            BDD_LOG_ERROR4("pfnAcquirePathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, SourceId = 0x%I64x, TargetId = 0x%I64x",                            Status, hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, TargetId);            goto CommitVidPnExit;        }        Status = IsVidPnPathFieldsValid(pVidPnPresentPath);        if (!NT_SUCCESS(Status))        {            goto CommitVidPnExit;        }        Status = SetSourceModeAndPath(pPinnedVidPnSourceModeInfo, pVidPnPresentPath);        if (!NT_SUCCESS(Status))        {            goto CommitVidPnExit;        }        Status = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath);        if (!NT_SUCCESS(Status))        {            BDD_LOG_ERROR3("pfnReleasePathInfo failed with Status = 0x%I64x, hVidPnTopoogy = 0x%I64x, pVidPnPresentPath = 0x%I64x",                            Status, hVidPnTopology, pVidPnPresentPath);            goto CommitVidPnExit;        }        pVidPnPresentPath = NULL; // Successfully released it    }CommitVidPnExit:    NTSTATUS TempStatus;    if ((pVidPnSourceModeSetInterface != NULL) &&        (hVidPnSourceModeSet != 0) &&        (pPinnedVidPnSourceModeInfo != NULL))    {        TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pPinnedVidPnSourceModeInfo);        NT_ASSERT(NT_SUCCESS(TempStatus));    }    if ((pVidPnInterface != NULL) &&        (pCommitVidPn->hFunctionalVidPn != 0) &&        (hVidPnSourceModeSet != 0))    {        TempStatus = pVidPnInterface->pfnReleaseSourceModeSet(pCommitVidPn->hFunctionalVidPn, hVidPnSourceModeSet);        NT_ASSERT(NT_SUCCESS(TempStatus));    }    if ((pVidPnTopologyInterface != NULL) &&        (hVidPnTopology != 0) &&        (pVidPnPresentPath != NULL))    {        TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath);        NT_ASSERT(NT_SUCCESS(TempStatus));    }    return Status;}NTSTATUS BASIC_DISPLAY_DRIVER::UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath){    PAGED_CODE();    BDD_ASSERT(pUpdateActiveVidPnPresentPath != NULL);    NTSTATUS Status = IsVidPnPathFieldsValid(&(pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo));    if (!NT_SUCCESS(Status))    {        return Status;    }    // Mark the next present as fullscreen to make sure the full rotation comes through    m_CurrentModes[pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.VidPnSourceId].Flags.FullscreenPresent = TRUE;    m_CurrentModes[pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.VidPnSourceId].Rotation = pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.ContentTransformation.Rotation;    return STATUS_SUCCESS;}//// Private BDD DMM functions//NTSTATUS BASIC_DISPLAY_DRIVER::SetSourceModeAndPath(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode,                                                    CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath){    PAGED_CODE();    CURRENT_BDD_MODE* pCurrentBddMode = &m_CurrentModes[pPath->VidPnSourceId];    NTSTATUS Status = STATUS_SUCCESS;    pCurrentBddMode->Scaling = pPath->ContentTransformation.Scaling;    pCurrentBddMode->SrcModeWidth = pSourceMode->Format.Graphics.PrimSurfSize.cx;    pCurrentBddMode->SrcModeHeight = pSourceMode->Format.Graphics.PrimSurfSize.cy;    pCurrentBddMode->Rotation = pPath->ContentTransformation.Rotation;    if (!pCurrentBddMode->Flags.DoNotMapOrUnmap)    {        // Map the new frame buffer        BDD_ASSERT(pCurrentBddMode->FrameBuffer.Ptr == NULL);        Status = MapFrameBuffer(pCurrentBddMode->DispInfo.PhysicAddress,                                pCurrentBddMode->DispInfo.Pitch * pCurrentBddMode->DispInfo.Height,                                &(pCurrentBddMode->FrameBuffer.Ptr));    }    if (NT_SUCCESS(Status))    {        pCurrentBddMode->Flags.FrameBufferIsActive = TRUE;        BlackOutScreen(pPath->VidPnSourceId);        // Mark that the next present should be fullscreen so the screen doesn't go from black to actual pixels one dirty rect at a time.        pCurrentBddMode->Flags.FullscreenPresent = TRUE;    }    return Status;}NTSTATUS BASIC_DISPLAY_DRIVER::IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const{    PAGED_CODE();    if (pPath->VidPnSourceId >= MAX_VIEWS)    {        BDD_LOG_ERROR2("VidPnSourceId is 0x%I64x is too high (MAX_VIEWS is 0x%I64x)",                        pPath->VidPnSourceId, MAX_VIEWS);        return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE;    }    else if (pPath->VidPnTargetId >= MAX_CHILDREN)    {        BDD_LOG_ERROR2("VidPnTargetId is 0x%I64x is too high (MAX_CHILDREN is 0x%I64x)",                        pPath->VidPnTargetId, MAX_CHILDREN);        return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET;    }    else if (pPath->GammaRamp.Type != D3DDDI_GAMMARAMP_DEFAULT)    {        BDD_LOG_ERROR1("pPath contains a gamma ramp (0x%I64x)", pPath->GammaRamp.Type);        return STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED;    }    else if ((pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_IDENTITY) &&             (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_CENTERED) &&             (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_NOTSPECIFIED) &&             (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_UNINITIALIZED))    {        BDD_LOG_ERROR1("pPath contains a non-identity scaling (0x%I64x)", pPath->ContentTransformation.Scaling);        return STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED;    }    else if ((pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_IDENTITY) &&             (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_ROTATE90) &&             (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_NOTSPECIFIED) &&             (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_UNINITIALIZED))    {        BDD_LOG_ERROR1("pPath contains a not-supported rotation (0x%I64x)", pPath->ContentTransformation.Rotation);        return STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED;    }    else if ((pPath->VidPnTargetColorBasis != D3DKMDT_CB_SCRGB) &&             (pPath->VidPnTargetColorBasis != D3DKMDT_CB_UNINITIALIZED))    {        BDD_LOG_ERROR1("pPath has a non-linear RGB color basis (0x%I64x)", pPath->VidPnTargetColorBasis);        return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;    }    else    {        return STATUS_SUCCESS;    }}NTSTATUS BASIC_DISPLAY_DRIVER::IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const{    PAGED_CODE();    if (pSourceMode->Type != D3DKMDT_RMT_GRAPHICS)    {        BDD_LOG_ERROR1("pSourceMode is a non-graphics mode (0x%I64x)", pSourceMode->Type);        return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;    }    else if ((pSourceMode->Format.Graphics.ColorBasis != D3DKMDT_CB_SCRGB) &&             (pSourceMode->Format.Graphics.ColorBasis != D3DKMDT_CB_UNINITIALIZED))    {        BDD_LOG_ERROR1("pSourceMode has a non-linear RGB color basis (0x%I64x)", pSourceMode->Format.Graphics.ColorBasis);        return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;    }    else if (pSourceMode->Format.Graphics.PixelValueAccessMode != D3DKMDT_PVAM_DIRECT)    {        BDD_LOG_ERROR1("pSourceMode has a palettized access mode (0x%I64x)", pSourceMode->Format.Graphics.PixelValueAccessMode);        return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;    }    else    {        for (UINT PelFmtIdx = 0; PelFmtIdx < ARRAYSIZE(gBddPixelFormats); ++PelFmtIdx)        {            if (pSourceMode->Format.Graphics.PixelFormat == gBddPixelFormats[PelFmtIdx])            {                return STATUS_SUCCESS;            }        }        BDD_LOG_ERROR1("pSourceMode has an unknown pixel format (0x%I64x)", pSourceMode->Format.Graphics.PixelFormat);        return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;    }}// Add more mode from the table.struct SampleSourceMode{    UINT ModeWidth;    UINT ModeHeight;};// The driver will advertise all modes that fit within the actual required mode (see AddSingleSourceMode below)const static SampleSourceMode C_SampleSourceMode[] = {{800,600},{1024,768},{1152,864},{1280,800},{1280,1024},{1400,1050},{1600,1200},{1680,1050},{1920,1200}};const static UINT C_SampleSourceModeMax = sizeof(C_SampleSourceMode)/sizeof(C_SampleSourceMode[0]);NTSTATUS BASIC_DISPLAY_DRIVER::AddSingleSourceMode(_In_ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface,                                                   D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet,                                                   D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId){    PAGED_CODE();    // There is only one source format supported by display-only drivers, but more can be added in a     // full WDDM driver if the hardware supports them    for (UINT PelFmtIdx = 0; PelFmtIdx < ARRAYSIZE(gBddPixelFormats); ++PelFmtIdx)    {        // Create new mode info that will be populated        D3DKMDT_VIDPN_SOURCE_MODE* pVidPnSourceModeInfo = NULL;        NTSTATUS Status = pVidPnSourceModeSetInterface->pfnCreateNewModeInfo(hVidPnSourceModeSet, &pVidPnSourceModeInfo);        if (!NT_SUCCESS(Status))        {            // If failed to create a new mode info, mode doesn't need to be released since it was never created            BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet);            return Status;        }        // Populate mode info with values from current mode and hard-coded values        // Always report 32 bpp format, this will be color converted during the present if the mode is < 32bpp        pVidPnSourceModeInfo->Type = D3DKMDT_RMT_GRAPHICS;        pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cx = m_CurrentModes[SourceId].DispInfo.Width;        pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy = m_CurrentModes[SourceId].DispInfo.Height;        pVidPnSourceModeInfo->Format.Graphics.VisibleRegionSize = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize;        pVidPnSourceModeInfo->Format.Graphics.Stride = m_CurrentModes[SourceId].DispInfo.Pitch;        pVidPnSourceModeInfo->Format.Graphics.PixelFormat = gBddPixelFormats[PelFmtIdx];        pVidPnSourceModeInfo->Format.Graphics.ColorBasis = D3DKMDT_CB_SCRGB;        pVidPnSourceModeInfo->Format.Graphics.PixelValueAccessMode = D3DKMDT_PVAM_DIRECT;        // Add the mode to the source mode set        Status = pVidPnSourceModeSetInterface->pfnAddMode(hVidPnSourceModeSet, pVidPnSourceModeInfo);        if (!NT_SUCCESS(Status))        {            // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked            NTSTATUS TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnSourceModeInfo);            UNREFERENCED_PARAMETER(TempStatus);            NT_ASSERT(NT_SUCCESS(TempStatus));            if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)            {                BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x, pVidPnSourceModeInfo = 0x%I64x", Status, hVidPnSourceModeSet, pVidPnSourceModeInfo);                return Status;            }        }    }    UINT WidthMax = m_CurrentModes[SourceId].DispInfo.Width;    UINT HeightMax = m_CurrentModes[SourceId].DispInfo.Height;    // Add all predefined modes that fit within the bounds of the required (POST) mode    for (UINT ModeIndex = 0; ModeIndex < C_SampleSourceModeMax; ++ModeIndex)    {        if (C_SampleSourceMode[ModeIndex].ModeWidth > WidthMax)        {            break;        }        else if (C_SampleSourceMode[ModeIndex].ModeWidth == WidthMax)        {            if(C_SampleSourceMode[ModeIndex].ModeHeight >= HeightMax)            {                break;            }        }        else        {            if(C_SampleSourceMode[ModeIndex].ModeHeight > HeightMax)            {                continue;            }        }        // There is only one source format supported by display-only drivers, but more can be added in a         // full WDDM driver if the hardware supports them        for (UINT PelFmtIdx = 0; PelFmtIdx < ARRAYSIZE(gBddPixelFormats); ++PelFmtIdx)        {            // Create new mode info that will be populated            D3DKMDT_VIDPN_SOURCE_MODE* pVidPnSourceModeInfo = NULL;            NTSTATUS Status = pVidPnSourceModeSetInterface->pfnCreateNewModeInfo(hVidPnSourceModeSet, &pVidPnSourceModeInfo);            if (!NT_SUCCESS(Status))            {                // If failed to create a new mode info, continuing to the next mode and trying again isn't going to be at all helpful, so return                // Also, mode doesn't need to be released since it was never created                BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet);                return Status;            }            // Populate mode info with values from mode at ModeIndex and hard-coded values            // Always report 32 bpp format, this will be color converted during the present if the mode at ModeIndex was < 32bpp            pVidPnSourceModeInfo->Type = D3DKMDT_RMT_GRAPHICS;            pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cx = C_SampleSourceMode[ModeIndex].ModeWidth;            pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy = C_SampleSourceMode[ModeIndex].ModeHeight;            pVidPnSourceModeInfo->Format.Graphics.VisibleRegionSize = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize;            pVidPnSourceModeInfo->Format.Graphics.Stride = 4*C_SampleSourceMode[ModeIndex].ModeWidth;            pVidPnSourceModeInfo->Format.Graphics.PixelFormat = gBddPixelFormats[PelFmtIdx];            pVidPnSourceModeInfo->Format.Graphics.ColorBasis = D3DKMDT_CB_SCRGB;            pVidPnSourceModeInfo->Format.Graphics.PixelValueAccessMode = D3DKMDT_PVAM_DIRECT;            // Add the mode to the source mode set            Status = pVidPnSourceModeSetInterface->pfnAddMode(hVidPnSourceModeSet, pVidPnSourceModeInfo);            if (!NT_SUCCESS(Status))            {                if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)                {                    BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x, pVidPnSourceModeInfo = 0x%I64x", Status, hVidPnSourceModeSet, pVidPnSourceModeInfo);                }                // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked, continue to next mode anyway                Status = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnSourceModeInfo);                BDD_ASSERT_CHK(NT_SUCCESS(Status));            }        }    }    return STATUS_SUCCESS;}// Add the current mode information (acquired from the POST frame buffer) as the target mode.NTSTATUS BASIC_DISPLAY_DRIVER::AddSingleTargetMode(_In_ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface,                                                   D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet,                                                   _In_opt_ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo,                                                   D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId){    PAGED_CODE();    D3DKMDT_VIDPN_TARGET_MODE* pVidPnTargetModeInfo = NULL;    NTSTATUS Status = pVidPnTargetModeSetInterface->pfnCreateNewModeInfo(hVidPnTargetModeSet, &pVidPnTargetModeInfo);    if (!NT_SUCCESS(Status))    {        // If failed to create a new mode info, mode doesn't need to be released since it was never created        BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", Status, hVidPnTargetModeSet);        return Status;    }    pVidPnTargetModeInfo->VideoSignalInfo.VideoStandard = D3DKMDT_VSS_OTHER;    UNREFERENCED_PARAMETER(pVidPnPinnedSourceModeInfo);    pVidPnTargetModeInfo->VideoSignalInfo.TotalSize.cx = m_CurrentModes[SourceId].DispInfo.Width;    pVidPnTargetModeInfo->VideoSignalInfo.TotalSize.cy = m_CurrentModes[SourceId].DispInfo.Height;    pVidPnTargetModeInfo->VideoSignalInfo.ActiveSize = pVidPnTargetModeInfo->VideoSignalInfo.TotalSize;    pVidPnTargetModeInfo->VideoSignalInfo.VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;    pVidPnTargetModeInfo->VideoSignalInfo.VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;    pVidPnTargetModeInfo->VideoSignalInfo.HSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;    pVidPnTargetModeInfo->VideoSignalInfo.HSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;    pVidPnTargetModeInfo->VideoSignalInfo.PixelRate = D3DKMDT_FREQUENCY_NOTSPECIFIED;    pVidPnTargetModeInfo->VideoSignalInfo.ScanLineOrdering = D3DDDI_VSSLO_PROGRESSIVE;    // We add this as PREFERRED since it is the only supported target    pVidPnTargetModeInfo->Preference = D3DKMDT_MP_PREFERRED;    Status = pVidPnTargetModeSetInterface->pfnAddMode(hVidPnTargetModeSet, pVidPnTargetModeInfo);    if (!NT_SUCCESS(Status))    {        if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)        {            BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x, pVidPnTargetModeInfo = 0x%I64x", Status, hVidPnTargetModeSet, pVidPnTargetModeInfo);        }        else        {            Status = STATUS_SUCCESS;        }        // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked        NTSTATUS TempStatus = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnTargetModeInfo);        UNREFERENCED_PARAMETER(TempStatus);        NT_ASSERT(NT_SUCCESS(TempStatus));        return Status;    }    else    {        // If AddMode succeeded with something other than STATUS_SUCCESS treat it as such anyway when propagating up        return STATUS_SUCCESS;    }}NTSTATUS BASIC_DISPLAY_DRIVER::AddSingleMonitorMode(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes){    PAGED_CODE();    D3DKMDT_MONITOR_SOURCE_MODE* pMonitorSourceMode = NULL;    NTSTATUS Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnCreateNewModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, &pMonitorSourceMode);    if (!NT_SUCCESS(Status))    {        // If failed to create a new mode info, mode doesn't need to be released since it was never created        BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x", Status, pRecommendMonitorModes->hMonitorSourceModeSet);        return Status;    }    D3DDDI_VIDEO_PRESENT_SOURCE_ID CorrespondingSourceId = FindSourceForTarget(pRecommendMonitorModes->VideoPresentTargetId, TRUE);    // Since we don't know the real monitor timing information, just use the current display mode (from the POST device) with unknown frequencies    pMonitorSourceMode->VideoSignalInfo.VideoStandard = D3DKMDT_VSS_OTHER;    pMonitorSourceMode->VideoSignalInfo.TotalSize.cx = m_CurrentModes[CorrespondingSourceId].DispInfo.Width;    pMonitorSourceMode->VideoSignalInfo.TotalSize.cy = m_CurrentModes[CorrespondingSourceId].DispInfo.Height;    pMonitorSourceMode->VideoSignalInfo.ActiveSize = pMonitorSourceMode->VideoSignalInfo.TotalSize;    pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;    pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;    pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;    pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;    pMonitorSourceMode->VideoSignalInfo.PixelRate = D3DKMDT_FREQUENCY_NOTSPECIFIED;    pMonitorSourceMode->VideoSignalInfo.ScanLineOrdering = D3DDDI_VSSLO_PROGRESSIVE;    // We set the preference to PREFERRED since this is the only supported mode    pMonitorSourceMode->Origin = D3DKMDT_MCO_DRIVER;    pMonitorSourceMode->Preference = D3DKMDT_MP_PREFERRED;    pMonitorSourceMode->ColorBasis = D3DKMDT_CB_SRGB;    pMonitorSourceMode->ColorCoeffDynamicRanges.FirstChannel = 8;    pMonitorSourceMode->ColorCoeffDynamicRanges.SecondChannel = 8;    pMonitorSourceMode->ColorCoeffDynamicRanges.ThirdChannel = 8;    pMonitorSourceMode->ColorCoeffDynamicRanges.FourthChannel = 8;    Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnAddMode(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode);    if (!NT_SUCCESS(Status))    {        if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)        {            BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x, pMonitorSourceMode = 0x%I64x",                            Status, pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode);        }        else        {            Status = STATUS_SUCCESS;        }        // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked        NTSTATUS TempStatus = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnReleaseModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode);        UNREFERENCED_PARAMETER(TempStatus);        NT_ASSERT(NT_SUCCESS(TempStatus));        return Status;    }    else    {        // If AddMode succeeded with something other than STATUS_SUCCESS treat it as such anyway when propagating up        return STATUS_SUCCESS;    }}

C++程式檔案 bdd_util.cxx

/******************************Module*Header*******************************\* Module Name: bdd_util.cxx** Basic Display Driver utility functions** Created: 29-Mar-2011* Author: Amos Eshel [amosesh]** Copyright (c) 2011 Microsoft Corporation\**************************************************************************/#include "BDD.hxx"#pragma code_seg("PAGE")//// EDID validation//BOOLEAN IsEdidHeaderValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid){    PAGED_CODE();    static const UCHAR EDID1Header[8] = {0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0};    return memcmp(pEdid, EDID1Header, sizeof(EDID1Header)) == 0;}BOOLEAN IsEdidChecksumValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid){    PAGED_CODE();    BYTE CheckSum = 0;    for (const BYTE* pEdidStart = pEdid; pEdidStart < (pEdid + EDID_V1_BLOCK_SIZE); ++pEdidStart)    {        CheckSum += *pEdidStart;    }    return CheckSum == 0;}//// Frame buffer map/unmap//NTSTATUSMapFrameBuffer(    _In_                       PHYSICAL_ADDRESS    PhysicalAddress,    _In_                       ULONG               Length,    _Outptr_result_bytebuffer_(Length) VOID**              VirtualAddress){    PAGED_CODE();    //    // Check for parameters    //    if ((PhysicalAddress.QuadPart == (ULONGLONG)0) ||        (Length == 0) ||        (VirtualAddress == NULL))    {        BDD_LOG_ERROR3("One of PhysicalAddress.QuadPart (0x%I64x), Length (0x%I64x), VirtualAddress (0x%I64x) is NULL or 0",                        PhysicalAddress.QuadPart, Length, VirtualAddress);        return STATUS_INVALID_PARAMETER;    }    *VirtualAddress = MmMapIoSpaceEx(PhysicalAddress,                                   Length,                                   PAGE_READWRITE | PAGE_WRITECOMBINE);    if (*VirtualAddress == NULL)    {        // The underlying call to MmMapIoSpace failed. This may be because, MmWriteCombined        // isn't supported, so try again with MmNonCached        *VirtualAddress = MmMapIoSpaceEx(PhysicalAddress,                                       Length,                                       PAGE_READWRITE | PAGE_NOCACHE);        if (*VirtualAddress == NULL)        {            BDD_LOG_LOW_RESOURCE1("MmMapIoSpace returned a NULL buffer when trying to allocate 0x%I64x bytes", Length);            return STATUS_NO_MEMORY;        }    }    return STATUS_SUCCESS;}NTSTATUSUnmapFrameBuffer(    _In_reads_bytes_(Length) VOID* VirtualAddress,    _In_                ULONG Length){    PAGED_CODE();    //    // Check for parameters    //    if ((VirtualAddress == NULL) && (Length == 0))    {        // Allow this function to be called when there's no work to do, and treat as successful        return STATUS_SUCCESS;    }    else if ((VirtualAddress == NULL) || (Length == 0))    {        BDD_LOG_ERROR2("Only one of Length (0x%I64x), VirtualAddress (0x%I64x) is NULL or 0",                        Length, VirtualAddress);        return STATUS_INVALID_PARAMETER;    }    MmUnmapIoSpace(VirtualAddress,                   Length);    return STATUS_SUCCESS;}

最後找出diagnostic tool關於 video & graphic card部分的測試

參考文章:

微軟 Getting started with Windows drivers
Steward
小z说:内核驱动的编译环境
VS2012开发驱动小Tip之:更改KMDF版本以支持XP系统

2019/07/03

英文學習: 關於 include 三種用法,一次滿足!

動詞 include 放在句子後方作補充說明用法時,有幾個常見的型態--including、included,它們因為太相像而讓許多人總是搞錯它們的用法,像是:

Some people are trapped in the burning building, _____ two men and five women.
請問老師,我應該要用 including 還是 included 呢?


2018-03-07
老師救救我考試英文include用法
出處: 希平方


1) include 怎麼用?

Include 就是一般動詞「包括、包含」的意思,需要搭配主詞、受詞,例如:
The meal includes dessert and beverage.
(餐點包含甜點以及飲料。)

2) including 怎麼用?

Including 是用來帶出包含的事物,在主要句子後面先加上逗號之後,由 including 引導含括的事物,例如剛剛的例句中包含的事物在後面,所以前方的空格應該使用 including:
Some people are trapped in the burning building, including two men and five women.
(有些人被困在那棟著火的建築物裡,包含兩名男性及五名女性。)
再舉個例子:
My grandparents own a farm, and they grow a lot of vegetables there, including cabbage and peppers.
(我的祖父母有一座農場,他們在那裡種許多蔬菜,包含高麗菜跟椒類。)

3) included 怎麼用?

Included 也是在主要句子後加上逗號,再作補充說明,不過它放置的位子跟 including 相反,會先講出所包含的事物,再加上 included 於後方位置。例如剛剛那句可以這樣改:
Some people are trapped in the burning building, two men and five women included.
(有些人被困在那棟著火的建築物裡,包含兩名男性及五名女性。)
或是:
They’re having a big sale, all electric appliances included.
(他們在舉辦一場大拍賣,所有電器產品都有包含在內。)

2019/06/13

英語學習 - 正確使用 時間介係詞 in, on, at 範例很多

作者: Derrick Chen
【時間介係詞】2 分鐘搞懂 In, On, At!讓你再也不怕用錯!

in, on, at 用法的差別就在於:

at:一個準確、特定的時刻
in:月份、季節、年、世紀、一段長而非特定的時間
on:特定日期、星期
邏輯就只是這樣而已!下面幫大家統整常用的時間用法,一起練習看看吧!

in + (months, years, centuries, long periods)

in the morning
in the afternoon
in the evening
in January
in February
in March, 2015
in the spring
in the summer
in the fall
in the winter
in 2015
in the past year
in the 18th century
in the week
in the past
in the future

on + (days and dates)

on Monday
on Tuesday morning
on Wednesday afternoon
on Thursday evening
on Friday night
on 28, April
on New Year’s Day
on Christmas Day
on the weekend

at + (precise time)

at 07:11
at 10 o’clock
at noon
at noon yesterday
at night
at midnight
at the same time

2019/06/12

這個網頁可以DEMO你的程式, 支援C / JAVA / PHP/ Object-C / C++ / C# / Python / VB / Perl ...etc

補充其它可以Demo的網站


如題, 這個網頁可以幫助你demo一些小程式, 而不需要特別設定你的編譯環境, 像是假一個Linux主機 去弄gcc之類的….

像我要用這個去跑C語言, 進入網址 http://ideone.com/
下面可切換語言 把它換成C, 然後就可以跑看看

但是網頁版的編譯…就是會有些缺陷, 如果急著需要驗證程式碼, 可以試試囉!

附上圖片大致了解一下吧!

2019/05/28

投資存股筆記- 嘉里大榮物流(2608) 主力為商業貨運, 台灣主要物流企業之一

嘉里大榮前身是大榮貨運,為台灣最早的物流公司之一。2008年曾獲亞洲糖王郭鶴年旗下的香港嘉里物流集團入主經營,成為嘉里集團一員,並更名為嘉里大榮。2015年整併超峰快遞,期待提高台灣區的網購與快遞市占率。目前台灣的三大快遞業者為嘉里大榮、宅配通和新竹貨運,合併超峰快遞可以確保嘉里大榮的市場領先地位。嘉里大榮物流為本土主要物流企業之一,擁有員工5400人,營運車輛達3150輛,超過187個營運物流據點(2017/08/01).

母公司為香港的嘉里物流(英語:Kerry Logistics Network Limited,港交所:0636), 集團致力於立足於大中華地區, 並擴及全球業務!

心得:

  • 2019/05/28: 股價33.8, 第一季稅後盈餘3億3701萬元,EPS 0.72元, 比去年第一季略高, 但基本上這幾年成長趨緩, 觀望
  • 2019/03/21: 股價37.15
  • 2018/04/25: 股價40.5
  • 2018/03/28: 股價37.5
  • 2017/08/10-9/15: 股價35.9-36.55, 股價偏弱, 競爭者順豐資料: 台灣順豐2007成立,十年來,員工人數近1,500人、車輛數近650台、全台約50個分點部,月結客戶數超過兩萬家
  • 2017/06/02: 股價38.1, 第一季獲利下降, 股價從44元跌至38.1元, 路上的黑貓宅急便數量好像超越大榮橘車
  • 2017/05/03: 大榮擬配息1.5元,殖利率約3.6%,以5%為標準的話實在是不合格

2019年02月21日 嘉里大榮 今年營收成長動能強

工商時報 本報訊
嘉里大榮(2608)本月8日大年初四發生桃園觀音物流中心火災事件,讓公司股價年後呈現震盪狀況,而本月15日公司公告1月營收達11.6億元,創歷史新高,月增31.6%,年增19.06%,呈現大躍升狀態,股價也很快獲得支撐,20日上漲0.35元,收盤價37元。目前觀音物流中心預計半年後恢復營運。

嘉里大榮董事長沈宗桂表示,公司今年有特殊成長動能,在冷鍊物流方面,過去一年公司冷凍車隊增加了約50輛、達550輛,食品運送符合政府食安政策,其中醫療專用物流車達已達250輛,是公司響應政府加入PIC/S組織,符合藥品優良運銷規範GDP政策的專業物流車隊,這兩項業務今年都將出現高成長,預計成長率在二到四成間。另公司併購的科學城物流,今年1月正式接手,公司擁有43,051張持股,持股比率達60.07%,今年還會持續增加持股。

2017年11月25日 嘉里大榮 進軍農業供應鏈

工商時報 張佩芬/台北報導
嘉里大榮物流(2608)決定投入農業供應鏈,與經營鮮果20多年的宗美量販店與徠徠徠鮮果合資成立的嘉里鮮菓股份公司,昨(24)日正式開幕,將扮演農產運銷的先驅者。大榮董事長沈宗桂表示,今年電商、醫藥與低溫配送都有高成長,全年獲利估可優於去年。新成立的嘉里鮮果將分三階段發展業務,首先將建立全台生鮮蔬果產銷供應網路,再整合農民契作及國內外客戶推動進出口貿易,最後成立生鮮蔬果裁切中心,透過「KerryGo電商平台」提供加值化服務,為台灣農民創造利潤。

沈宗桂指出,總統蔡英文發展新農業策略,在生產、採收、集貨、分級、品檢、包裝、幹線運輸、常低溫倉儲及配送、農藥檢驗、零售批發、行銷設計,每項都對環環相扣的農產運銷供應鏈有著舉足輕重的影響。有鑑於此,嘉里大榮物流和宗美量販與徠徠徠鮮果合資,打造新品牌「嘉里鮮菓」,合力提供國際級服務網路,成為專業農產運銷鏈一份子。依嘉里鮮菓的短期計畫,明年起逐步建立「全台生鮮蔬果產銷供應鏈」,以嘉里大榮全台53個常溫配送所、19個冷鏈配送站、5個低溫倉庫、超過3,000台常溫配送車輛、500台以上低溫配送車輛資源,專業物流拓展市場。

與嘉里大榮物流同屬香港嘉里物流集團的關係企業,名列全球四大農產品生產企業-豐益國際(Wilmar International)上個月在台中設立豐益大宗物資有限公司,經營項目以棕櫚油、乳製品、巧克力,未來也將提供嘉里鮮果海外通路,為台灣農產品創造商機,達成最大的經營綜效。沈宗桂透露,會成立嘉里鮮果,是因為進入公司工作兩年的清華大學材料研究所碩士郭力綸,是宗美量販店董事長郭榮宗的兒子,他在認識郭榮宗夫婦後,看到這對方夫妻的善良與誠信,也看好市場商機,一手催生嘉里鮮果,由大榮投資51%。嘉里鮮果董事長郭榮宗表示,過去宗美一年營業額約1,2億元,嘉里鮮果將以3年內業績倍增為目標。

2017/08/28 違法解雇逾一年未復職 嘉里大榮前員工貼封條討欠薪

張智琦 苦勞網記者
知名物流業者「嘉里大榮」因為員工曾堉誠籌組工會而逕自將他解雇,勞動部今年(2017)1月裁決解雇案構成不當勞動行為,資方應復職並補發放薪資,然而曾堉誠出面指控,嘉里大榮在勞動部裁決出爐後仍一再刁難,至今都不讓他順利復職,他上個月以勞動部裁決書向台中地院聲請強制執行,查封台中嘉里大榮中東所建物,今日(8/28)更偕同家屬及數名離職員工至中東所抗議,要求嘉里大榮補付積欠薪資。去年(2016)7月嘉里大榮貨運駕駛曾堉誠在網路上號召組織工會,6天後遭公司解雇,勞動部今年1月判決嘉里大榮構成不當勞動行為,公司應在7日內恢復原職,並支付解雇期間的薪水與利息。然而曾堉誠表示,他之後數度到公司要求復職皆被拒絕,後因生計需要,被迫和公司和解並簽下離職同意書,但至今自認仍是員工,要求復職,並要求嘉里大榮支付2月到8月的薪資。

然而,嘉里大榮委任律師謝文倩指出,今年2月公司已按勞動部裁決,給付曾32萬元的薪資和利息,曾堉誠也在2月20日申請自願離職,認為曾聲請強制執行已經違法,且嚴重損害公司信譽,將對曾提告反制。對於公司的說法,曾堉誠不滿表示,公司當初不讓他復職,反而一直慫恿他和解並離職,當時為了取回公司積欠他的薪水,他只好簽下離職同意書。他也指控,嘉里大榮事後散布他「拿錢走人」的消息,已違反離職書的保密條款,他主張和解無效,目前仍是員工,因此公司必須支付2月份至今的薪資。曾堉誠今偕同家屬和數名離職員工到原工作地點嘉里大榮中東所外抗議,並拿出自製封條,貼在公司招牌柱子上;嘉里大榮也動員廠內員工聲援自家公司,批評曾「以為抗爭就有錢拿」,高喊「嘉里大榮加油」,並上前撕下封條,現場上演「勞勞相殘」的場面。

2017-08-02 黑貓宅急便周日假日停止配送 一張表盤點四大宅配送貨現況

經濟日報 記者李至和/台北報導
統一速達旗下黑貓宅急便昨(1)日在官網公告,將在8月28日起周日與假日停止集貨與配送服務,且營業所也將提前一小時收工,宅配指定時間取消晚間時段。這是繼新竹物流、嘉里大榮停止周日假日送貨後,黑貓宅急便也跟進,宅配通則仍在觀望,暫不改變現有做法。黑貓宅急便並非第一個停止周日假日配送的業者,昨日消息一出,網路上有罵聲、也有讚聲,有網友大讚「良心企業」,但也有人認為「既然要縮減服務時間,那之前就不應該漲價」。對黑貓宅急便跟進停止周日配送,其他物流業者認為,物流業是高度勞力密集的產業,現在已經不只是一例一休的問題,缺工、招不到人才是燃眉之急,在人力不足、工時成本增加的情況下,勢必得調整營業時間。

今年1月一例一休政策上路之後,新竹物流、嘉里大榮即陸續停止周日假日送貨,當時黑貓宅急便與宅配通仍維持原作法,經過半年評估,考量員工休息需求,並從整體評估人力需求下,決定縮短營業時間、周末假日不配送、縮窄當日配範圍三大做法,紓解物流人員壓力。統一速達指出,經過人力需求、員工休息與配送情況等全盤考量後,為讓員工兼顧工作及家庭生活的平衡,周日假日停止集貨與配送包裹,指定配送也不再有晚間時段,未來僅有台北市、新北市、基隆市、桃園市有當日配服務。

統一速達是國內一哥,全台有3,000多台集配車及超過4,000名的送貨員,去年營收達110億元,稅後純益4.57億元,在電子商務物流量增加、開拓宅商機有成等因素帶動下,營收、獲利均穩健成長。統一速達今年第1季稅後純益為1.29億元,年減約7%,罕見的獲利衰退。為了讓營運回穩,今年3月統一速達也在宅配通、新竹物流、嘉里大榮等三大貨物業者調漲物流費後,才決定調漲包裹費用。

2017年08月02日 嘉里大榮斥資15億 觀音物流中心動土

龍益雲/桃園報導
看好桃園市積極發展物流產業,嘉里大榮物流昨(1)日動工興建最大投資案觀音物流中心,預計斥資15億元。桃園市長鄭文燦昨天出席動工典禮強調,嘉里大榮物流規模大且服務完整,擁有5,400名員工、3,150輛營運車輛,超過187個營運據點,在桃園市就有林口國際物流中心、蘆竹物流中心、林口所、南崁所、桃園所及中壢所,近年更積極從本土邁向國際。嘉里大榮董座沈宗桂表示,選擇桃園市是響應市長鄭文燦推動航空城計畫跨境物流,提供本土產業跨進國際物流領域,觀音物流中心也是公司歷年最大投資,未來將成為空港、海港物流中心,將提供智慧物流供應鏈服務。嘉里大榮觀音物流中心面積約5,000坪,將興建5層樓的智慧尖端物流中心,未來將可服務北部地區的企業。鄭文燦指出,桃園市臨近桃園國際機場及台北港,目前全市約有1,800家物流產業,市府也將設置大園沙崙、楊梅幼獅及平鎮長安3個產業園區。

2017年07月03日 物流+智能櫃 鋪路網購最後一哩

張佩芬/台北報導
嘉里大榮物流與掌櫃智慧生活公司異業結盟,即日起提供24小時自助寄件、取件服務,預計可增長2成消費者宅配寄件服務量。消費者可至全台近千個智能櫃領取配送商品,或透過智能櫃寄出包裹,突破時間、空間的限制,隨時寄貨取貨,享受智慧科技便利生活。電商宅配經濟近年爆發性成長,由於台灣雙薪家庭多、白天在宅率低,約有1成網購包裹需要2~3次配送,多次聯繫送達時間。網購市場最重要的「物流」一環看似簡單,流程卻複雜,取貨的便利性與到貨品質,都是影響消費者購買意願的關鍵要素。

嘉里大榮物流為了提供消費者更貼心的服務,即日起與掌櫃智慧生活公司攜手合作,提供收派件、透過掌櫃配送到府、到府無人收件轉派送鄰近櫃點等多元服務,讓消費者彈性支配寄取件時間。消費者只要在智能櫃官網或APP填寫資料,前往智能櫃輸入寄件碼與付款便完成寄件程序;消費者收到取件碼簡訊,前往智能櫃輸入取件碼,20秒即可輕鬆取出包裹。未來更可藉由嘉里大榮的冷鏈配送,發展智能櫃低溫商品的配送服務。掌櫃智慧生活公司是全台市占率第一的智能櫃業者,目前在全台的萊爾富、美廉社、大型公共設施與住宅等人口密集處設置近千個智能櫃,透過簡訊將投遞信息發送給客戶;對嘉里大榮及電商而言,不僅確保配送的時效性、提高配送成功率,也可降低物流成本。

2017/05/26 大榮Q1成本增獲利年減4成;需續觀察Q2調整狀況

MoneyDJ新聞 記者 劉莞青 報導
大榮(2608)第一季受一例一休新法上路影響人力成本增加,影響單季毛利率15%,年減少近6個百分點,稅後淨利1.97億元、年減4成,EPS 0.42元。展望後續營運,法人指出大榮已以增加派遣人員等措施來降低員工加班成本,且也將人力成本上揚因素反應至客戶端、調漲服務價格,惟法人評估台灣貨運市場競爭激烈,漲價空間有限,後續營運仍需觀察第二季人事成本調整狀況而定。

嘉里大榮前身為大榮貨運,2008年時由亞洲糖王郭鶴年旗下的香港嘉里物流集團入主經營,成為嘉里集團成員,並於2015年初與同屬嘉里集團的超峰快遞合併。大榮業務主要為路線貨運,提供零擔貨件託運等B2B或B2C配送,也提供冷鏈物流等專業整合物流服務,目前集團車輛約有3,100台車,路線貨運佔營收比重約八成,倉儲與其他佔營收比重約二成。

回顧大榮去年營運表現,受惠於零擔與低溫物流營收穩健增加,大榮全年營收94.01億元,年增近4%,但在業外收入上,由於前年有處分資產一次性獲利因子2.5億元,相較去年處分資產獲利僅約1億元左右,減少約1.5億元,是以大榮稅後淨利12.93億元,年減約2.7%,EPS 2.68元。而在今年股利政策上,大榮董事會決議配發現金股利1.5元,以昨(25)日收盤價38.35元計算,隱含現金殖利率約4%。

而在大榮今年第一季的營運成績上,由於受到油價走升以及一例一休勞規新法上路,導致大榮營運成本走增,單季毛利率降至15%,年減少近6個百分點,法人指出其中油價影響約1個百分點,較大影響因素仍是人力成本增加;在毛利率大幅下滑影響下,加以去年同期有處分土地利潤進帳墊高基期,大榮第一季稅後淨利1.97億、年減4成,EPS 0.42元。

展望今年後續營運,法人指出油價價格持續震盪,大榮第二季毛利率受油價干擾應可較第一季減少,而針對一例一休所造成的人力成本上揚因素,法人表示大榮已從多方面調整,包括透過增加派遣人員來因應部分人力需求、降低加班費用,另外也會將部分人力成本走升因素反應至客戶端,調漲服務價格,惟法人評估台灣貨運市場競爭激烈,漲價空間有限,後續大榮營運狀況仍需觀察第二季調整後狀況而定。

2017/02/22 電訪嘉里大榮

Q: 公司目前有降低油品成本的計畫或建造營運加油站嗎?
A: 嘉里大榮目前沒有營運加油站的計畫, 但會跟油品供應商簽訂合約, 如台灣中油或台塑石油, 會與報價低的廠商簽約購油!

《航運股》嘉里大榮設倉儲與貨櫃場,台南科技園區附近購萬坪地

2017/02/18 15:12 工商 張佩芬/台北報導
嘉里大榮 (2608) 董事長沈宗桂指出,公司昨(18)日在台南科學園區附近的台南市新市區大營段以6.57億元購買5筆土地,共計約3.62萬平方公尺,約1.09萬坪,將做為倉儲與貨櫃場用地,建構成為南科貨櫃轉運中心。大榮在台南現有營運中心是租用的土地,現有面積不敷使用,公司洽詢合適土地已經一段時間,這次購自宜進實業 (1457) 的土地,方便進出南科,大榮將計畫根據香港總公司制定的標準,以一年時間建設倉庫和貨櫃調度車場。大榮台南營運中心總投資金額約8到9億元,將成為公司零擔物流在南部的成長據點。

大榮去年股東大會也通過投資7.8億元興建北區第二個國際化物流中心,公司在林口除現有物流中心,買下觀音觀塘區土地5,088.09坪,距離桃園機場不到20分鐘路程,將建設為國際化專業物流中心,提供醫療、跨境與水果物流與一般物流使用,預計2018年年底完工啟用。

展望明年,台灣貨運市場已非常飽和,大榮業績成長動力相對有限,不過,法人看好大榮已提前取得醫藥物流GDP驗證,在明年醫藥新法規上路後,作為唯一取得醫藥物流驗證的廠商,大榮醫藥物流業務成長可期,現階段醫藥物流約佔大榮3%營收,長線成長看好。至於在其他新業務上,大榮也規劃將陸續跨入高階時尚品與藝術品物流業務,雖然此兩項貨品量不大,難以大量挹注營收,但在獲利上可望優於傳統商品物流。

大榮、宅配通 本季獲利看增

2016年12月27日 張佩芬/台北報導
物流宅配業第4季是全年最大旺季,嘉里大榮(2608)與宅配通(2642)預料獲利將再拉升。但面對一例一休,大榮董事長沈宗桂表示 ,將需要增加一成五到兩成人力,並停止周日派工並調高費率,宅配通表示也是朝這個方向去做。

大榮董事長沈宗桂指出,他上周四代表路線貨運公會參加行政院長林全主持座談會,指出因一例一休,周日勢必停止派工,周六輪值的人員要在平日排休,預計要增加一成五到兩成人力才夠支應,運輸費率也勢必要調升。

大榮內部將擬具一例一休因應方案,不會讓公司業績受到影響。大榮今年前3季合併營收69.51億元,較去年同期增加6.90%,除了零擔與低溫物流比現良好,併購的超峰快遞完成整頓,人事費用下降,加上上半年約1億元的售地利益,獲利10.17億元,EPS 2.10元。

第4季除了進入傳統旺季,沈宗桂指出,今年第3季因為颱風,有8個工作天無法作業,第4季天候情況好,也是一大助力。公司在11月時公告將執行庫藏股,預計在股價38~52元間買回16,925張,上周五(23日)公告已買回6,890張,每股平均買進價格44.23元。

大榮已有500輛冷凍冷藏車,旗下的嘉里醫療物流也有200輛車,醫療部分響應政府加入PIC/S組織 ,推動藥品優良運銷規範GDP政策,明年醫藥新法規上路後,將成唯一取得醫藥物流驗證的公司。大榮明年在低溫與醫藥物流都準備擴充一成運力。

宅配通因為以一般客戶為主,不像大榮偏重企業客戶,對於明年周日是否停止派工還在做最後研究,但是根據使用者付費原則,調升費率恐無法避免。

不過宅配通營運相當靈活,除在桃園機場提供行李配送服務,近期搭配Wi-Ho!特樂通,搶在聖誕假期前推出國內首見「桃園機場24小時免費取機服務」。另宅配通在漫畫博覽會、美妝等消費性展出,都提供現場宅配服務。

嘉里大榮物流董事長沈宗桂:下一步進軍…時尚、藝術品物流

2016年08月15日 04:10 康彰榮、李書良/專訪
沈宗桂持續推動組織重整、品牌再造和業務重塑的工程,甚至不定時「跟車」,親自觀察配送過程,同時訪問客戶了解其感受。

嘉里大榮 布局醫藥、冷鏈、時尚、危險品和藝術品物流
香港嘉里物流集團在2008年12月入主台灣物流巨頭大榮貨運,並更名為嘉里大榮後,董事長沈宗桂近8年來持續的革新,並借重嘉里集團在全球完善的物流鏈資源,穩坐了台灣物流業的龍頭。

為了強化公司競爭力,嘉里大榮繼布局醫藥、冷鏈物流之後,下一步還準備進軍時尚、危險品和藝術品物流。在物流業競爭呈現一片紅海之際,嘉里大榮總比同業跨前一步,正是其成功之道。

沈宗桂接受本報專訪時指出,2008年他入主大榮之後,立即對公司進行三大變革,第一個就是對董事會進行全面調整,因為這牽涉到公司治理和價值;其次,是在人事方面做了適才適所的專業分工;第三就是讓財務透明,因為嘉里大榮是上市公司,透明是公司治理最基本的要求,「我們這個是做得非常的徹底」。

第一步:進行三大變革 自豪最大成就 是乾淨、透明
沈宗桂得意地說,若要問他在嘉里大榮過去8年最大的成就,可以用兩個英文字來概括:clean和transparency,也就是乾淨俐落而且透明,「我經得起考驗,而任何專業的經理人只要他有能力,他就有機會。」

嘉里大榮目前擁有3,300多部車輛、5,300多名員工,是台灣單一第三方物流業中規模最大的企業,其橘身黑色標誌的車輛穿梭在台灣各大街小巷之間,相當顯眼。

沈宗桂表示,大榮已成立60年,公司歷經一甲子的好處,是沒有人不認識這家公司,但若不去革新,就會有尾大不掉的包袱,例如沉重的人事壓力和不彰的效力。因此,他接任嘉里大榮董事長之後,持續推動三「R」工程:組織重整(Restructure)、品牌再造(Rebranding)和業務重塑(Remodeling)。

在組織重整部分,明確公司領導人和管理人的工作差異:領導人工作是要把公司引導到甚麼方向,而管理人則是要去執行領導人的方向,讓客戶感到滿意。沈宗桂透露,為了落實改造工程,過去8年來他不定時的「跟車」,親自去觀察配送過程,以及司機跟客戶的互動,同時訪問客戶了解其感受。

在品牌再造方面,沈宗桂把大榮更名為嘉里大榮,使這家公司從非常傳統的台灣貨運公司轉換成一家具有國際化、一步到位、全方位的物流服務企業,將大榮從本土轉向大中華、大亞洲甚至全球;另外,他還花了幾億元把公司所有車輛、制服、辦公室、工作環境、廁所完成再造。

第二步:拓展企業觸角 眼見滿地西瓜 起念當電商
至於業務重塑,嘉里大榮原本只做「零擔」貨運業務,現在已擴充到10項,涵蓋低溫配送、低溫倉庫、常溫倉庫、快遞、醫藥物流、貨櫃拖車、海空承攬及電商物流等。

嘉里大榮旗下的電商為「嘉里購」(Kerry Go)。談到進軍電商領域,沈宗桂是抱持著回饋社會的心情去推動。沈宗桂說:「我去花蓮看到農夫種的西瓜,滿地都是,我就跟他們說,我給你們包了,放在嘉里購上面去賣,第一,西瓜不會擺在那裏爛掉,第二,也是給社會一個小小的回饋。」

沈宗桂說,台灣現在電商蓬勃發展,但電商和物流的配送基本上是利益衝突的,因此嘉里大榮決定自已來做,也就是在既有電商又有物流的優勢下,農民們可以把他們願意賣的價格,不必經過農會或大賣場,直接放到嘉里購的網站,消費者要買就直接在嘉里購下單,由公司的物流系統送貨到消費者家中。

再邁步:走向高階物流 設據點處理藝術品、危險品
沈宗桂還透露,嘉里大榮接下來還準備做時尚、藝術品和危險品物流。他指出,公司在新店已有一個據點專門處理珠寶等高單價的時尚品,雖然量不是很大,但未來它會是一個國際趨勢。

至於藝術物流,包括運送過程、包裝、拆掛,都有一套專門學問,因為很多相關業務涉及到國際端,會牽涉到海空運、報關、內陸運送、展覽館的安排等,嘉里物流在這些領域都有完整的配套。

嘉里大榮只留下5個大陸據點
另外,談到大榮從2000年開始對大陸的投資,沈宗桂認為,因為定位和策略錯誤,基本上那是失敗的投資。自他接掌董事長之後,進行整頓,大榮中國慢慢移轉到嘉里物流集團在大陸投資的嘉里大通,嘉里大榮只留下5個大陸據點,自2014年之後已經轉虧為盈。

2016年04月13日 台中市府與嘉里大榮簽約 推中部農產銷往東協

(大紀元記者黃玉燕台灣台中報導)
繼日本參訪行程,台中市長林佳龍再度訪星4天,13日最後一站與嘉里大榮物流公司總部董事長沈宗桂,共同簽署合作備忘錄;市府計畫未來每年推出「台中高值農產品週」等行銷活動,透過嘉里大榮協助邀請買家下單選購,將有助於將台中荔枝等優質農特產品,外銷至東協各國,開拓東協市場行銷通路,持續推進「新南向政策」。

考量2018年世界花卉博覽會在台中,屆時將有龐大花卉、蔬果運銷需求,林佳龍於10日抵達新加坡,當晚先與現任嘉里物流集團主席楊榮文會面,盼借重其物流實力,成為台中農產品外銷夥伴。林佳龍表示,嘉里大榮為台灣主要路線運輸服務業者之一,以台中為最大根據地,他感謝企業協助運送生鮮食品至台中食物銀行、幫助弱勢;此次參訪盼透過集團優勢,行銷東協,甚至全世界,成為台灣「新南向政策」的重要通路。

董事長沈宗桂簡報表示,嘉里大榮創始於台中,嘉里集團入主大榮後,業績逐漸由負轉正,成為外資入主的成功先例,近幾年業績呈倍數成長。台中市府團隊也拜會當地工商聯合總會、企業代表及當地台商,盼建立常態性投資貿易合作對話機制。並在12日率領台中優良食品業者組代表隊,參與2016新加坡國際食品展,並設置台中形象館一起作戰。另為宣傳中台灣觀光旅遊,市府已與星馬12家旅行業者簽訂觀光交流合作備忘錄,為持續推動包機和直航台中奠下基礎。

2016年04月02日大榮 拓展跨境快遞

張佩芬/台北報導 工商時報
嘉里大榮去年3月併購的超峰快遞,今年將會與母公司嘉里物流聯網透過資源整合,拓展東南亞地區跨境快遞與國內快遞業務,預計今年下半年超峰快遞將更名為嘉里快遞。超峰快遞除了3百輛貨車,在全台還擁有1百多部機車,公司正在重新定調分區,機車車隊將聚焦都會核心;另透過母公司嘉里物流聯網在東協的基礎,今年將強化資訊軟體,建立一個系統一條龍服務,待跨境業務到位,預計明年進行車隊擴充。

沈宗桂指出,公司去年在冷鏈物流、醫藥物流、時尚物流及跨境電商等4大利基市場都已完成布署,在一般物流公司常溫、低溫與醫藥物流都還用同1輛車運送情況下,大榮已有500輛冷凍冷藏車,而旗下嘉里醫療物流已有200輛車,除了醫藥運送也做醫藥代理。

2001-2016歷年EPS與股利資料

可以看到2008是很明顯的分水嶺, 換了新的經營團隊後公司開始成長持續獲利!

2008-2016本益比

這兩年回到14~15左右

2019/05/27

2020-2019房屋稅 信用卡刷卡優惠

卡優新聞網-刷卡繳房屋稅全攻略 23家銀行免收手續費
記者 溫子豪 報導
5月繳稅季除了申報綜所稅外,「有殼一族」還須繳納房屋稅。今(2019)年各家銀行提供的房屋稅信用卡優惠中,一次付清免手續費共有23家,13家提供分期0利率方案,臺銀、合庫、一銀、彰銀、兆豐、臺企銀、永豐、台新等祭出刷卡金回饋,而花旗、玉山與樂天信用卡則舉辦抽獎活動,「台灣Pay」額外加碼雙重抽獎送10萬元禮券與1台兩黃金條塊。

今(2019)年信用卡繳納房屋稅,共有23家銀行給予一次付清免收手續費,另有3家銀行有低門檻免手續費優惠,華南指定卡別繳稅免收、遠銀當月有消費免收,而以樂天卡繳稅且國內消費滿100元,就以回饋金方式返還手續費,其他銀行則多以單筆20元或稅額0.5%~1%計收。

為減輕卡友5月繳稅季的資金負擔,共有21家業者祭出房屋稅分期付款方案,其中合庫、一銀、彰銀、台北富邦、國泰世華、新光、陽信、聯邦、遠銀、永豐、玉山、台新、安泰等13家銀行提供分期0利率福利,又以彰銀、台北富邦、玉山等4家銀行可分12期0利率「最大方」,其餘多為3~6期0利率。

在額外優惠方面,臺銀、合庫、一銀、彰銀、兆豐、臺企銀等6家業者,以「台灣Pay」或自有行動銀行繳稅,就送50~100元刷卡金或超商禮券,永豐與台新釋出全家便利商店繳稅優惠,以永豐卡綁定Apple Pay繳納,稅額滿5,000元贈300元刷卡金,以My FamiPay綁台新卡交易,稅額滿5,000元則回饋50元刷卡金。

彰銀、花旗、玉山與樂天信用卡舉辦抽獎活動,彰銀提供台灣Pay納稅卡友6~12月台灣Pay交易均享100%回饋,回饋上限10萬元;花旗卡繳納房屋稅抽馬丘比丘雙人遊、Gogoro、Apple Watch…等獎項;玉山卡稅額滿1萬元抽紅利點數或空氣清淨機;樂天卡繳納房屋稅且一般消費滿百元,登錄抽iPhone XS 64GB與雙人東京來回機票。

財金公司與台灣行動支付公司為鼓勵民眾多多使用「台灣Pay」,也強打抽獎活動,以「台灣行動支付」APP綁定指定16家銀行金融卡或以20家銀行行動網銀綁金融卡繳稅,抽SOGO禮券10萬元、燦坤提貨券2萬元…等365個獎項;以「台灣行動支付」APP綁定指定16家銀行金融卡或19家銀行信用卡,則有1台兩臺銀金條、iPhone手機…等288個獎項抽獎。

比較【2020-2019年信用卡繳稅回饋】優惠總整理 108年所得稅_免手續費,分期零 利率,紅利積點

— 2019/05/27更新 —
快月底, 趕緊繳稅吧!
建議可以先查自己所得資料: 綜合所得稅電子結算申報繳稅網頁

今年報稅軟體有大進步耶, 不論是離線版或是線上版都比去年的完善, 介面設計的一致性, 終於有點專業等級的感受, 畢竟之前美工外觀真的很像學生時代作專題的質感, 若以前是業餘接案來形容的話, 今年的就比較像是給職業的軟體公司提供的Total Solution!

先說結論:
今年最強報稅+最感心的銀行就是: 玉山銀行 & 台新銀行
當然繳稅大戶幾十萬幾百萬稅款, 因為超出回饋額度, 就要另當別論囉!

以下整理了各家銀行2019年刷卡繳綜合所得稅的優惠活動,要繳稅之前先比較一下哪家銀行信用卡比較優惠! 大部分的銀行都有免手續費的優惠,除了可以分期之外,有些銀行刷卡還可以抽獎。快來看看哪間銀行的優惠最多~

中國信託、合作金庫、華南銀行、永豐銀行、元大銀行、聯邦銀行、陽信銀行、第一銀行、台灣銀行、彰化銀行、玉山銀行、大眾銀行、台新銀行、台北富邦、國泰世華、土地銀行、花旗銀行、台灣企銀、渣打銀行、台中銀行、新光商銀、兆豐商銀、上海銀行、澳盛銀行、匯豐銀行

薪資所得扣繳稅額表(含薪資所得受領人免稅額申報表)
國稅局網頁, 可以查到98至108年度薪資所得扣繳稅額表, 每年會被扣繳的薪資都是根據表格而來!

2019年(即2018年度)課稅級距:

2019年報稅新制 可以享受到優惠制度

先說結論, 這三大族群的低於此年薪以下免繳稅:
*單身族: 低於40.8萬年薪免繳稅
*雙薪夫妻(無兒女): 低於81.6萬年薪免繳稅
*雙薪夫妻(有2個五歲以下兒女): 低於123.2萬年薪免繳稅
圖/財政部

主要是提高4項扣除額的額度

*「標準扣除額」:單身者從9萬元提升到12萬元,有配偶者從18萬元提升到24萬元
*「薪資特別扣除額」:從12.8萬元提高到20萬元
*「幼而學前特別扣除額」:從每人2.5萬元提高到12萬元
*「身心障礙特別扣除額」:從每人12.8萬元提高到20萬元

單身族:

雙薪家庭+兩名5歲以下幼兒:

基本生活費條文: 保障享有符合人性尊嚴的基本生活所需費用

107年度每人基本生活費為17.1萬元,每一申報戶的「基本生活費總額」是17.1萬元×人數(含納稅者本人、配偶及受扶養親屬人數),稱為 A。

基本生活費比較基礎合計數,含免稅額每人為8.8萬元、滿70歲為13.2萬元;標準扣除額單身為12萬元、有配偶為24萬元;幼兒扣除額(5歲以下子女)每人12萬元;教育扣除額(大專以上院校)每人最高2.5萬元;儲蓄投資扣除額每戶上限27萬元;身障扣除額每人20萬元,稱為 B。

當 A>B 時,差額(即基本生活費差額)得自綜合所得總額中再行減除。

股利課稅: 名詞「稅額扣抵比率」與「可扣抵稅額」將走入歷史。

從107年1月1日起,股利所得課稅規定有重大變革,除了廢除「兩稅合一之稅額設算扣抵制」,同時我國個人居住者於107年獲配股利,在隔年申報綜所稅時,可以從「股利所得合併計稅」或「單一稅率28%分開計稅」擇一擇優適用。以107年獲配之股利所得為例,在108年5月報稅時就將採用新制。

也就是說,從前股利憑單上的「稅額扣抵比率」與「可扣抵稅額」等名詞將走入歷史。還有,以往投資客在尋找標的時,也許會將「高稅額扣抵比率」納入選股條件之一,希望降低獲配股利時的稅負,在新制上路後就不必再顧慮這件事。

而「股利所得合併計稅」與「單一稅率28%分開計稅」之規定及計算方式如下:
  • 第一種(適合綜合所得20%以下):
    併入綜合所得稅,按照股利8.5%計算可抵稅額,每戶抵用上限為8萬元,全年股利所得94萬元以下,可以抵稅或退稅
  • 第二種(適合綜合所得稅30%以上):
    分開計算稅額,股利按28%稅率,與其他應納稅額合併報繳

2019年 多家銀行與「台灣Pay」行動支付也有優惠

* 活動網頁
為鼓勵民眾使用行動支付,財金公司與台灣行動支付公司分別規畫有抽獎福利,使用「台灣Pay」(「台灣行動支付APP」金融卡或金融機構「行動銀行APP」金融卡),掃描107年度綜合所得稅及108年度房屋稅稅單上之QR Code進行繳稅,每成功繳納1張稅單即享有1次抽獎機會,成功繳納2張稅單即享有2次抽獎機會,以此類推;惟同一人僅限得一個獎項。
活動獎項:
抽出365位中獎名額,獎品、數量如下:
頭獎 / SOGO禮券100,000元 / 1名
貳獎 / SOGO禮券50,000元 / 2名
參獎 / 燦坤現金提貨券20,000元 / 6名
肆獎 / 燦坤現金提貨券10,000元 / 6名
伍獎 / 家樂福提貨券5,000元 / 20名
陸獎 / 家樂福提貨券2,000元 / 30名
柒獎 / 超商禮券1,000元 / 100名
捌獎 / 超商禮券500元 / 200名

2019年 中區國稅局加碼三大好康抽獎!

* 活動網頁
* 僅限設籍: 苗栗縣、臺中市、南投縣、彰化縣及雲林縣
(1)以電子憑證完成網路報稅,即可參加抽獎。獎項內容如下:

(2)使用e化繳退稅即可參加抽獎,獎項共1,000名,每名可得超商電子禮券100元。
如:使用自動櫃員機(ATM)、晶片金融卡、信用卡、行動支付、繳稅取款委託書、活期(儲蓄)存款帳戶等e化方式

(3)使用行動支付工具繳稅成功者,即可參加抽獎。獎項內容如下:

2019綜所稅信用卡優惠更新表(108年):

目前仍有一部份銀行並未完全公告, 2019年信用卡繳稅優惠, 請大家務必再等一等繳稅, 按照過往經驗通常在五月第二週以前會完全公布優惠內容, 包含抽獎/回饋/分期領利率/紅利積點…等等! 小編會陸續更新上去

108年信用卡繳綜合所得稅優惠
銀行
活動連結
最高
分期0利率
優惠內容
玉山銀行

推薦原因: 不限金額有6期零利率, Pi拍錢包信用卡回饋1%P幣, 全家抽獎

6期零利率免手續費,
玉山信用卡一次付清: 税額滿一萬, 送7-11便利店100元抵用券
玉山世界卡稅款滿20萬: 現金回饋 1%(上限3000元)
* 玉山Pi拍錢包信用卡: P幣回饋 1% 上限2000 P幣 (1P幣可折抵1台幣)

指定卡加碼:
家樂福卡滿5萬, 送家樂福100元抵用券
國旅/南山/寶雅卡, 送7-11便利店100元抵用券

抽獎:
*每滿一萬元, 可抽一次玉山紅利點數1萬點(100名) & Dyson Pure Hot+Cool三合一空氣清淨機HP03(5名)

全家便利店刷信用卡繳費:
*滿3000可分3期零利率, 可抽千元全家禮券

台新銀行

推薦原因: 有6期零利率, 現金回饋1%, 抽獎
6期零利率免手續費,

● 全卡最高回饋1%:
-滿1萬送 100 元刷卡金
-滿5萬送 200 元刷卡金
-滿10萬回饋 0.3% 刷卡金 (每戶回饋上限 3,000元) ※ 活動登錄時間:5/1-6/2
FlyGo卡、@GOGO卡專享
繳稅不限金額回饋 1% (登錄2萬名,回饋上限200元) ※活動登錄時間:5/28-6/2

台新MasterCard信用卡再加碼:
-繳稅刷滿1萬送全家便利商店禮券 100 元(限量3000名)
-抽獎: 繳稅刷MasterCard卡不限金額,登錄即可抽機票、iPhone 、Apple Watch (限10名如下):
§首爾單人來回機票 兩名 §東京單人來回機票 兩名 §大阪單人來回機票 兩名 §Apple iPhone XS Max 256GB 乙名 §Apple iPhone XR 64GB 乙名 §Apple Watch Series 4 兩名 ※ 活動登錄時間:5/28-6/2

中國信託

推薦原因: 有12期零利率, 指定卡有0.3% 無上限回饋

12期0利率免手續費,
中國信託商旅鈦金卡 繳稅0.3% 無上限的回饋
中信卡繳綜所稅,幸福3得利」活動:
12期或6期分期0利率優惠,但簽帳金融卡不可分期。
* 中國信託商旅鈦金卡另享0.3%現金回饋無上限!
星展銀行

推薦原因: 不限金額有6期零利率, 一萬元以上回饋100元

6期零利率免手續費,
使用星展信用卡成功繳納「107年度綜合所得稅」活動:
可選擇分期零利率或刷卡金回饋
* 現金回饋: 所得稅一萬以上回饋100元 ; 十萬以上回饋500元
* 綜所稅分期0%利率: 3期 / 6期

* iPhone Xs 抽獎天天送(含所有交易類型及綜所稅): 天天刷星展信用卡新增交易金額累積每滿NT$500,即可輕鬆獲得該日iPhone Xs抽獎機會1次。
永豐銀行

推薦原因: 稅額滿2仟元有12期零利率

12期0利率免手續費,
* 單筆稅額滿2仟元享12期0利率
* 繳稅滿10萬送3佰元刷卡金
* 您繳稅永豐買單,不限金額抽刷卡金最高10萬元(限量10名)
* 【新戶加碼】新戶繳稅單筆滿1萬元加送3佰元全家購物金
* 到全家繳稅免手續費, Apple Pay繳稅單筆滿5仟元送3佰元刷卡金 (全家稅款繳納上限: 新台幣2萬元)

聯邦銀行

推薦原因: 非聯邦銀行存戶也有6期零利率, 抽機票, 貸款送禮券

8期0利率免手續費,
* 單筆稅額達3,000元享8期零利率分期優惠(非聯邦銀行存戶也有6期零利率)
* 一次付清繳稅且單筆滿20萬元: 登錄享紅利點數回饋,每30元回饋1點,最高回饋紅利點數10萬點。
* 聯邦紅利點數100%折抵綜所稅款: 活動期間登錄選擇紅利折抵,紅利折抵以1仟點為單位,每1仟點折抵50元
* 回饋再加碼,萬事達卡抽台北大阪來回機票:
活動期間刷聯邦萬事達卡繳綜所稅不限金額, 抽長榮航空-台北大阪單人來回機票。(共3名)

* 資金靈活貸,再送全聯禮券800元:
活動期間以聯邦卡繳綜所稅,申請個人信貸且成功撥貸者,贈全聯禮券800元,貸款利率前3個月最低1.68%起。

花旗銀行

推薦原因: 繳稅金額0.5%的刷卡金回饋

一次付清,免手續費
* 加碼現金回饋: 可獲繳稅金額0.5%的刷卡金回饋,最高回饋新台幣1000元。(限登錄前20萬名)
* 刷卡單筆繳稅金額滿新台幣888元,可線上搶抽有「天空之城」美譽的祕魯馬丘比丘雙人遊、Gogoro、Apple watch、Nintendo Switch、總額千萬刷卡金等超過160萬個大獎,中獎率達75%。 單筆繳稅金額滿NT$888 (含) 以上可享線上抽獎機會1此,刷越多筆抽獎機會越多; 單月累積消費(含一般合格消費及繳稅金額) 滿NT$5,888 (含) 以上,加享抽獎機會2次
兆豐銀行9期0利率繳稅卡輕鬆 9是刷兆豐:
*單筆綜所稅滿3000元就可分3期0利率、滿1萬元則可分6期0利率。單筆綜所稅繳稅達100萬元以上,兆豐銀將送上1000元刷卡金、繳稅1000萬元以上送3000元刷卡金。
* 使用兆豐頂級卡繳納,則獨享25元1點的紅利點數回饋。
*「台灣pay」兆豐行動優惠: 使用「兆豐pay」綁定兆豐卡繳稅, 登錄後送50元刷卡金, 稅額單筆達1萬元以上, 再加送100元刷卡金。
元大銀行一次付清免手續費
國泰世華6期零利率免手續費,
* 3,000元以上可分6期零利率,同時還有機會抽萬元刷卡金的方案。
108/5/1~5/31 使用「國泰證券電子交易憑證」報稅成功並登錄,即可參加抽獎!
新光銀行4期零利率免手續費,
* 分期優惠:5月份新增一筆一般消費,且繳稅金額滿3,000元,享 4期零利率
* 信用卡紅利點數可折抵綜所稅款: 1000點可抵60元稅款(折抵上限10,000點)
上海商銀6期0利率免手續費,
簡單卡新卡友獨享稅款 1% 回饋: 上限300元, 限108年5月25日前核卡
稅款達1,000元, 登錄即享6期0利率
土地銀行6期零利率信用卡繳納綜合所得稅
一次繳清:免收手續費(核定補徵部分每筆收取手續費新台幣20元整)
分期付款:免收手續費,按月平均攤還本息:
3期:利率0%,總費用年百分率為0%。6期:利率0%,總費用年百分率為0%。12期:利率5%,總費用年百分率為5%。牌照稅3/27-5/2、房屋稅4/26-6/2、綜所稅5/1-6/2 以「土銀行動Pay信用卡」成功完成上述稅款掃碼繳納,每實體卡每一稅種送新臺幣100元回饋金
陽信銀行4期零利率免手續費
安泰商銀6期零利率不限金額免手續費
分期享優惠
稅款單筆滿6,000元(含)以上,且於活動期間新增國內一般消費滿888元,並完成登錄享6期分期0利率
日盛銀行6期0利率免手續費
凱基銀行3期0利率免手續費
全卡友不限金額享刷卡繳稅3期0利率,10萬元以上卡友6期0利率;擁有存款帳戶且繳納稅額達10萬元以上者,更可享高達8期的0利率優惠方案。
台灣企銀3期零利率免手續費,
綜所稅金額達新臺幣3,000元以上者,分期期別及利率:
(1)3期:0利率 (2)6期: 年利率3.99% (3)12期:年利率5.99%
渣打銀行6期零利率免手續費,
不限金額,可享3期或6期分期零利率
合作金庫6期0利率免手續費,
* 繳納綜所稅,即可抽獎:
* 一萬元刷卡金(共10名)
* 星巴克大杯拿鐵(共1000名)

繳納稅金滿10萬元並使用合庫E Pay或台灣Pay行動支付者,可再抽獎:
* * 日本東京或泰國曼谷來回機票一名(共10名)

以Mastercard繳稅可再抽獎:
* * 家樂福禮券5,000元。

第一銀行6期0利率3、6期分期0利率免手續費,
第一重:繳稅百萬送新光三越百貨商品禮券1,000元。
第二重: * 台灣Pay加碼回饋最高150元刷卡金。
第三重: 繳稅抽黃金,新戶再享加碼抽。
第四重: JCB加碼送最高送250元刷卡金
彰化銀行12期0利率免手續費
* 抽出乙位幸運兒獨享:以指定APP綁定彰銀信用卡於108年6月至12月,每筆交易均享100%刷卡金回饋。(回饋上限新臺幣10萬元)
* 以台灣行動支付APP綁定「彰銀JCB信用卡」繳納稅款,每實體卡每一稅種送50元回饋金。
華南銀行6期零利率免手續費,
* 稅款滿50萬登錄送1000元新光三越禮券
* 登錄抽OPEN小將抱枕毯組: 繳稅客群108年5-6月新增一般消費每滿一千元,享一次抽獎機會,滿二千元享二次抽獎機會,以次類推,消費越多機會越多,可抽OPEN小將抱枕毯組(1,480名)。
* 消費滿額登錄稅款享紅利回饋: 繳稅客群108年5-6月新增一般消費金額超過「繳稅金額」或「合計達6萬元」以上,登錄稅額部分享紅利回饋。※限正卡人使用,每戶上限5,000點
* 好康加碼: 使用華南支付綁定信用卡繳牌照稅、房屋稅及綜所稅,登錄再抽三麗鷗可愛明星限量環保袋(限量500份,限使用三麗鷗可愛明星系列信用卡)或卡納赫拉的小動物限量造型陶瓷杯(限量200份,限使用非三麗鷗可愛明星系列信用卡)!
匯豐銀行免手續費,
「萬元刷卡金」抽獎活動:
以滙豐信用卡繳交107年綜所稅,每人可獲得1次抽獎機會,當單筆稅額超過新臺幣10,000元時,每新臺幣10,000元可再增加1次抽獎機會,最多5次。

申請5期或8期年利率0.88%的超優利繳稅分期

台北富邦12期零利率免手續費,
* 不限金額享分期3期或6期0利率、另富邦J卡獨享12期0利率
* 抽獎:
* (1)抽住宿券:以富邦Mastercard卡繳納綜所稅,即可抽台南大員皇冠假日酒店住宿券(價值3999元,3名)
(2)抽黃金:使用「台灣行動支付APP」以富邦信用卡繳納綜所稅,即可抽獎黃金、iPhone XS、Sony Xperia XZ3、統一超商禮券等多項獎

台灣銀行6 期 0 利率免手續費,
* 單筆稅額滿新臺幣(以下同)20,000 元享 6 期 0 利率。
* 使用「台灣行動支付」APP 或臺銀隨身銀行 APP 之本行「行動信用卡」以QRCode 掃碼方式繳納綜合所得稅款成功者可享:
– 1. 單筆綜所稅不限金額享 6 期 0 利率。
– 2. 每戶可獲贈刷卡金 100 元。
遠東銀行8期0利率活動期間刷遠銀HAPPY GO信用卡累積一般消費滿20,000元,單筆稅額達10,000元享分期優惠

2018綜所稅信用卡優惠更新表(107年):

107年信用卡繳綜合所得稅優惠
銀行分期0利率(最高)優惠
星展銀行分期年利率2.99%~14.49%信用卡稅額達滿額門檻並登錄,即可獲得最高500元刷卡金
玉山銀行6期0利率信用卡繳稅分期需於2018/6/2前登錄完成始可參加
花旗銀行6.75% ~ 15%分期利率花旗信用卡繳綜所稅免手續費
元大銀行3期1.88%
6期3.88%
信用卡繳稅單筆1000(含)以上可以分期
國泰世華0.5%分期利率信用卡繳稅一次付清免手續費
新光銀行4期0利率信用卡報稅滿3000享分期優惠
上海商銀6期0利率刷上海商銀信用卡,繳綜所稅超方便
土地銀行3期0利率土地銀行信用卡線上繳稅
陽信銀行4期0利率信用卡繳稅辦理分期之最低分期金額3,000元
安泰商銀6期0利率繳綜所稅單筆達6,000元(含)以上,6期0利率
台新銀行報稅刷太陽/玫瑰卡享1%現金回饋(限新戶)
永豐銀行6期0利率費金額達30,000元,即可享信用卡報稅6期0利率及100元刷卡金回饋
日盛銀行6期0利率需於4/1 – 6/2以日盛卡,新增3筆不限金額之一般消費 ,登錄享繳稅分6期0利率
凱基銀行8期0利率已開立凱基銀行個人存款帳戶信用卡繳稅享8期0利率
中國信託6期0利率信用卡繳稅抽100萬LINE Points點數
台灣企銀3期0利率信用卡繳綜所稅單筆達3,000元(含)以上,即可申請分期
兆豐銀行3期0利率信用卡繳稅贈送「漢來海港餐廳平日晚餐券
渣打銀行6期0利率刷渣打信用卡繳納綜所稅 樂享3大禮遇
合作金庫6期0利率繳納綜所稅,即可抽日本東京或泰國曼谷來回機票
聯邦銀行6期0利率信用卡繳綜所稅紅利折抵100%
第一銀行6期0利率信用卡繳稅登錄刷卡抽行李箱
彰化銀行6期0利率刷卡繳稅抽3萬元刷卡金,最低分期金額3000元
華南銀行6期0利率刷華南卡繳綜所稅達百萬元以上未辦理分期,登錄送新光三越禮券
匯豐銀行0.88~1.88%刷匯豐信用卡繳稅抽LG空氣清淨機
台北富邦6期0利率刷富邦信用卡繳綜所稅抽耳機、義大天悅飯店家庭房住宿券
台灣銀行年利率6.8%刷臺銀信用卡繳納綜所稅,享免手續費優惠
遠東銀行6期0利率信用卡繳稅滿10萬以上+一般簽帳累積10萬享1000刷卡金

2017綜所稅信用卡優惠更新表(106年):

#注意# 報稅截止日 2017/06/01 23:59:59 「週四」晚上報稅截止!

台灣銀行

  • 免手續費 一次繳清:
    • 106/5/1~106/6/1,刷臺銀信用卡繳納綜合所得稅,不限稅額免收手續費。
  • 分期繳稅:
    • 持卡人利用電話語音或網際網路取得授權後,可於106年6月1日前電洽本行客服中心辦理分期繳稅作業,期數為六期,以年利率6.8%計收利息,免收手續費。
  • 活動網址

土地銀行

  • 106年刷土銀信用卡繳105年度綜合所得稅,享免收手續費優惠!分期付款再享優惠利率!
  • 計息方式:按月平均攤還本息。
    (一) 3期:利率0%,總費用年百分率為0%。
    (二) 6期:利率3%,總費用年百分率為3%。
    (三) 12期:利率5%,總費用年百分率為5%。
  • 申請期間:自即日起至106年6月30日止。
  • 活動詳情

合作金庫

  • 免手續費
  • 106/5/1-6/01
    • 單筆滿3,000享分3期0利率、稅額200萬以下分6期0利率、200萬以上分6期手續費100元/筆
  • 抽獎活動:
    • 刷合庫卡繳105年綜所稅,可抽「1萬元刷卡金」(10名)
  • 活動細節

第一銀行

  • 一次付清免收手續費
  • 3、6期分期0利率0手續費
  • 繳綜所稅賺紅利:
    • 活動期間累計新增一般消費達繳綜所稅金額並完成活動登錄後,信用卡繳納綜所稅金額亦享白金卡等級以上每15元、金/普卡每20元回饋紅利點數1點,回饋上限5,000 點,紅利點數將於2017年7 月底回饋至正卡人信用卡帳戶。
  • 活動詳情

華南銀行

  • 好康一:免收手續費
  • 好康二:6期分期0利率(需登錄)
  • 好康三:早鳥請吃酷聖石冰淇淋(需登錄)
  • 好康四:滿額再送萬點紅利(需登錄)
  • 好康五:icash聯名卡加碼抽OPENPOINT點數525萬點(限定兌換長榮航空哩程3.5萬哩)10名(需登錄)
  • 活動詳情

彰化銀行

  • 免收手續費:不限金額,一次性繳款及分期付款皆可享有刷本行信用卡繳稅免收手續費之優惠。
  • 分期付款優惠(需登錄)
    • 繳稅可分3、6期。
    • 高端卡(VISA無限卡/MasterCard世界卡/ VISA商旅御璽卡):享3、6期0利率。
    • 一般卡(排除前述之其他卡片):享3期0利率。
  • 一般消費抽獎:
    活動期間:106年6月1日起至同年8月31日止
    使用本行信用卡繳納105年度綜合所 得稅,該持卡人於活動期間累計新增一般消費每滿3,000元即可得乙次抽獎機會,刷越多抽獎機會越多。 (消費滿6,000元即兩次,以此類推,正、附卡合 併計算消費抽獎機會,以正卡人具中獎資格)

    • 獎項: 刷卡金100,000元 1名
    • 獎項: AMERICAN TOURISTER 18吋行李箱乙個 30名
  • 活動內容

上海銀行

台北富邦

  • 2017/5/1-6/3
  • 稅額滿10,000元,享3期0利率
  • 稅額滿100,000元,享6期0利率

國泰世華

  • 免手續費
  • 106/5/1-6/3 :享最高6期0利率
    • 6期0利率:財管VIP/世界卡/無限卡/鈦金商務卡/御璽卡
    • 3期0利率:其他卡
  • 刷卡繳稅送TreeMall購物金
  • 活動詳情

兆豐銀行

  • 免手續費
  • 106/5/1-6/1 : 稅滿3千以上可辦3期零利率
  • 抽獎活動:
    • 首獎→贈當年度稅金金額之刷卡金(最高2萬,3名)、貳獎子母行李箱、三獎飛狼旅行三件組
  • 滿額活動:稅達3百萬以上,送「施華洛世奇」水金對筆組乙組
  • 活動詳情

花旗銀行

台灣企銀

  • 免手續費
  • 106/5/1-6/15
  • 單筆滿3,000享分3期0利率
  • 活動詳情

澳盛銀行

  • 免手續費
  • 2017/5/1-6/03
  • 登錄享綜所稅額3期0利率
  • 綜所稅額達1萬元者,登錄享現金回饋100元
  • 活動網址

匯豐銀行

渣打銀行

  • 免手續費
  • 2017/5/1-5/31
  • 申辦分期享3期、6期0利率
  • 活動網址

台中銀行

  • 免手續費

新光銀行

  • 免手續費
  • 106/5/1 – 6/2
    • 單筆滿3,000享分4期0利率
    • 抽獎:墾丁華泰瑞苑住宿憑證乙份 (10名)
    • 加碼抽:同一持卡人繳交綜所稅+房屋稅 抽獎機會再多一次!!

陽信銀行

  • 免手續費
  • 106/5/1 – 6/2
    • 分3期0利率及免分期手續費
  • 活動詳情

聯邦銀行

遠東商銀

  • 免手續費
  • 2017/5/1-6/3
  • 分期0利率:
    3期:繳稅達3千元以上即可申請
    6期:遠東快樂信用卡或遠東商銀VIP尊榮會員達3萬元即可申請
  • HAPPY GO 4點折1稅金(折抵無上限)
  • 活動內容

元大銀行

N/A

永豐銀行

  • 免手續費
  • 2017/5/1-6/3(繳稅期間)
  • 分期0利率:
    • 3期:單筆繳稅金額達2,000元
    • 6期:單筆繳稅額滿3萬元 或 累積一般消費滿3萬且單筆繳稅金額達2千
  • 滿額活動:繳稅滿10萬元,送1百元百貨刷卡金
  • 活動詳情

玉山銀行

  • 免手續費
  • 2017/5/1-6/1
    • 新增一筆消費,可享3或6期0利率
    • 抽獎活動:可抽RIMOWA行李箱(5名)、西堤餐券2張(50名)
  • 活動詳情

凱基銀行

星展銀行

N/A

台新銀行

  • 免手續費
  • 【一次付清優惠最超值】
    • 1.滿額送桃園機場環宇商務禮遇通關 (不含Visa金融卡)
      • (a)繳稅滿NT10萬元,送一次(市價NT$4,800)
      • (b)106/4/1-106/6/30累計消費滿20萬元送兩次、滿50萬送四次
      • (a)(b)擇優回饋。
    • 2.特定客群再加碼 (不含Visa金融卡)
      • (a)繳稅新戶加碼: 6.7月新增一般消費滿1萬元送100元、滿10萬元送500元(各限量1000名,7月統一回饋)
      • (b)VIP貴賓繳稅滿額送:近三年曾刷台新卡繳稅之VIP貴賓,享繳稅滿60萬元送500元刷卡金;滿250萬元送1,000元刷卡金
  • 【早鳥獨享88繳稅金】
    • 5/15前台新卡得利APP/官網登錄,並完成繳稅加刷任一筆不限金額消費,贈88元刷卡金(消費排除項目詳注意事項所述,限量10,000名,7月統一回饋,不含Visa金融卡)
  • 【紅利點數折抵繳稅0負擔】
    • 台新卡得利APP/官網登錄紅利點數折抵,繳稅0負擔(折抵上限不超過稅額,每1000點折抵60元,未滿1,000點恕無法折抵,7月統一折抵,不含Visa金融卡)
  • 【分期0利率輕鬆繳】
    • 分期享4期0利率 (不含Visa金融卡)
  • 【筆筆再抽全額幫您繳】
    • 不限繳稅金額,抽每人最高回饋NT50,000元(正附卡合併計算,限5名,不含Visa金融卡)
  • 活動詳情

大眾銀行

日盛銀行

  • 免手續費
  • 2017/5/1-6/3(繳稅期間)
    • 免手續費族群:單筆稅款1百萬以內,超過者手續費0.1%符合以下任一條件卡友,登錄享106年5月以日盛卡繳所得稅稅款分5期0%:
      • 1.106年4~5月任刷3筆不限金額之一般消費。
      • 2.106年5月底前成功下載日盛HCE行動信用卡。(限106年首次新下載卡友)
  • 活動詳情

安泰銀行

  • 免手續費
  • 2017/5/1-6/5
  • 抽獎:哈根達斯冰淇淋、膳魔師悶燒罐、康寧晶彩鍋
  • 活動內容

中國信託

  • 免手續費
  • 2017/5/1-6/3(外籍人士~6/1)
  • 持Line Pay卡享6期0利率、LinePoints 1%點數回饋無上限

樂天信用卡

N/A

美國運通

N/A

永旺信用卡

N/A

2019/05/22

2020行事曆 中華民國109年更新版《行政院已核定人事行政局公告》

行政院已核定2020年 政府行政機關辦公日曆表

資訊出處:行政院人事行政總處
行政院人事行政總處表示,3天以上的連續假期共六個,包括農曆除夕及春節7天連假、228和平紀念日(3天)、清明節(4天)、端午節(4天)、中秋節(4天)及國慶日(3天),明年共放假115天

最新公告的時間:108.05.01
109年辦公日曆表

2020年農曆除夕及春節連續假期自1月23日起至1月29日,共放假7日
並配合1月11日總統、立委大選投票日、1月18日為109學年度學科能力測驗、2月1日及8日為術科考試,因此在2月15日(星期六)補行上班。

端午節 放假4天 / 中秋節 放假4天
都適逢週四,週五都將調整為彈性放假! 因此端午節4天連假為6月25日到6月28日,將在6月20日補上班;中秋連假10月1日到10月4日,9月26日補上班。

清明節 放假4天
兒童節及民族掃墓節(清明節)為同一日,並適逢星期六,依「紀念日及節日實施辦法」及內政部函釋,於4月2日補假、4月3日放假,因此,兒童節及民族掃墓節有4日連續假期;

國慶日 放假3天:
10月10日適逢週六,週五10月9日補放假,因此也會從10月9日到11日放假3天。

人事總處強調,政府行政機關辦公日曆表僅適用於政府行政機關公務人員,至於公營事業機構人員的放假,原則上比照辦理;軍人的放假,則屬國防部主管權責,應依該部規定辦理。另各級學校適用的學年度行事曆,是由各該主管教育行政機關訂定。此外,民間企業人員的放假涉及勞動基準法相關事項,應依該法主管機關勞動部的規定辦理。

檔案下載:

109年辦公日曆表.xls 
109年辦公日曆表.pdf 
109年辦公日曆表.ods

2019/04/10

理財筆記-綜合所得稅《如何節稅與避稅?》整理小技巧減輕個人租稅負擔!

首先說一下基本節稅方式:

個人所得稅部份有以下幾個方式可以參考:(可憐的小老百姓的基本作法)

    1. 除了本薪以外的公司福利,可不列入員工薪資所得。

      包括伙食津貼、交通津貼等等名目所得稅法規定,「除了本薪以外之公司福利,按月一千八百元以內之伙食津貼、公司旅遊等,可不列入員工薪資所得」。

    2. 加班費可免稅

      在 勞動基準法規定的加班時數內加班費可免納所得稅 (男生一個月46小時,女生一個月24小時 )。例如一位員工如果在正常工作天已加班四十九小時,四十六小時的部分依規定可以免稅,另外超過的三小時加班費則要併入薪資所得課稅。另外若在國定假日、 例假日的加班費,可免納所得稅。

    3. 公教人員子女獎學金可免稅

      公教人員子女教育補助費屬薪資所得須課稅,但子女獎學金如果是以在校學業和操行成績達到特定標準者,就可以免稅。

    4. 變動所得只須申報半數

      一次給付的養老金、退休金、資遣費等,是屬「變動所得」的納稅義務人,其所得只須就半數申報。

    5. 結婚

      ;夫妻合併申報再加上生小孩就可增加扣除額。

    6. 貸款買房屋

      ;房屋貸款也有貸款扣除額,目前最高每年30萬為上限。

      • 善用購屋借款利息扣除額,節稅機會別錯過!
        有相當多的年青人是以貸款購置自用住宅的方式找殼,每年負擔了不少的利息支出,申報綜合所得稅時,正可選用列舉扣除額,享受有殼成就感與租稅優惠。
        購屋借款利息的可扣除額度,是以支付自用住宅借款利息減去申報之儲蓄投資特別扣除額後,每一申報戶得於三十萬元限額內申報扣除。但須符合下列規定:
        1、每一申報戶只能申報一棟房屋,並不是按人頭計算,且房屋必須是屬於納稅人本人或配偶、扶養親屬所有(所有權人為同一申報戶)。
        2、納稅人本人、或配偶或其扶養親屬在申報年度內於該地已辦妥戶籍登記。
        3、房屋必須為自住用途,無出租或供營業使用。
        4、購屋借款限於向金融機構借貸者,向一般公司或個人之借款不得扣除。另外,舉新債還舊債所支付之自用住宅購屋借款利息,只要是新債和舊債的借款房屋是同一棟房屋,且借款時間銜接,則在舊債未償還的額度內所支付者,還是可以申報扣除的。
        如果是以修繕貸款或消費性貸款名義借款,但確實是用於購買自用住宅,要能檢附所有權狀影本或建物登記謄本、借款契約等有關文件,利息支出也可以申報,稽徵機關會依借款目的或借款與買房子時間相近程度決定是否認定。
        如果房屋有部份營業,部份自住,則購屋借款利息可按自住之比例扣除。納稅義務人可以房屋稅單上的課稅現值,區分出營業與住家比例,再 用此比例算出有多少利息可歸為購置自用住宅的利息支出。必須注意的是,以原有住宅向金融機購借款,或購買投資用的非自用住宅,其借款是不能扣除的。
    7. 房屋租金

      支出可扣除,付款憑證莫忘記!
      為減輕無殼蝸牛的負擔,自89年度綜合所得稅結算申報起,房屋租金支出可列為列舉扣除的項目。納稅義務人及其配偶與申報受扶養直系親屬在中華民國境內租屋供自住且非供營業或執行業務使用者,其所支付之租金,每一申報戶每年扣除數額可以在12萬元的限額內列報減除。但如果申報有購屋借款利息者,不得再適用此項扣除額。所以納稅義務人如同時有合乎規定之購屋借款利息與房屋租金支出時,應自行計算2者可扣除之金額,以較大者申報減除。列報房屋租金支出時,應檢附:

      • *承租房屋之租賃契約書及支付租金之付款證明影本(如:出租人簽收之收據、自動櫃員機轉帳交易明細表或匯款證明)。
      • *納稅義務人本人、配偶或申報受扶養直系親屬中實際居住承租地址之1人,於課稅年度於承租地址辦竣戶籍登記或納稅義務人載明承租之房屋於課稅年度內係供自住且非供營業或執行業務使用之切結書等,以供稽徵機關核認。所以別忘了將支付租金之證明文件好好保存,以備申報年度綜合所得稅時檢附。
    8. 撫養與認養:

      • 申報撫養親戚或長輩: 最好能找有殘障手冊資格的扣除額愈多。
      • 外籍配偶(中國大陸/東南亞/外國配偶)的父母也可列為受扶養對象,稅務單位會依法受理,不過民眾須依規定填報證明,才能享有扣抵。至於扣抵額度,原則上與本國父母扶養一致,不會有差別待遇
      • 認養:認養也可被視為撫養親屬,多多認養扣除額愈多。

      增加受扶養親屬的人數就是最好的扣除額,人多就是扣除額多,免稅額也就增加了。多扶養一位親屬可以 增加82,000元的免稅額,年滿七十歲以上的扶養親屬還可以增加到123,000元的免稅額˙扶養親屬的首選為直系尊親屬(如父母親、祖父母)其次為再 學或未成年的兄弟姐妹。 今年更放寬只要合於民法第1114條第4款及第1123條第3款規定,未滿20歲,或滿20歲以上而因在校就學、身心障礙或無謀生能力,確定是受納稅義務 人扶養,且與納稅義務人同居一家者,就可以列報減除免稅額。如果以適用所得稅率十二%的家庭計算,納稅義務人每多扶養一名「其他親屬或家屬」,可少繳九八 四○元稅金。
      小提醒:
      *有共同居住和扶養事實是重要條件。
      *無謀生能力者應優先被子女扶養,其次是父母,接下來的順位依序為家長、兄弟姊妹、家屬、媳婦或女婿、夫妻的父母(岳父母或公婆)。若由後順位者申報扶養,要有正當理由或合理說明。
      *高所得者常會列報扶養其他親屬或家屬節稅,其中以列報兄弟姊妹的小孩最常被剔除。因為小孩應優先由父母扶養,納稅義務人的兄弟姊妹有能力扶養,就不能報在其他人名下。

    9. 捐贈節稅

      : 找企業或慈善機構認捐贈;其捐贈金額可全額扣除。

      • 申報綜合所得稅時,捐贈亦是可以列舉扣除項目之一,如妥善運用可以有效降低適用稅率。但並不是所有捐贈都符合列舉扣除之規定,現行稅法對捐贈對像和金額甚至捐贈時間都有明確規定。一般來說,捐贈可分為:
        一、得申報為列舉扣除額之捐贈:
        1、對合於民法總則公益社團及財團法人組織或依其他關係法令,經向主管機關登記或立案成立之教育、文化、公益慈善機構或團體的捐贈,有金額的限制,其捐贈總金額不能超過綜合所得總額的百分之二十。
        2、對政府單位的捐獻或有關國防、勞軍及依文化資產保存法第31條之1規定出資贊助維護或修復古蹟、古蹟保存區內建築物及歷史建築之贊助款的捐贈,則沒有金額的限制。
        二、依公職人員選罷法規定所為之捐贈即俗稱的「政治獻金」
        1、對政黨、政治團體及擬參選人之捐贈,每一申報戶可扣除之總額,不得超過當年度申報之綜合所得總額20%,其總額並不得超過20萬元。
        2、對同一擬參選人每年捐贈總額不得超過10萬元。但對於未依法登記為候選人或登記後其候選人資格經撤銷者之捐贈或收據格式不符者,不得列報。
        3、對政黨之捐贈,政黨推薦之候選人於93年度立法委員選舉之平均得票率未達2%者或收據格式不符者,不得列報。
        4、捐贈發生之時點須於政治獻金法規定期間方可扣除。
        三、個人對私立學校之捐款:
        依私立學校法第51條規定,透過財團法人私立學校興學基金會,對私立學校之捐贈,其金額不得超過綜合所得總額50%。須檢附受贈單位(財團法人私立學校興學基金會)開立之收據正本。
    10. 保險費節稅

      依稅法規定,納稅義務人如採列舉扣除,則其本人、配偶和受其申報扶養直系親屬的人身保險(包括人壽保險、健康保險、傷害保險、勞工、軍公教、農民保險、學生平安保險、旅遊平安保險、全民健康保險及其眷保)之保險費,在申報扣除年度繳納者,每一被保險人每年可在不超過二萬四千元的額度內申報扣除。
      值得注意的是被保險人與要保人要在同一申報戶,而且如果列報扶養親屬的保險費支出,必須是受納稅義務人扶養的直系親屬才可申報,如為兄弟姐妹或其他非直系親屬,或是產險方面(例如汽車責任險)的保費支出,都不可列報扣除。

      • 小提醒:保險費繳納收據是申報扣除的關鍵?
        *檢視保險費收據或相關證明有無收集齊全。
        *為全家繳納全民健康保險費之支出有無請投保單位將保費分依被保險人名義開立收據?
        *由服務單位經收彙繳之員工保險費有無向服務單位申請填發繳納保險費證明?
    11. 醫藥及生育費, 如憑證符合核實列報無上限!

      您可知道可用以節稅的醫藥及生育費用項目有那些嗎?

      1. 納稅人本人、配偶及同居受扶養親屬的醫藥費及生育費用(含掛號費及伙食費)只要是付給公立醫院、公務人員保險特約醫院、勞工保險特約醫院及診所或經財政部認定會計紀錄完備正確的醫院,都可以憑醫院、診所出具的費用收據列報,沒有金額的限制。就醫或生育時別忘了向合於規定的醫院、診所索取收據,妥善保存。
      2. 因身體殘障所裝配的助聽器、義肢、輪椅等各項支出,可以憑醫師出具的診斷證明與統一發票或收據,全數列報扣除。
      3. 因牙病必須做鑲牙、假牙製作或齒列矯正的醫療費及器材費,也可以憑醫師或院所出具的診斷證明及收據,列報扣除。不過,如果齒列矯正、鑲牙是以美容為目的,醫藥費就不可以申報扣除。
      4. 付給養護中心的養護費並不在醫藥費列舉扣除項目中,但如果養護費中確有具醫療行為的支出費用,只要將屬於醫療給付部分的費用,單獨開立收據,就可以申報扣除。
      5. 付給依法立案之公立單位或與全民健康保險具有特約關係之護理之家機構及居家護理機構,可檢附該機構出具之收費收據及醫師診斷證明書,申報列舉扣除。
      6. 給付公立、全民健康保險特約之設置救護車機構,因救護車執行勤務依緊急醫療救護法規定收取之費用,可憑該機構摯發之收款憑證申報列舉扣除。
      7. 因病赴國外就醫,只要能檢附國外公立醫院或國外財團法人組織的醫院、公私立大學附設醫院出具的證明,就可列報扣除。
      8. 本人、配偶或其同居受扶養親屬,在合於上述規定之醫療院、所治療,因病情需要急須使用該院所無之特種藥物,而自行購買使用者,其藥費可憑該醫療院、所之住院或就醫證明、主治醫師出具准予外購藥名、數量之證明及書明使用人為抬頭之統一發票或收據,申報醫藥及生育費列舉扣除。
        • 小提醒:一醫藥及生育費收據憑證已繳交服務機關或遺失時應如何申報?
        • *單據已繳交服務機關申請補助者,需檢附經其服務機關證明之該項收據影本。
        • *收據正本遺失時,可憑原醫療院、所開立之收據存根聯影本,並由該單位註明「影本與原本無異」之字樣及負責人蓋章證明申報列舉扣除。

投資理財的8大節稅妙招

(修改自林凱萍 吾愛吾家267期,三月號)
又要繳所得稅了,「收入差一天,繳稅差一年」,牢記這句箴言,延後所得發生的時間,將可在支付個人綜合所得稅上產生節稅的效果。此外,妥善保管扣繳憑單,也可以少繳不少冤枉稅。

留意現金收入的收款日

由於綜所稅的課徵是依照收入實現制,而非企業所用的權責發生制。因此如果有一筆現金收入,收款日期選在今年12月31日或是明年1月1日,兩者下場就會截然不同,後者將再隔一年才須繳稅,多賺了利息錢,也拉大理財空間。

隔年初領款可免利息超過扣除額

若預期今年全家(扶養眷屬與小孩有所得還是要申報)利息所得會超過27萬元儲蓄特別扣除額,恰巧有一筆定期存款將在年底到期時,聰明的做法便是延到明年初再去領款,屆時金融機構將會開出今年度的扣繳憑單,就可以在明年度再申報這筆利息所得,解決今年利息收入超限的困擾。

保存支出單據爭取減免和退稅

此外,注意蒐集扣繳憑單,以及部分生活支出證明文件,例如醫藥費、購物貸款利息支出、捐贈證明等,都可以成為應納稅額的減項,可以降低應納稅額甚至是退還稅款。總之,證據愈齊全,愈不會白繳冤枉稅。

 

股利扣抵稅額減半

上市櫃今年給付個人居住者股東股利由「完全設算扣抵制」修正為「部分設算扣抵制」,亦即盈餘分配日為104年1月1日以後者,股東可扣抵稅額為原可扣抵稅額的半數,抵扣金額減半,負擔自然變重。

舉例:55歲從事科技業,投資股票的黃先生,一家股價100元上市櫃公司,繳17%營所稅後,再配給股東5元現金股息,若是股民持有1張該公司股票,即可領5000元的現金。

若黃先生參加除權息,而這家公司的股東可扣抵稅率是13%,可扣抵的稅額是650元(5000元×13%),但因股東可扣抵稅率減半,現在只能扣抵325元(5000元×6.5%),

也就是說,投資人申報股利所得5650元,若以個人綜所稅12%級距來算,稅額是678元(5650元×12%),舊制僅需繳稅28元(678元-650元),但新制卻得繳353元(678元-325元)負擔明顯加重。

6種收入 須繳補充保費

依《全民健康保險法》保險費計算公式說明(最新105.01.01更新)
● 民眾如有下列6項所得或收入時,由扣費單位按費率1.91%就源扣取並繳納補充保險費。
● 公式:計費所得或收入 ×費率1.91%

Q什麼是「補充保費」?
正解》原本的保費都是受薪階級在繳,靠收租、收利息、玩股票賺錢的人,可以技巧性地規避,有失公平性,因此自2013年起,健保署便將「補充保費」納入繳交規範。只要其他業外收入單筆進帳超過2萬元,而未超過1,000萬元,就得扣繳1.91%補充保費。

也就是說,除了一般健保費之外,一般人會有的額外收入,包括兼職所得、執行業務收入、股利(包括現金、股票)所得、利息所得、租金收入及獎金等6項,都有機會被扣補充保費,好在扣費門檻已從原本的5,000元調高到2萬元,費率也從2%調降為1.91%,讓之前忙著拆單的定存族和菜籃族可以鬆口氣。

● 以H公司為例,若每張現金股利發放4萬元,每張要課徵764元補充保費。
補充保費=4萬元×1.91%=764元

● 以T公司為例,若每張股票配發3,000元現金股利,且沒有配發股票股利,因未超過兩萬元,不用課徵健保補充費。

Q投資人最在意的股票股利如何課徵?
正解》目前補充保費都要「就源扣繳」,但股票股利扣取方式無法依此方式。依《所得稅法》認定,以股票法定面額每股10元計算,配股數乘以每股法定面額10元後,超過2萬元時,須扣繳1.91%的補充保費。

參加海外公司除息 (大家常聽到的KY股)

幫自己累積財富的方法,就是參與每年一次的股票除息,只要選對股,就可以在每年的第四季之前,有一筆不小的現金收入唷!如果怕接下來取消兩稅合一之後,參與除息會不划算,最好的方法就是選擇在海外註冊但回台上市(櫃)的公司(大家常聽到的KY股),因為股利所得視為海外所得,而個人海外所得不超一百萬元者,是不需要申報的。

當然其中因為美國稅法的關係,必須排除營業地區在美國或是登記在美國的公司,才不會避掉了台灣但卻被美國課稅(過去曾發生科納-KY的股東遭美國國家稅務局追稅的案例),或是可選擇註冊地在開曼群島的個股。

海外基金免稅是大戶的最愛

另外,共同基金是現在十分熱門的理財工具,其實有不少人投資基金都基於節稅考量。富邦銀行個人理財中心表示,由於我國稅法對個人是採取「屬地主義」 ,只要這些獲利所得不在台灣,政府對於境外所得都可以免稅。因此,「合法節稅」反而成為許多國內投資大戶,投資海外基金的最大目的。

但國人投資的海外基金,如果基金公司的註冊地不是免稅國家,投資人雖然可以免繳國內個人綜合所得稅的利息收入部分,但是整個基金投資國家、地區或市場的相關交易稅賦將反映在淨值中,仍然無法完全免稅。

國內債券型基金穩定獲利也可節稅

因為投資的國內基金,如果不是每年發放股利,或是股息所得不超過每年27萬元的免稅額,甚至是投資在不配息的股票型基金,以及債券型基金,也可合法的規避綜合所得稅中利息課稅的問題。

國內的債券型基金雖然名為債券型基金,但是國內目前幾乎找不到純的債券型基金,實際結構上大半偏向於貨幣型基金的投資內涵(也有人稱為「貨幣市場基金」 ,其中80%投資在一年期以內的票券,只有20%投資在債券買賣斷) ,為了讓投資人達到節稅的效果,這些國內債券型基金都不分配股息,而是將股息灌入淨值中,以買賣時的價差當做股利的發放。

這樣做的好處是只要不配息,就不會列入個人綜合所得稅27萬元的免稅額度內計算,資本利得(投資的價差收益)又不用課稅,可讓投資人達到完全節稅的目的。

贈與稅免稅額,以及用小孩帳戶買基金或買股票

  • 220萬贈與稅免稅額(文:不敗教主)
    每個人每年有220萬的免稅額,但是大家常常誤解。我來舉例說明,我有三個小孩,不是我每年可以給每一個小孩220萬。而是『我』一年只能給別人220萬,我的三個小孩要平分這220萬。家庭夫妻2人,一年可以贈與220+220=440萬給小孩,這個是免稅的。假設我的小孩要買房子或是創業,需要1000萬的資金,那麼我們夫妻可以在今年12月底跟隔年的1月,各贈與440萬給小孩,這樣總數880萬都是免稅的。剩下的120萬就必須要繳交10%也就是12萬的贈與稅。總共贈與1000萬也只繳了12萬的稅,還是挺划算的。基於好國民的論點,我強烈建議『合法節稅、繳稅』,不要以為每天領現金給小孩就可以逃稅,財政部不是每天吃飯跟睡覺的,不要去挑戰財政部。一旦被逮到,除了補稅還要罰錢,神仙難救。要節稅,就要事先規劃。
  • 利用子女的名義購買共同基金
    雖然目前國內基金,不能像直接赴海外投資基金一樣,可用聯名方式開戶。但只要是有身分證,甚至是出生證明的小孩,都可以個人名義申購基金。而且只要申購金額,每年不超過100萬元台幣,既不用繳交贈與稅,也同時做了遺產稅的規劃,可以說是一舉兩得。
  • 善用子女的戶頭來投資股票
    也可以用子女的戶頭來投資股票,未成年也可以開戶。利用子女的戶頭來買股票,首要目的就是節稅(贈與、遺產稅)。假設利用每人每年220萬的免稅額,你每年在小孩戶頭存進220萬來買股票,持續10年後就投入了2200萬,這筆錢完全免稅。而且這筆錢會因為複利一直在增值,搞不好再過10年小孩戶頭的股票就增值到了5000萬。如果用現金贈與,5000萬是要課徵500萬的贈與稅的。所以,如果你有大筆的資產要贈與,利用每年的免稅額買進績優股票來贈與,不僅可以享受投資的複利,也可以節稅。但是,小孩子戶頭有那麼多錢,要注意他的交友,而且也要注意親友、配偶從小孩子那邊挖錢。萬一小孩子長大,他想要自己管理『他自己帳戶內的錢』,這個也挺傷腦筋的。就算小孩子的存摺、印章、密碼都是你在保管,理論上,小孩子成年後可以拿著身份證件,到銀行去把所有的錢通通領走。所以,不要把所有的財產贈與給小孩。

      • Q1: 用小孩子的名字買股票, 股利所得可以免申請嗎? 或還是一樣併入大人所得?
        A1: 跟大人一起申報,同一戶即使受扶養眷屬有所得還是要申報
        因為小孩無法獨立申報所得,所以還是無法達到節稅的目的,但是有做到規劃遺產稅的節稅目的,
        用小孩買股票無法做到節稅,除非小孩可獨立申報,
      • Q2. 去年買股票有賠, 今年拿到的股利, 還需要課稅嗎?
        A2: 要,股票買賣因為已停徵證券交易所得, 所以交易損失不得申報財產交易損失

     

  • *****爸媽必須注意*****:(聯合報 許祺昌口述、記者賴昭穎採訪整理)小孩的所得本來就少,或根本沒有所得,一旦名下突然冒出許多股票、增加很多股利所得,都可能被財政部財稅資料中心列為異常檔案。國稅局會根據資金流向追查來源,只要發現資金來自父母戶頭,就會要求父母說明是否贈與財產給小孩。國稅局聽取父母的說明後,會根據相關說法做不同判定,父母親要繳的贈與稅也有差別。

    1) 最嚴重的狀況是,被國稅局認定為直接「贈與」金錢給子女,除了必須繳交10%的贈與稅,還得被罰稅額1倍的罰鍰。舉例來說,有父母拿出1000萬元用小孩的名義買股票,扣掉220萬元的贈與免稅額,等於780萬元的贈與額要課稅,贈與稅率是10%(78萬元),外加稅額1倍罰鍰(也是78萬元),合計要繳給國庫156萬元。如果國稅局認定是幫小孩買股票,「視同贈與」,就只需補繳稅款,不用罰鍰,但必須在10天內申報贈與稅。同樣以父母出資1000萬元為例,補繳78萬元的贈與稅即可。至於「贈與」和「視同贈與」,最大的區別在於贈與人和受贈人是否「合意」,也就是說,如果子女知道父母出錢幫忙買股票,就得補稅加罰;但子女若不知情,就認定為「視同贈與」,只需補繳贈與稅。不過,除非贈與人能提出充分理由,否則國稅局認定為「視同贈與」的狀況並不多。

    2) 還有一種結果,是被認定為刻意分散股利所得,小孩只是父母的人頭戶,就不是「贈與」,而是逃漏綜合所得稅,因此要補綜所稅的差額,並且要依據所得稅漏稅額來罰鍰。例如父母出資額1000萬元、股票配息5%,換算後股利所得50萬元;如果父母適用40%稅率,原本要繳20萬元所得稅,但父母以稅率5%的小孩為人頭,稅金降到2萬5000元。國稅局除了要求父母補繳17萬5000 元所得稅,另外還要罰1倍,總共吐出35萬元。

     

值得注意的是共同基金雖然有節稅的效果,但投資最重要的目的,是賺取最高的資本利得與利息,所以「賺不賺錢」應該是投資人最應謹記的標準,千萬不要為了節稅反而遭受投資損失。

進階的節稅方式:

除了考慮個人的薪資所得,全戶的薪資狀況亦應一併考量。例如子女年屆廿歲或家中其他扶養親屬有薪資所得時,最好將該親屬的所得額與可扣除的各項扣除額合計數拿來好好試算一下,決定是否由其單獨申報,以達到另一種節稅的效果。

  1. 開公司或是開店營業;兩稅合一也可以將營業費用拿來做其扣除額。

參考-公司如何節稅?

概略的回答問題,至於詳細的節稅操作,建議您跟主動多跟您的會計師討論。

問題1:個人獨資所成立的有限公司, 如何節稅?

答:一般公司的主要稅目有兩個「營所稅」、「營業稅」,這兩種稅各有不同的節稅技巧。營所稅可以技巧性的選擇「書審申報」或「查帳申報」方式,可以有不錯的節稅效果。

問題2:在整年度的營運中有那些項目單據是可以報帳結稅的?

答:基本上,取得的支出單據都要是載明公司統一編號的發票或收據(交通費用例外)。而前面提到的兩個稅法,對於單據的規定不太一樣,整理如下,有點多,要耐心看看,也建議您多跟同業或會計師討教。

壹、營業稅可扣抵、營所稅可入帳之憑證

  • 1.進貨(料)、工程款、預付款、分期付款、定金之發票或退回折讓證明單。
  • 2.購置五金、工具、書籍雜誌、設備、貨車、客貨兩用車、機車、裝璜工程、空調工程、小噸數冷氣、電話、電腦硬軟體、辦公用品、其他固定資產之發票。
    *小噸數冷氣機不可太多;傢俱桌椅應於發票寫為辦公桌椅;萬客隆、家樂福、高峰之發票應附物品明細表且所列須全為可扣抵。
  • 3.汽車加油、修理之發票。(毋需打車號)
  • 4.出差住宿、租用設備之租金發票。
  • 5.參加外界訓練費用之發票。
  • 6.佣金支出、利息支出、運費取得之發票。
  • 7.工作服、衛生紙之發票。
  • 8.報紙、雜誌、電話簿產品廣告收據。
  • 9.水費、電費、瓦斯費收據。
  • 10.機票扣抵聯(需為員工)。
  • 11.其他。(請與事務所聯絡以明能否扣抵。

貳、營業稅不可扣抵、營所稅可入帳之馮證

  • 1.購置轎車(需登記公司名下)、冰箱、電視、音響、瓦斯爐、飲水機、熱水器及其他員工福利之發票。
  • 2.便餐、禮品、百貨之發票或收據。(有限額,約為營收0.5%
  • 3.人事廣告、大樓管理費收據;停車、過橋、通行之收據;茶葉、香皂之發票或收據;國內客運、火車購票證明聯。
  • 4.郵票購票證明單;政府稅捐、規費繳款書。
  • 5.團保壽險、產險、火險、勞健保之保費收據。
  • 6.銀行利息、手續費收據;訂閱報紙雜誌之收據。
  • 7.個人一時貿易盈餘申報表。(例如:直銷商、未營利登記之個人買賣)
  • 8.小店戶(小規模營利事業)之收據。(有限額,為營業費用及製造費用之3%)
  • 9.旅行社開立國外機票、團費、代辦費之代收轉付收據或航空公司開立之購票證明,連同機票票根填具差旅費報告單以「差旅費」入帳。
  • 10.其他。(請與事務所聯絡以明能否入帳)

參、營業稅不可扣抵、營所稅可入帳但須扣繳之憑證

  • 1.按月給付薪資依薪資所得扣繳稅額表扣繳。
  • 2.臨時工依6%扣繳,並於臨時工工資表及背面之切結書簽章。
  • 3.佣金依10%扣繳。
  • 4.租金依10%扣繳,並取得其房屋稅單影本。
  • 5.執行業務所得(如會計師、律師...等)依10%扣繳。
  • 6.其他(請與事務所聯絡以明扣繳率)
  • 7.每次應扣繳額未超過2000元(以員工個人為單位)免於扣繳。
  • 8.應於每月10日前填寫繳款書將上一月所扣稅款向銀行繳清。
  • 9.為能順利於年底填寫扣繳憑單,應取得被扣繳者之身份證正反面影本。

2019/04/01

國外消費刷信用卡, 當天刷卡匯率怎麼查詢? JCB,Master,VISA

在國外消費的時候的價格與最後信用卡帳單的價格有點不同, 究竟為什麼會這樣呢? …原來是匯率的日期導致的, 刷卡匯率通常是以店家向銀行請款的日期為主, 每個發卡銀行與組織有不一樣的匯率表, 每天都不同

不同發卡組織的查詢連結:

2019/03/26

參觀新北市永和區附近的幼兒園_心得與隨筆紀錄

小孩即將要到要到上幼兒園, 考量點主要有學校的環境, 日常作息, 教學內容, 校外教學, 樓層高低, 學校地點要在永和區附近不要太遠, 符合上下班接送! 有些觀察很主觀, 所以僅供筆記, 勿筆戰

(陸續補充中…)

公立_永和幼兒園民生分班:
就在永安傳統市場上面的二樓, 旁邊是市民活動中心, 校地比起很多私立大滿多的, 空間規畫很整齊, 遊樂設施也滿多的, 安全而且環境乾淨! 必須要抽籤才能就讀, 小班競爭激烈, 越大的孩子有優先權, 我家孩子備取第67, 老師說應該是排不到了, 目前只有錄取到備3

野聲
校地很大, 而且庭院有一棵大樹, 樹上有小鳥, 好夢幻的情境在永和竟然也能看到, 讓媽媽心花怒放! 學校有分全美班以及雙語班, 稍微參觀了一下, 全美班的位置在門口進來的右手邊, 每班有一外師一中師帶著, 全美班很夯, 必須要很早就預約排隊才有機會讀到, 我們太接近開學日了已經沒什麼希望就讀, 但老師還是有留我們聯絡資料, 只是後來老師也無聯繫我們, 應該是沒有名額! 但這裡外師的確是跟著一起帶小孩, 用英語跟孩子溝通觀念與生活常規! 然後繞過大樹之後的建築物就是雙語班, 依照小班中班大班分配在不同樓層, 我們跟著園長一層層參觀, 但我不是很喜歡孩子在不同樓層間的移動, 畢竟小班還小的孩子我覺得多少有點危險, 但其實學校已經在樓梯作了很多防護措施, 應可放心! 這邊的英語教學顯然就弱了一些, 當天我看到的是中師有點照著課本上課, 比較不像邊遊戲邊學習, 環境乾淨, 整體來說讀野聲孩子們很快樂, 由於校地夠大孩子跑跳活動力十足, 感覺很健康, 只能排候補

育才
與野聲幼兒園同屬於育才體系, 而育才幼兒園與育才國小是在一起的校區, 所以育才附設幼兒園是校區前面的區域, 2018整修完畢環境很乾淨, 特別的是一班15人一個老師, 所以班級數比較多, 教室也寬敞一些, 沒有廚房所以飲食不是現場製作的, 注重注音符號與ABC英語教學, 有分全美班與雙語班, 雙語班的英語老師也是全英語教學, 英語課教學活潑有趣, 果然是強調外語的學校, 學期末會有舞台表演讓孩子上台跳舞演戲, 萬聖節也有踩街活動, 校外教學好像是去BabyBoss

巨堡
巷弄內的學校, 也重視英語學習, 學校有很多玩具與圖書, 隔壁有很大的空間可以玩遊戲, 但夏天蚊子有點多

佳美
知名的學校, 孩子很開心上課, 走傳統健康路線重視角落學習

新佳美
顧名思義是新的佳美分校, 內容與佳美接近

巧可麗
接近四號公園的幼兒園, 接近馬路所以也是全室內空間, 但由於旁邊就是四號公園, 學校會充分利用這個優勢多帶孩子去公園活動, 教學也是滿嚴謹認真的, 會有家庭作業, 數學注音與英語都會教學, 需要爸媽回家複習, 校外教學去靠近竹圍的烤肉園地

吉得堡佳樂
教室是一樓二樓的空間, 由於接近大馬路所以是全室內空間

2019/03/19

兒童幼兒洗鼻器 我家四歲女兒示範教學: 噴鼻器Physiomer Baby舒喜滿 & Neilmed鹽包手動洗鼻器

== 幼童使用心得, 非業配 ==

女兒四歲被醫生診斷有 #鼻子過敏 的狀況, 可能是環境濕度或是不名過敏原造成, 一開始以為是感冒, 但持續不斷的流鼻水鼻涕, 我們看了許多醫生, 有一個共同的結論- — 勤勞地洗鼻子能夠清潔改善鼻腔, 加速康復—

一開始, 吸鼻器:
我們小孩無法接受洗鼻子, 所以透過吸鼻器, 將鼻涕抽出來, 但效果有限, 太深的鼻涕無法吸出, 另一方面過強的診所吸鼻儀器會破壞鼻腔黏摸, 長久下來會導致流鼻血傷口擴大

第二階段, #按壓式噴鼻器 :
媽咪上網與看書作功課, 選擇 #舒喜滿Physiomer Baby噴鼻器 , 按壓式會噴出洗鼻液, 難度中等, 幼童使用上可以循序漸進搭配

第三階段, #洗鼻器 :
本來媽咪想買電動洗鼻器, 但是擔心小孩如果無法接受, 完全不用會很浪費, 上網作功課後找到了一款好用的手動洗鼻器 #Neilmed鹽包洗鼻器 , 它沒有細細的管子, 也不容易有菌!

2019/03/13

義大利旅行- 龐貝古城 老丁解說大集合#商店餐廳#妓院#二戰修復歷史 以中文講 解 超神奇!

老丁是個義大利人,卻說得一口好中文, 很難想像一個拉丁語系的人可以將複雜的中文講得這麼好,雖然口音方面仍然腔調很重, 但是聽習慣後覺得很有趣

可能本身老丁就是一個有熱情又風趣的人, 因為過程中老丁會說許多台語的文字, 非常讓人會心一笑, 像是”貓仔間”,”站壁”..等等, 而且我們團員有提到台語”鬆一下”表示聲色場所, 老丁竟然很認真的想學起來, 讓我覺得他真的很努力且有熱忱於此, 因為下一次代台灣團他就可以逗大家笑

我剪輯了影片分享給大家 (推薦)
#行前介紹
#商家介紹
#住宅與商家介紹
#古城介紹

2018/11/29

推薦線上工具cleverpdf - 幫PDF檔案加上浮水印watermark

會推薦這個線上PDF加浮水印的工具網站, 是因為我比較過可以線上加圖的大部分網站, 但是效果都不好, 顏色太深或是透明度太差, 只有cleverpdf比較剛好, 不會把原本的文字蓋過去太多, 仍然可以看見內容!

網址:
https://www.cleverpdf.com/zh-tw/add-watermark-pdf

效果如下:

2018/11/21

[教學] 水餃的煮法 SOP步驟,水餃要好吃要讓他有足夠的空間滾!

冷凍水餃煮法:

  1. 先準備夠大的鍋子, 這樣水餃等一下才有空間滾動
  2. 將水煮滾後, 先讓用湯匙劃圓方式攪動水, 再依序放入水餃
  3. 持續輕輕攪拌, 防止黏鍋, 蓋鍋蓋, 等第二次水滾, 水餃浮起
  4. 轉中小火繼續滾, 開始計時7分鐘, 中途不再加冷水
  5. 等7分鐘到了, 美味水餃撈起來再關火


(引用自坤伯水餃)

重點 Q&A:

  • 建議不要冷水時就投入水餃, 因為冷水要再到達沸點時, 水餃泡在裡面太久, 皮容易吸太多水就會容易破。
  • 水餃煮的時候要不需要先退冰
  • 水餃要好吃,要讓他有足夠的空間滾,在水中滾動,這樣每顆才會受熱均勻,並且都把湯汁和美味快速鎖在水餃裡面。