1 {-# LANGUAGE ScopedTypeVariables #-}
2 {-# LANGUAGE TypeFamilies #-}
3 module Rehi.Win32bits where
5 import Data.Bits (Bits, toIntegralSized)
6 import Data.Int (Int32)
7 import Data.Proxy (Proxy)
8 import Data.Typeable (Typeable, typeRep)
9 import Data.Word (Word32)
10 import Foreign.Ptr (Ptr(), nullPtr)
11 import Foreign.Marshal.Alloc (allocaBytesAligned, alloca)
12 import Foreign.Storable (Storable(alignment, peek, peekByteOff, poke, pokeByteOff, sizeOf))
13 import Numeric (showHex)
15 import qualified System.Win32.Types as WT
21 #if defined(i386_HOST_ARCH)
22 #let WINDOWS_CCONV = "stdcall"
23 #elif defined(x86_64_HOST_ARCH)
24 #let WINDOWS_CCONV = "ccall"
26 # error Unknown mingw32 arch
29 #def typedef struct __PUBLIC_OBJECT_TYPE_INFORMATION {
30 UNICODE_STRING TypeName;
32 } PUBLIC_OBJECT_TYPE_INFORMATION;
35 ObjectNameInformation = 1,
36 } OBJECT_INFORMATION_CLASS;
38 #def NTSTATUS NtQueryObject(
40 OBJECT_INFORMATION_CLASS ObjectInformationClass,
41 *PUBLIC_OBJECT_TYPE_INFORMATION ObjectInformation,
42 ULONG ObjectInformationLength,
46 -- https://stackoverflow.com/a/8354582/2303202
47 -- https://wiki.haskell.org/FFICookBook#Working_with_structs
48 #if __GLASGOW_HASKELL__ < 800
49 #let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)
52 data NT_OBJECT_NAME_INFORMATION = NT_OBJECT_NAME_INFORMATION
53 { noniLength :: WT.USHORT
54 , noniMaximumLength :: WT.USHORT
55 , noniBuffer :: WT.LPWSTR }
57 instance Storable NT_OBJECT_NAME_INFORMATION where
58 sizeOf = const #{size PUBLIC_OBJECT_TYPE_INFORMATION}
59 alignment = const #{alignment PUBLIC_OBJECT_TYPE_INFORMATION}
60 peek p = NT_OBJECT_NAME_INFORMATION
61 <$> #{peek UNICODE_STRING, Length} p
62 <*> #{peek UNICODE_STRING, MaximumLength} p
63 <*> #{peek UNICODE_STRING, Buffer} p
65 #{poke UNICODE_STRING, Length} p (noniLength o)
66 #{poke UNICODE_STRING, MaximumLength} p (noniMaximumLength o)
67 #{poke UNICODE_STRING, Buffer} p (noniBuffer o)
69 type ObjectInformationClass = #{type OBJECT_INFORMATION_CLASS}
71 #enum ObjectInformationClass, , hs_ObjectNameInformation = ObjectNameInformation
73 type family Unsigned t :: *
74 type instance Unsigned Int32 = Word32
76 type NTSTATUS = Unsigned #{type NTSTATUS}
80 foreign import #{WINDOWS_CCONV} "NtQueryObject"
81 c_NtQueryObject :: WT.HANDLE
82 -> ObjectInformationClass
83 -> Ptr NT_OBJECT_NAME_INFORMATION
88 toIntegralSizedM :: forall a b . (Bits a, Integral a, Show a, Bits b, Integral b, Typeable b) => a -> IO b
89 toIntegralSizedM v = case toIntegralSized v of
91 Nothing -> fail ("Cannot cast from " ++ show v ++ " to " ++ show (typeRep (undefined :: Proxy b)))
93 getFileNameInformation :: WT.HANDLE -> IO String
94 getFileNameInformation h =
95 alloca $ \ (p_len :: Ptr ULONG) -> do
97 (== 0xC0000004) -- STATUS_INFO_LENGTH_MISMATCH
98 $ c_NtQueryObject h hs_ObjectNameInformation nullPtr 0 p_len
100 len_signed <- toIntegralSizedM len
103 (alignment (undefined :: NT_OBJECT_NAME_INFORMATION))
106 (\s -> s >= 0 && s <= 0x7FFFFFFF) -- https://msdn.microsoft.com/en-us/library/windows/hardware/ff565436.aspx
107 $ c_NtQueryObject h hs_ObjectNameInformation p_oni len p_len
110 oni_length <- toIntegralSizedM (noniLength oni `div` 2)
111 WT.peekTStringLen (noniBuffer oni, oni_length)
113 checkNtStatus :: (NTSTATUS -> Bool) -> IO NTSTATUS -> IO ()
114 checkNtStatus p f = do
118 else fail ("NtQueryObject(ObjectNameInformation) failed: " ++ showHex s "")