--- /dev/null
- dll\directx\bdaplgin\bdaplgin.ax 1
+; Main ReactOS package
+
+.Set DiskLabelTemplate="ReactOS" ; Label of disk
+.Set CabinetNameTemplate="reactos.cab" ; reactos.cab
+.Set InfFileName="reactos.inf" ; reactos.inf
+
+
+;.Set Cabinet=on
+;.Set Compress=on
+
+.InfBegin
+[Version]
+Signature = "$ReactOS$"
+
+[Directories]
+1 = system32
+2 = system32\drivers
+3 = Fonts
+4 =
+5 = system32\drivers\etc
+6 = inf
+7 = bin
+8 = media
+
+.InfEnd
+
+; Contents of disk
+.InfBegin
+[SourceFiles]
+.InfEnd
+
+
+; Base files
+base\applications\cacls\cacls.exe 1
+base\applications\calc\calc.exe 1
+base\applications\charmap\charmap.exe 1
+base\applications\cmdutils\dbgprint\dbgprint.exe 1
+base\applications\cmdutils\doskey\doskey.exe 1
+base\applications\cmdutils\find\find.exe 1
+base\applications\cmdutils\hostname\hostname.exe 1
+base\applications\cmdutils\lodctr\lodctr.exe 1
+base\applications\cmdutils\more\more.exe 1
+base\applications\cmdutils\reg\reg.exe 1
+base\applications\cmdutils\xcopy\xcopy.exe 1
+base\applications\control\control.exe 1
+base\applications\dxdiag\dxdiag.exe 1
+base\applications\fontview\fontview.exe 1
+base\applications\mscutils\devmgmt\devmgmt.exe 1
+base\applications\mscutils\eventvwr\eventvwr.exe 1
+base\applications\games\solitaire\sol.exe 1
+base\applications\games\spider\spider.exe 1
+base\applications\games\winemine\winemine.exe 1
+base\applications\hh\hh.exe 4
+base\applications\kbswitch\kbswitch.exe 1
+base\applications\kbswitch\kbsdll\kbsdll.dll 1
+base\applications\logoff\logoff.exe 1
+base\applications\magnify\magnify.exe 1
+base\applications\mplay32\mplay32.exe 1
+base\applications\msconfig\msconfig.exe 1
+base\applications\mstsc\mstsc.exe 1
+base\applications\network\arp\arp.exe 1
+base\applications\network\dwnl\dwnl.exe 1
+base\applications\network\route\route.exe 1
+base\applications\network\finger\finger.exe 1
+base\applications\network\ftp\ftp.exe 1
+base\applications\network\ipconfig\ipconfig.exe 1
+base\applications\network\netstat\netstat.exe 1
+base\applications\network\nslookup\nslookup.exe 1
+base\applications\network\ping\ping.exe 1
+base\applications\network\telnet\telnet.exe 1
+base\applications\network\tracert\tracert.exe 1
+base\applications\network\whois\whois.exe 1
+base\applications\notepad\notepad.exe 1
+base\applications\paint\paint.exe 1
+base\applications\rapps\rapps.exe 1
+base\applications\regedit\regedit.exe 4
+base\applications\regedit\clb\clb.dll 1
+base\applications\regedt32\regedt32.exe 1
+base\applications\sc\sc.exe 1
+base\applications\screensavers\3dtext\3dtext.scr 1
+base\applications\screensavers\logon\logon.scr 1
+base\applications\mscutils\servman\servman.exe 1
+base\applications\shutdown\shutdown.exe 1
+base\applications\sndrec32\sndrec32.exe 1
+base\applications\sndvol32\sndvol32.exe 1
+base\applications\taskmgr\taskmgr.exe 1
+base\applications\winhlp32\winhlp32.exe 4
+base\applications\winver\winver.exe 1
+base\applications\wordpad\wordpad.exe 1
+base\applications\write\write.exe 1
+
+base\services\audiosrv\audiosrv.exe 1
+base\services\eventlog\eventlog.exe 1
+base\services\rpcss\rpcss.exe 1
+base\services\spoolsv\spoolsv.exe 1
+base\services\tcpsvcs\tcpsvcs.exe 1
+base\services\telnetd\telnetd.exe 1
+base\services\tcpsvcs\quotes 5
+base\services\umpnpmgr\umpnpmgr.exe 1
+base\services\wlansvc\wlansvc.exe 1
+base\services\svchost\svchost.exe 1
+
+base\setup\setup\setup.exe 1
+base\setup\vmwinst\vmwinst.exe 1
+
+base\shell\cmd\cmd.exe 1
+base\shell\explorer\explorer.exe 4
+base\shell\explorer\explorer-cfg-template.xml 4
+base\shell\explorer\notifyhook\notifyhook.dll 1
+base\shell\explorer-new\explorer_new.exe 4 optional
+
+base\system\autochk\autochk.exe 1
+base\system\bootok\bootok.exe 1
+base\system\format\format.exe 1
+base\system\lsass\lsass.exe 1
+base\system\msiexec\msiexec.exe 1
+base\system\regsvr32\regsvr32.exe 1
+base\system\rundll32\rundll32.exe 1
+base\system\runonce\runonce.exe 1
+base\system\services\services.exe 1
+base\system\userinit\userinit.exe 1
+base\system\winlogon\winlogon.exe 1
+base\system\expand\expand.exe 1
+base\system\smss\smss.exe 1
+
+
+; Dynamic Link Libraries
+dll\3rdparty\mesa32\mesa32.dll 1
+dll\3rdparty\libjpeg\libjpeg.dll 1
+dll\3rdparty\libxslt\libxslt.dll 1
+dll\3rdparty\dxtn\dxtn.dll 1 optional
+
+dll\cpl\access\access.cpl 1
+dll\cpl\appwiz\appwiz.cpl 1
+dll\cpl\console\console.dll 1
+dll\cpl\desk\desk.cpl 1
+dll\cpl\hdwwiz\hdwwiz.cpl 1
+dll\cpl\input\input.dll 1
+dll\cpl\intl\intl.cpl 1
+dll\cpl\joy\joy.cpl 1
+;dll\cpl\liccpa\liccpa.cpl 1
+dll\cpl\main\main.cpl 1
+dll\cpl\mmsys\mmsys.cpl 1
+dll\cpl\ncpa\ncpa.cpl 1
+;dll\cpl\odbccp32\odbccp32.cpl 1
+dll\cpl\powercfg\powercfg.cpl 1
+dll\cpl\sysdm\sysdm.cpl 1
+;dll\cpl\telephon\telephon.cpl 1
+dll\cpl\timedate\timedate.cpl 1
+;dll\cpl\usrmgr\usrmgr.cpl 1
+
+dll\directx\amstream\amstream.dll 1
- dll\directx\msdvbnp\msdvbnp.ax 1
- dll\directx\msvidctl\msvidctl.dll 1
++;dll\directx\bdaplgin\bdaplgin.ax 1
+dll\directx\dinput\dinput.dll 1
+dll\directx\dinput8\dinput8.dll 1
+dll\directx\dmusic\dmusic.dll 1
+dll\directx\dplay\dplay.dll 1
+dll\directx\dplayx\dplayx.dll 1
+dll\directx\dsound\dsound.dll 1
+dll\directx\dxdiagn\dxdiagn.dll 1
+dll\directx\wine\ddraw\ddraw.dll 1
+dll\directx\d3d8thk\d3d8thk.dll 1
+dll\directx\devenum\devenum.dll 1
+dll\directx\ksproxy\ksproxy.ax 1
+dll\directx\ksuser\ksuser.dll 1
+dll\directx\msdmo\msdmo.dll 1
- drivers\multimedia\bdasup\bdasup.sys 2
++;dll\directx\msdvbnp\msdvbnp.ax 1
++;dll\directx\msvidctl\msvidctl.dll 1
+dll\directx\quartz\quartz.dll 1
+dll\directx\qedit\qedit.dll 1
+dll\directx\wine\d3d8\d3d8.dll 1
+dll\directx\wine\wined3d\wined3d.dll 1
+dll\directx\wine\d3d9\d3d9.dll 1
+
+dll\keyboard\kbda1\kbda1.dll 1
+dll\keyboard\kbda2\kbda2.dll 1
+dll\keyboard\kbda3\kbda3.dll 1
+dll\keyboard\kbdal\kbdal.dll 1
+dll\keyboard\kbdarme\kbdarme.dll 1
+dll\keyboard\kbdarmw\kbdarmw.dll 1
+dll\keyboard\kbdaze\kbdaze.dll 1
+dll\keyboard\kbdazel\kbdazel.dll 1
+dll\keyboard\kbdbgm\kbdbgm.dll 1
+dll\keyboard\kbdbgt\kbdbgt.dll 1
+dll\keyboard\kbdblr\kbdblr.dll 1
+dll\keyboard\kbdbr\kbdbr.dll 1
+dll\keyboard\kbdbga\kbdbga.dll 1
+dll\keyboard\kbdbe\kbdbe.dll 1
+dll\keyboard\kbdbur\kbdbur.dll 1
+dll\keyboard\kbdcan\kbdcan.dll 1
+dll\keyboard\kbdcr\kbdcr.dll 1
+dll\keyboard\kbdcz\kbdcz.dll 1
+dll\keyboard\kbdcz1\kbdcz1.dll 1
+dll\keyboard\kbdda\kbdda.dll 1
+dll\keyboard\kbddv\kbddv.dll 1
+dll\keyboard\kbdes\kbdes.dll 1
+dll\keyboard\kbdest\kbdest.dll 1
+dll\keyboard\kbdfc\kbdfc.dll 1
+dll\keyboard\kbdfi\kbdfi.dll 1
+dll\keyboard\kbdfr\kbdfr.dll 1
+dll\keyboard\kbdgeo\kbdgeo.dll 1
+dll\keyboard\kbdgerg\kbdgerg.dll 1
+dll\keyboard\kbdgneo\kbdgneo.dll 1
+dll\keyboard\kbdgrist\kbdgrist.dll 1
+dll\keyboard\kbdgr\kbdgr.dll 1
+dll\keyboard\kbdhe\kbdhe.dll 1
+dll\keyboard\kbdheb\kbdheb.dll 1
+dll\keyboard\kbdhu\kbdhu.dll 1
+dll\keyboard\kbdic\kbdic.dll 1
+dll\keyboard\kbdinasa\kbdinasa.dll 1
+dll\keyboard\kbdinben\kbdinben.dll 1
+dll\keyboard\kbdindev\kbdindev.dll 1
+dll\keyboard\kbdinguj\kbdinguj.dll 1
+dll\keyboard\kbdinmal\kbdinmal.dll 1
+dll\keyboard\kbdir\kbdir.dll 1
+dll\keyboard\kbdit\kbdit.dll 1
+dll\keyboard\kbdja\kbdja.dll 1
+dll\keyboard\kbdkaz\kbdkaz.dll 1
+dll\keyboard\kbdla\kbdla.dll 1
+dll\keyboard\kbdlt1\kbdlt1.dll 1
+dll\keyboard\kbdlv\kbdlv.dll 1
+dll\keyboard\kbdmac\kbdmac.dll 1
+dll\keyboard\kbdne\kbdne.dll 1
+dll\keyboard\kbdno\kbdno.dll 1
+dll\keyboard\kbdpl1\kbdpl1.dll 1
+dll\keyboard\kbdpo\kbdpo.dll 1
+dll\keyboard\kbdro\kbdro.dll 1
+dll\keyboard\kbdru\kbdru.dll 1
+dll\keyboard\kbdru1\kbdru1.dll 1
+dll\keyboard\kbdsg\kbdsg.dll 1
+dll\keyboard\kbdsk\kbdsk.dll 1
+dll\keyboard\kbdsk1\kbdsk1.dll 1
+dll\keyboard\kbdsw\kbdsw.dll 1
+dll\keyboard\kbdtat\kbdtat.dll 1
+dll\keyboard\kbdth0\kbdth0.dll 1
+dll\keyboard\kbdth1\kbdth1.dll 1
+dll\keyboard\kbdth2\kbdth2.dll 1
+dll\keyboard\kbdth3\kbdth3.dll 1
+dll\keyboard\kbdtuf\kbdtuf.dll 1
+dll\keyboard\kbdtuq\kbdtuq.dll 1
+dll\keyboard\kbduk\kbduk.dll 1
+dll\keyboard\kbdur\kbdur.dll 1
+dll\keyboard\kbdurs\kbdurs.dll 1
+dll\keyboard\kbdus\kbdus.dll 1
+dll\keyboard\kbdusa\kbdusa.dll 1
+dll\keyboard\kbdusl\kbdusl.dll 1
+dll\keyboard\kbdusr\kbdusr.dll 1
+dll\keyboard\kbdusx\kbdusx.dll 1
+dll\keyboard\kbduzb\kbduzb.dll 1
+dll\keyboard\kbdvntc\kbdvntc.dll 1
+dll\keyboard\kbdycc\kbdycc.dll 1
+dll\keyboard\kbdycl\kbdycl.dll 1
+dll\keyboard\kbdko\kbdko.dll 1
+
+dll\ntdll\ntdll.dll 1
+
+dll\win32\acledit\acledit.dll 1
+dll\win32\aclui\aclui.dll 1
+dll\win32\activeds\activeds.dll 1
+dll\win32\advapi32\advapi32.dll 1
+dll\win32\advpack\advpack.dll 1
+dll\win32\actxprxy\actxprxy.dll 1
+dll\win32\atl\atl.dll 1
+dll\win32\authz\authz.dll 1
+dll\win32\avicap32\avicap32.dll 1
+dll\win32\avifil32\avifil32.dll 1
+dll\win32\batt\batt.dll 1
+dll\win32\bcrypt\bcrypt.dll 1
+dll\win32\beepmidi\beepmidi.dll 1
+dll\win32\browseui\browseui.dll 1
+dll\win32\cabinet\cabinet.dll 1
+dll\win32\cards\cards.dll 1
+dll\win32\cfgmgr32\cfgmgr32.dll 1
+dll\win32\clusapi\clusapi.dll 1
+dll\win32\comcat\comcat.dll 1
+dll\win32\comctl32\comctl32.dll 1
+dll\win32\comdlg32\comdlg32.dll 1
+dll\win32\compstui\compstui.dll 1
+dll\win32\credui\credui.dll 1
+dll\win32\crtdll\crtdll.dll 1
+dll\win32\crypt32\crypt32.dll 1
+dll\win32\cryptdlg\cryptdlg.dll 1
+dll\win32\cryptdll\cryptdll.dll 1
+dll\win32\cryptnet\cryptnet.dll 1
+dll\win32\cryptui\cryptui.dll 1
+dll\win32\dbghelp\dbghelp.dll 1
+dll\win32\dciman32\dciman32.dll 1
+dll\win32\dwmapi\dwmapi.dll 1
+dll\win32\devmgr\devmgr.dll 1
+dll\win32\dhcpcsvc\dhcpcsvc.dll 1
+dll\win32\dnsapi\dnsapi.dll 1
+dll\win32\faultrep\faultrep.dll 1
+dll\win32\fmifs\fmifs.dll 1
+dll\win32\fusion\fusion.dll 1
+dll\win32\gdi32\gdi32.dll 1
+dll\win32\gdiplus\gdiplus.dll 1
+dll\win32\getuname\getuname.dll 1
+dll\win32\glu32\glu32.dll 1
+dll\win32\hhctrl.ocx\hhctrl.ocx 1
+dll\win32\hid\hid.dll 1
+dll\win32\hlink\hlink.dll 1
+dll\win32\hnetcfg\hnetcfg.dll 1
+dll\win32\httpapi\httpapi.dll 1
+dll\win32\iccvid\iccvid.dll 1
+dll\win32\icmp\icmp.dll 1
+dll\win32\imaadp32.acm\imaadp32.acm 1
+dll\win32\imagehlp\imagehlp.dll 1
+dll\win32\imm32\imm32.dll 1
+dll\win32\inetcomm\inetcomm.dll 1
+dll\win32\inetmib1\inetmib1.dll 1
+dll\win32\initpki\initpki.dll 1
+dll\win32\inseng\inseng.dll 1
+dll\win32\iphlpapi\iphlpapi.dll 1
+dll\win32\itircl\itircl.dll 1
+dll\win32\itss\itss.dll 1
+dll\win32\jscript\jscript.dll 1
+dll\win32\kernel32\kernel32.dll 1
+dll\win32\loadperf\loadperf.dll 1
+dll\win32\localspl\localspl.dll 1
+dll\win32\localui\localui.dll 1
+dll\win32\lsasrv\lsasrv.dll 1
+dll\win32\lz32\lz32.dll 1
+dll\win32\mapi32\mapi32.dll 1
+dll\win32\mciavi32\mciavi32.dll 1
+dll\win32\mcicda\mcicda.dll 1
+dll\win32\mciqtz32\mciqtz32.dll 1
+dll\win32\mciseq\mciseq.dll 1
+dll\win32\mciwave\mciwave.dll 1
+dll\win32\mlang\mlang.dll 1
+dll\win32\mmdrv\mmdrv.dll 1
+dll\win32\modemui\modemui.dll 1
+dll\win32\mpr\mpr.dll 1
+dll\win32\mprapi\mprapi.dll 1
+dll\win32\msacm32\msacm32.dll 1
+dll\win32\msacm32\msacm32.drv\msacm32.drv 1
+dll\win32\msadp32.acm\msadp32.acm 1
+dll\win32\msafd\msafd.dll 1
+dll\win32\mscat32\mscat32.dll 1
+dll\win32\mscms\mscms.dll 1
+dll\win32\mscoree\mscoree.dll 1
+dll\win32\msctf\msctf.dll 1
+dll\win32\msftedit\msftedit.dll 1
+dll\win32\msg711.acm\msg711.acm 1
+dll\win32\msgina\msgina.dll 1
+dll\win32\msgsm32.acm\msgsm32.acm 1
+dll\win32\mshtml\mshtml.dll 1
+dll\win32\mshtml.tlb\mshtml.tlb 1
+dll\win32\msi\msi.dll 1
+dll\win32\msimg32\msimg32.dll 1
+dll\win32\msimtf\msimtf.dll 1
+dll\win32\msisip\msisip.dll 1
+dll\win32\msisys.ocx\msisys.ocx 1
+dll\win32\msnet32\msnet32.dll 1
+dll\win32\msrle32\msrle32.dll 1
+dll\win32\mssign32\mssign32.dll 1
+dll\win32\mssip32\mssip32.dll 1
+dll\win32\mstask\mstask.dll 1
+dll\win32\msvcrt\msvcrt.dll 1
+dll\win32\msvcrt20\msvcrt20.dll 1
+dll\win32\msvcrt40\msvcrt40.dll 1
+dll\win32\msvfw32\msvfw32.dll 1
+dll\win32\msvidc32\msvidc32.dll 1
+dll\win32\mswsock\mswsock.dll 1
+dll\win32\msxml3\msxml3.dll 1
+dll\win32\nddeapi\nddeapi.dll 1
+dll\win32\netapi32\netapi32.dll 1
+dll\win32\netcfgx\netcfgx.dll 1
+dll\win32\netid\netid.dll 1
+dll\win32\netshell\netshell.dll 1
+dll\win32\newdev\newdev.dll 1
+dll\win32\ntdsapi\ntdsapi.dll 1
+dll\win32\ntlanman\ntlanman.dll 1
+dll\win32\ntmarta\ntmarta.dll 1
+dll\win32\ntprint\ntprint.dll 1
+dll\win32\objsel\objsel.dll 1
+dll\win32\odbc32\odbc32.dll 1
+dll\win32\odbccp32\odbccp32.dll 1
+dll\win32\ole32\ole32.dll 1
+dll\win32\oleacc\oleacc.dll 1
+dll\win32\oleaut32\oleaut32.dll 1
+dll\win32\olecli32\olecli32.dll 1
+dll\win32\oledlg\oledlg.dll 1
+dll\win32\olepro32\olepro32.dll 1
+dll\win32\olesvr32\olesvr32.dll 1
+dll\win32\olethk32\olethk32.dll 1
+dll\win32\opengl32\opengl32.dll 1
+dll\win32\pdh\pdh.dll 1
+dll\win32\pidgen\pidgen.dll 1
+dll\win32\powrprof\powrprof.dll 1
+dll\win32\printui\printui.dll 1
+dll\win32\psapi\psapi.dll 1
+dll\win32\pstorec\pstorec.dll 1
+dll\win32\qmgr\qmgr.dll 1
+dll\win32\qmgrprxy\qmgrprxy.dll 1
+dll\win32\query\query.dll 1
+dll\win32\rasadhlp\rasadhlp.dll 1
+dll\win32\rasapi32\rasapi32.dll 1
+dll\win32\rasdlg\rasdlg.dll 1
+dll\win32\resutils\resutils.dll 1
+dll\win32\rasman\rasman.dll 1
+dll\win32\riched20\riched20.dll 1
+dll\win32\riched32\riched32.dll 1
+dll\win32\rpcrt4\rpcrt4.dll 1
+dll\win32\rsabase\rsabase.dll 1
+dll\win32\rsaenh\rsaenh.dll 1
+dll\win32\samlib\samlib.dll 1
+dll\win32\samsrv\samsrv.dll 1
+dll\win32\sccbase\sccbase.dll 1
+dll\win32\schannel\schannel.dll 1
+dll\win32\secur32\secur32.dll 1
+dll\win32\security\security.dll 1
+dll\win32\sensapi\sensapi.dll 1
+dll\win32\serialui\serialui.dll 1
+dll\win32\setupapi\setupapi.dll 1
+dll\win32\sfc\sfc.dll 1
+dll\win32\sfc_os\sfc_os.dll 1
+dll\win32\shdoclc\shdoclc.dll 1
+dll\win32\shdocvw\shdocvw.dll 1
+dll\win32\shell32\shell32.dll 1
+dll\win32\shfolder\shfolder.dll 1
+dll\win32\shimgvw\shimgvw.dll 1
+dll\win32\shlwapi\shlwapi.dll 1
+dll\win32\slbcsp\slbcsp.dll 1
+dll\win32\smdll\smdll.dll 1
+dll\win32\snmpapi\snmpapi.dll 1
+dll\win32\softpub\softpub.dll 1
+dll\win32\spoolss\spoolss.dll 1
+dll\win32\srclient\srclient.dll 1
+dll\win32\stdole2.tlb\stdole2.tlb 1
+dll\win32\stdole32.tlb\stdole32.tlb 1
+dll\win32\sti\sti.dll 1
+dll\win32\sxs\sxs.dll 1
+dll\win32\syssetup\syssetup.dll 1
+dll\win32\t2embed\t2embed.dll 1
+dll\win32\tapi32\tapi32.dll 1
+dll\win32\tapiui\tapiui.dll 1
+dll\win32\traffic\traffic.dll 1
+dll\win32\twain_32\twain_32.dll 1
+dll\win32\uext2\uext2.dll 1
+dll\win32\ufat\ufat.dll 1
+dll\win32\ufatx\ufatx.dll 1 optional
+dll\win32\untfs\untfs.dll 1
+dll\win32\updspapi\updspapi.dll 1
+dll\win32\url\url.dll 1
+dll\win32\urlmon\urlmon.dll 1
+dll\win32\user32\user32.dll 1
+dll\win32\userenv\userenv.dll 1
+dll\win32\usp10\usp10.dll 1
+dll\win32\uxtheme\uxtheme.dll 1
+dll\win32\vdmdbg\vdmdbg.dll 1
+dll\win32\version\version.dll 1
+dll\win32\windowscodecs\windowscodecs.dll 1
+dll\win32\winemp3.acm\winemp3.acm 1
+dll\win32\winfax\winfax.dll 1
+dll\win32\winhttp\winhttp.dll 1
+dll\win32\wininet\wininet.dll 1
+dll\win32\winmm\winmm.dll 1
+dll\win32\winspool\winspool.drv 1
+dll\win32\winsta\winsta.dll 1
+dll\win32\wlanapi\wlanapi.dll 1
+dll\win32\wintrust\wintrust.dll 1
+dll\win32\wldap32\wldap32.dll 1
+dll\win32\wmi\wmi.dll 1
+dll\win32\ws2_32\ws2_32.dll 1
+dll\win32\ws2help\ws2help.dll 1
+dll\win32\wshirda\wshirda.dll 1
+dll\win32\wshtcpip\wshtcpip.dll 1
+dll\win32\wsock32\wsock32.dll 1
+dll\win32\wtsapi32\wtsapi32.dll 1
+dll\win32\wuapi\wuapi.dll 1
+dll\win32\xinput1_1\xinput1_1.dll 1
+dll\win32\xinput1_2\xinput1_2.dll 1
+dll\win32\xinput1_3\xinput1_3.dll 1
+dll\win32\xinput9_1_0\xinput9_1_0.dll 1
+dll\win32\xmllite\xmllite.dll 1
+dll\win32\winmm\midimap\midimap.dll 1
+dll\win32\wdmaud.drv\wdmaud.drv 1
+
+; Shell Extensions
+dll\shellext\deskadp\deskadp.dll 1
+dll\shellext\deskmon\deskmon.dll 1
+
+; Drivers
+drivers\base\bootvid\bootvid.dll 1
+drivers\base\beep\beep.sys 2
+drivers\base\null\null.sys 2
+drivers\base\nmidebug\nmidebug.sys 2
+
+drivers\battery\battc\battc.sys 2
+
+drivers\bus\acpi\cmbatt\cmbatt.sys 2
+drivers\bus\acpi\compbatt\compbatt.sys 2
+
+drivers\directx\dxapi\dxapi.sys 2
+drivers\directx\dxg\dxg.sys 2
+drivers\directx\dxgthk\dxgthk.sys 2
+
+drivers\filesystems\fs_rec\fs_rec.sys 2
+drivers\filesystems\msfs\msfs.sys 2
+drivers\filesystems\mup\mup.sys 2
+drivers\filesystems\npfs\npfs.sys 2
+
+drivers\input\mouclass\mouclass.sys 2
+drivers\input\sermouse\sermouse.sys 2
+
+drivers\ksfilter\ks\ks.sys 2
++;drivers\multimedia\bdasup\bdasup.sys 2
+
+drivers\network\afd\afd.sys 2
+drivers\network\ndis\ndis.sys 2
+drivers\network\tcpip\tcpip.sys 2
+drivers\network\tdi\tdi.sys 2
+drivers\network\dd\ne2000\ne2000.sys 2
+drivers\network\dd\pcnet\pcnet.sys 2
+
+drivers\serial\serenum\serenum.sys 2
+drivers\serial\serial\serial.sys 2
+
+drivers\storage\ide\pciide\pciide.sys 2
+drivers\storage\ide\pciidex\pciidex.sys 2
+
+;drivers\usb\miniport\usbohci\usbohci.sys 2
+;drivers\usb\miniport\usbuhci\usbuhci.sys 2
+;drivers\usb\usbhub\usbhub.sys 2
+;drivers\usb\usbport\usbport.sys 2
+drivers\usb\nt4compat\usbdriver\usbdriver.sys 2
+
+drivers\video\displays\vga\vgaddi.dll 1
+drivers\video\displays\framebuf\framebuf.dll 1
+drivers\video\miniport\vga\vgamp.sys 2
+drivers\video\miniport\vbe\vbemp.sys 2
+drivers\video\videoprt\videoprt.sys 2
+drivers\video\font\ftfd\ftfd.dll 1
+
+drivers\wdm\audio\filters\kmixer\kmixer.sys 2
+drivers\wdm\audio\sysaudio\sysaudio.sys 2
+drivers\wdm\audio\legacy\wdmaud\wdmaud.sys 2
+drivers\wdm\audio\backpln\portcls\portcls.sys 2
+drivers\wdm\audio\drm\drmk\drmk.sys 2
+drivers\wmi\wmilib.sys 2
+
+; Media
+media\fonts\DejaVuSans.ttf 3
+media\fonts\DejaVuSans-Bold.ttf 3
+media\fonts\DejaVuSans-BoldOblique.ttf 3
+media\fonts\DejaVuSansMono.ttf 3
+media\fonts\DejaVuSansMono-Bold.ttf 3
+media\fonts\DejaVuSansMono-BoldOblique.ttf 3
+media\fonts\DejaVuSansMono-Oblique.ttf 3
+media\fonts\DejaVuSans-Oblique.ttf 3
+media\fonts\DejaVuSerif.ttf 3
+media\fonts\DejaVuSerif-Bold.ttf 3
+media\fonts\DejaVuSerif-BoldItalic.ttf 3
+media\fonts\DejaVuSerif-Italic.ttf 3
+
+media\fonts\FreeMono.ttf 3
+media\fonts\FreeMonoBold.ttf 3
+media\fonts\FreeMonoBoldOblique.ttf 3
+media\fonts\FreeMonoOblique.ttf 3
+
+media\fonts\LiberationMono-Bold.ttf 3
+media\fonts\LiberationMono-BoldItalic.ttf 3
+media\fonts\LiberationMono-Italic.ttf 3
+media\fonts\LiberationMono-Regular.ttf 3
+media\fonts\LiberationSans-Bold.ttf 3
+media\fonts\LiberationSans-BoldItalic.ttf 3
+media\fonts\LiberationSans-Italic.ttf 3
+media\fonts\LiberationSans-Regular.ttf 3
+media\fonts\LiberationSerif-Bold.ttf 3
+media\fonts\LiberationSerif-BoldItalic.ttf 3
+media\fonts\LiberationSerif-Italic.ttf 3
+media\fonts\LiberationSerif-Regular.ttf 3
+
+media\fonts\Marlett.ttf 3
+media\fonts\symbol.ttf 3
+media\fonts\tahoma.ttf 3
+media\fonts\tahomabd.ttf 3
+
+media\vgafonts\vgafonts.cab 4
+
+media\nls\c_037.nls 1
+media\nls\c_424.nls 1
+media\nls\c_500.nls 1
+media\nls\c_737.nls 1
+media\nls\c_775.nls 1
+media\nls\c_850.nls 1
+media\nls\c_852.nls 1
+media\nls\c_855.nls 1
+media\nls\c_856.nls 1
+media\nls\c_857.nls 1
+media\nls\c_860.nls 1
+media\nls\c_861.nls 1
+media\nls\c_862.nls 1
+media\nls\c_863.nls 1
+media\nls\c_864.nls 1
+media\nls\c_865.nls 1
+media\nls\c_866.nls 1
+media\nls\c_869.nls 1
+media\nls\c_874.nls 1
+media\nls\c_875.nls 1
+media\nls\c_878.nls 1
+media\nls\c_932.nls 1
+media\nls\c_936.nls 1
+media\nls\c_949.nls 1
+media\nls\c_950.nls 1
+media\nls\c_1006.nls 1
+media\nls\c_1026.nls 1
+media\nls\c_1250.nls 1
+media\nls\c_1251.nls 1
+media\nls\c_1253.nls 1
+media\nls\c_1254.nls 1
+media\nls\c_1255.nls 1
+media\nls\c_1256.nls 1
+media\nls\c_1257.nls 1
+media\nls\c_1258.nls 1
+media\nls\c_10000.nls 1
+media\nls\c_10006.nls 1
+media\nls\c_10007.nls 1
+media\nls\c_10029.nls 1
+media\nls\c_10079.nls 1
+media\nls\c_10081.nls 1
+media\nls\c_20866.nls 1
+media\nls\c_21866.nls 1
+media\nls\c_28591.nls 1
+media\nls\c_28592.nls 1
+media\nls\c_28593.nls 1
+media\nls\c_28594.nls 1
+media\nls\c_28595.nls 1
+media\nls\c_28596.nls 1
+media\nls\c_28597.nls 1
+media\nls\c_28598.nls 1
+media\nls\c_28599.nls 1
+media\nls\c_28600.nls 1
+media\nls\c_28603.nls 1
+media\nls\c_28604.nls 1
+media\nls\c_28605.nls 1
+media\nls\c_28606.nls 1
+media\drivers\etc\hosts 5
+media\drivers\etc\services 5
+media\inf\audio.inf 6
+media\inf\acpi.inf 6
+media\inf\battery.inf 6
+media\inf\cdrom.inf 6
+media\inf\cpu.inf 6
+media\inf\display.inf 6
+media\inf\font.inf 6
+media\inf\fdc.inf 6
+media\inf\hdc.inf 6
+media\inf\intl.inf 6
+media\inf\layout.inf 6
+media\inf\machine.inf 6
+media\inf\msmouse.inf 6
+media\inf\keyboard.inf 6
+media\inf\ks.inf 6
+media\inf\NET_NIC.inf 6
+media\inf\netamd.inf 6
+media\inf\netisa.inf 6
+media\inf\netrtpnt.inf 6
+media\inf\nettcpip.inf 6
+media\inf\ports.inf 6
+media\inf\scsi.inf 6
+media\inf\syssetup.inf 6
+media\inf\usbport.inf 6
+media\inf\usb.inf 6
+media\inf\usbstor.inf 6
+media\inf\xboxdisp.inf 6
+
+
+; Media Files
+media\sounds\ReactOS_LogOn.wav 8
+
+; Ini Files
+boot\bootdata\system.ini 4
+
+; Regression Testing
+boot\bootdata\bootcdregtest\regtest.cmd 7 optional
+
+; Subsystems
+subsystems\win32\csrss\csrss.exe 1
+subsystems\win32\csrss\win32csr\win32csr.dll 1
+subsystems\win32\csrss\csrsrv\csrsrv.dll 1
+subsystems\ntvdm\ntvdm.exe 1
+subsystems\win32\win32k\win32k.sys 1
+
+; Optional/proprietary files
+modules\optional\DroidSansFallback.ttf 3 optional
+modules\optional\NOTICE_for_Droid_Font.txt 4 optional
+modules\optional\netkvm2k.inf 6 optional
+modules\optional\netkvm2k.cat 6 optional
+modules\optional\netkvm.sys 2 optional
+modules\optional\alcxwdm.inf 6 optional
+modules\optional\alcxwdm.sys 2 optional
+modules\optional\mfc42.dll 1 optional
+modules\optional\mfc42u.dll 1 optional
+modules\optional\mfc71.dll 1 optional
+modules\optional\mfc71u.dll 1 optional
+modules\optional\msvbvm50.dll 1 optional
+modules\optional\msvbvm60.dll 1 optional
+modules\optional\msvcirt.dll 1 optional
+modules\optional\msvcp71.dll 1 optional
+modules\optional\msvcr71.dll 1 optional
+modules\optional\vmx_fb.dll 1 optional
+modules\optional\vmx_mode.dll 1 optional
+modules\optional\vmx_svga.inf 6 optional
+modules\optional\vmx_svga.sys 2 optional
+modules\optional\wine_gecko-1.0.0-x86.cab 4 optional
+
+; Rosapps
+modules\rosapps\applications\screensavers\cylfrac\cylfrac.scr 1 optional
+modules\rosapps\applications\screensavers\matrix\matrix.scr 1 optional
+modules\rosapps\applications\screensavers\blankscr\scrnsave.scr 1 optional
+modules\rosapps\applications\screensavers\starfield\starfield.scr 1 optional
+modules\rosapps\applications\screensavers\mazescr\mazescr.scr 1 optional
+modules\rosapps\applications\screensavers\butterflies\butterflies.scr 1 optional
+modules\rosapps\applications\cmdutils\comp\comp.exe 1 optional
+modules\rosapps\applications\cmdutils\mode\mode.exe 1 optional
+modules\rosapps\applications\cmdutils\sort\sort.exe 1 optional
+modules\rosapps\applications\cmdutils\tee\tee.exe 1 optional
+modules\rosapps\applications\cmdutils\touch\touch.exe 1 optional
+modules\rosapps\applications\cmdutils\uptime\uptime.exe 1 optional
+modules\rosapps\applications\cmdutils\y\y.exe 1 optional
+modules\rosapps\applications\devutils\gdb2\gdb2.exe 1 optional
+modules\rosapps\applications\devutils\gdihv\gdihv.exe 1 optional
+modules\rosapps\applications\devutils\genguid\genguid.exe 1 optional
+modules\rosapps\applications\sysutils\gettype\gettype.exe 1 optional
+modules\rosapps\applications\net\ncftp\ncftp.exe 1 optional
+modules\rosapps\applications\net\netreg\netreg.exe 1 optional
+modules\rosapps\applications\net\niclist\niclist.exe 1 optional
+modules\rosapps\applications\net\roshttpd\roshttpd.exe 1 optional
+modules\rosapps\applications\notevil\notevil.exe 1 optional
+modules\rosapps\applications\sysutils\chkdsk\chkdsk.exe 1 optional
+modules\rosapps\applications\sysutils\systeminfo\systeminfo.exe 1 optional
+modules\rosapps\applications\sysutils\chklib\chklib.exe 1 optional
+modules\rosapps\applications\sysutils\ctm\ctm.exe 1 optional
+modules\rosapps\applications\sysutils\kill\kill.exe 1 optional
+modules\rosapps\applications\sysutils\lsdd\lsdd.exe 1 optional
+modules\rosapps\applications\sysutils\man\man.exe 1 optional
+modules\rosapps\applications\sysutils\pedump\pedump.exe 1 optional
+modules\rosapps\applications\sysutils\regexpl\regexpl.exe 1 optional
+modules\rosapps\applications\sysutils\tcat\tcat.exe 1 optional
+modules\rosapps\applications\sysutils\tlist\tlist.exe 1 optional
+modules\rosapps\applications\sysutils\screenshot\screenshot.exe 1 optional
+modules\rosapps\applications\sysutils\utils\binpatch\binpatch.exe 1 optional
+modules\rosapps\applications\sysutils\utils\cat\cat.exe 1 optional
+modules\rosapps\applications\sysutils\utils\driver\load\load.exe 1 optional
+modules\rosapps\applications\sysutils\utils\driver\unload\unload.exe 1 optional
+modules\rosapps\applications\sysutils\utils\infinst\infinst.exe 1 optional
+modules\rosapps\applications\sysutils\utils\nts2w32err\nts2w32err.exe 1 optional
+modules\rosapps\applications\sysutils\utils\objdir\objdir.exe 1 optional
+modules\rosapps\applications\sysutils\utils\partinfo\partinfo.exe 1 optional
+modules\rosapps\applications\sysutils\utils\ps\ps.exe 1 optional
+modules\rosapps\applications\sysutils\utils\rosperf\rosperf.exe 1 optional
+modules\rosapps\applications\sysutils\utils\stats\stats.exe 1 optional
+modules\rosapps\applications\sysutils\utils\tickcount\tickcount.exe 1 optional
+modules\rosapps\applications\winfile\winfile.exe 1 optional
+modules\rosapps\demos\maze\maze.exe 1 optional
+modules\rosapps\drivers\green\green.sys 2 optional
+
+; Rostests
+modules\rostests\rosautotest\rosautotest.exe 1 optional
+modules\rostests\drivers\kmtest\kmtest.sys 2 optional
+modules\rostests\drivers\kmtest\kmtestassist.sys 2 optional
+modules\rostests\tests\pseh2\pseh2_test.exe 7 optional
+modules\rostests\winetests\advapi32\advapi32_winetest.exe 7 optional
+modules\rostests\winetests\advpack\advpack_winetest.exe 7 optional
+modules\rostests\winetests\browseui\browseui_winetest.exe 7 optional
+modules\rostests\winetests\cabinet\cabinet_winetest.exe 7 optional
+modules\rostests\winetests\comcat\comcat_winetest.exe 7 optional
+modules\rostests\winetests\comctl32\comctl32_winetest.exe 7 optional
+modules\rostests\winetests\comdlg32\comdlg32_winetest.exe 7 optional
+modules\rostests\winetests\crypt32\crypt32_winetest.exe 7 optional
+modules\rostests\winetests\cryptnet\cryptnet_winetest.exe 7 optional
+modules\rostests\winetests\dsound\dsound_winetest.exe 7 optional
+modules\rostests\winetests\gdi32\gdi32_winetest.exe 7 optional
+modules\rostests\winetests\gdiplus\gdiplus_winetest.exe 7 optional
+modules\rostests\winetests\hlink\hlink_winetest.exe 7 optional
+modules\rostests\winetests\icmp\icmp_winetest.exe 7 optional
+modules\rostests\winetests\iphlpapi\iphlpapi_winetest.exe 7 optional
+modules\rostests\winetests\jscript\jscript_winetest.exe 7 optional
+modules\rostests\winetests\kernel32\kernel32_winetest.exe 7 optional
+modules\rostests\winetests\lz32\lz32_winetest.exe 7 optional
+modules\rostests\winetests\mapi32\mapi32_winetest.exe 7 optional
+modules\rostests\winetests\mlang\mlang_winetest.exe 7 optional
+modules\rostests\winetests\mshtml\mshtml_winetest.exe 7 optional
+modules\rostests\winetests\msi\msi_winetest.exe 7 optional
+modules\rostests\winetests\mstask\mstask_winetest.exe 7 optional
+modules\rostests\winetests\msvcrt\msvcrt_winetest.exe 7 optional
+modules\rostests\winetests\msxml3\msxml3_winetest.exe 7 optional
+modules\rostests\winetests\netapi32\netapi32_winetest.exe 7 optional
+modules\rostests\winetests\ntdll\ntdll_winetest.exe 7 optional
+modules\rostests\winetests\odbccp32\odbccp32_winetest.exe 7 optional
+modules\rostests\winetests\ole32\ole32_winetest.exe 7 optional
+modules\rostests\winetests\oleaut32\oleaut32_winetest.exe 7 optional
+modules\rostests\winetests\powrprof\powrprof_winetest.exe 7 optional
+modules\rostests\winetests\psapi\psapi_winetest.exe 7 optional
+modules\rostests\winetests\riched20\riched20_winetest.exe 7 optional
+modules\rostests\winetests\rpcrt4\rpcrt4_winetest.exe 7 optional
+modules\rostests\winetests\rsabase\rsabase_winetest.exe 7 optional
+modules\rostests\winetests\rsaenh\rsaenh_winetest.exe 7 optional
+modules\rostests\winetests\schannel\schannel_winetest.exe 7 optional
+modules\rostests\winetests\secur32\secur32_winetest.exe 7 optional
+modules\rostests\winetests\setupapi\setupapi_winetest.exe 7 optional
+modules\rostests\winetests\shdocvw\shdocvw_winetest.exe 7 optional
+modules\rostests\winetests\shell32\shell32_winetest.exe 7 optional
+modules\rostests\winetests\shlwapi\shlwapi_winetest.exe 7 optional
+modules\rostests\winetests\urlmon\urlmon_winetest.exe 7 optional
+modules\rostests\winetests\user32\user32_winetest.exe 7 optional
+modules\rostests\winetests\usp10\usp10_winetest.exe 7 optional
+modules\rostests\winetests\uxtheme\uxtheme_winetest.exe 7 optional
+modules\rostests\winetests\version\version_winetest.exe 7 optional
+modules\rostests\winetests\winhttp\winhttp_winetest.exe 7 optional
+modules\rostests\winetests\wininet\wininet_winetest.exe 7 optional
+modules\rostests\winetests\winmm\winmm_winetest.exe 7 optional
+modules\rostests\winetests\wintrust\wintrust_winetest.exe 7 optional
+modules\rostests\winetests\wlanapi\wlanapi_winetest.exe 7 optional
+modules\rostests\winetests\ws2_32\ws2_32_winetest.exe 7 optional
+modules\rostests\winetests\xmllite\xmllite_winetest.exe 7 optional
+
+
+modules\wallpaper\Angelus_02_ROSWP.bmp 4 optional
--- /dev/null
- pbo->pvRbrush = EngAllocMem(0, cj, 'rbdG');
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: GDI Driver Brush Functions
+ * FILE: subsystem/win32/win32k/eng/engbrush.c
+ * PROGRAMER: Jason Filby
+ * Timo Kreuzer
+ */
+
+#include <win32k.h>
+
+#define NDEBUG
+#include <debug.h>
+
+/** Internal functions ********************************************************/
+
+VOID
+NTAPI
+EBRUSHOBJ_vInit(EBRUSHOBJ *pebo, PBRUSH pbrush, PDC pdc)
+{
+ ASSERT(pebo);
+ ASSERT(pbrush);
+ ASSERT(pdc);
+
+ pebo->BrushObject.flColorType = 0;
+ pebo->BrushObject.pvRbrush = NULL;
+ pebo->pbrush = pbrush;
+ pebo->pengbrush = NULL;
+ pebo->flattrs = pbrush->flAttrs;
+
+ /* Initialize 1 bpp fore and back colors */
+ pebo->crCurrentBack = pdc->pdcattr->crBackgroundClr;
+ pebo->crCurrentText = pdc->pdcattr->crForegroundClr;
+
+ pebo->psurfTrg = pdc->dclevel.pSurface;
+ ASSERT(pebo->psurfTrg);
+ ASSERT(pebo->psurfTrg->ppal);
+
+ pebo->ppalSurf = pebo->psurfTrg->ppal;
+ GDIOBJ_IncrementShareCount(&pebo->ppalSurf->BaseObject);
+
+ if (pbrush->flAttrs & GDIBRUSH_IS_NULL)
+ {
+ /* NULL brushes don't need a color */
+ pebo->BrushObject.iSolidColor = 0;
+ }
+ else if (pbrush->flAttrs & GDIBRUSH_IS_SOLID)
+ {
+ /* Set the RGB color */
+ EBRUSHOBJ_vSetSolidBrushColor(pebo, pbrush->BrushAttr.lbColor);
+ }
+ else
+ {
+ /* This is a pattern brush that needs realization */
+ pebo->BrushObject.iSolidColor = 0xFFFFFFFF;
+
+ /* Use foreground color of hatch brushes */
+ if (pbrush->flAttrs & GDIBRUSH_IS_HATCH)
+ pebo->crCurrentText = pbrush->BrushAttr.lbColor;
+ }
+}
+
+VOID
+FASTCALL
+EBRUSHOBJ_vSetSolidBrushColor(EBRUSHOBJ *pebo, COLORREF crColor)
+{
+ ULONG iSolidColor;
+ EXLATEOBJ exlo;
+
+ /* Never use with non-solid brushes */
+ ASSERT(pebo->flattrs & GDIBRUSH_IS_SOLID);
+
+ /* Set the RGB color */
+ pebo->crRealize = crColor;
+ pebo->ulRGBColor = crColor;
+
+ /* Initialize an XLATEOBJ RGB -> surface */
+ EXLATEOBJ_vInitialize(&exlo,
+ &gpalRGB,
+ pebo->ppalSurf,
+ pebo->crCurrentBack,
+ 0,
+ 0);
+
+ /* Translate the brush color to the target format */
+ iSolidColor = XLATEOBJ_iXlate(&exlo.xlo, crColor);
+ pebo->BrushObject.iSolidColor = iSolidColor;
+
+ /* Clean up the XLATEOBJ */
+ EXLATEOBJ_vCleanup(&exlo);
+}
+
+VOID
+NTAPI
+EBRUSHOBJ_vCleanup(EBRUSHOBJ *pebo)
+{
+ /* Check if there's a GDI realisation */
+ if (pebo->pengbrush)
+ {
+ EngDeleteSurface(pebo->pengbrush);
+ pebo->pengbrush = NULL;
+ }
+
+ /* Check if there's a driver's realisation */
+ if (pebo->BrushObject.pvRbrush)
+ {
+ /* Free allocated driver memory */
+ EngFreeMem(pebo->BrushObject.pvRbrush);
+ pebo->BrushObject.pvRbrush = NULL;
+ }
+
+ PALETTE_ShareUnlockPalette(pebo->ppalSurf);
+}
+
+VOID
+NTAPI
+EBRUSHOBJ_vUpdate(EBRUSHOBJ *pebo, PBRUSH pbrush, PDC pdc)
+{
+ /* Cleanup the brush */
+ EBRUSHOBJ_vCleanup(pebo);
+
+ /* Reinitialize */
+ EBRUSHOBJ_vInit(pebo, pbrush, pdc);
+}
+
+/**
+ * This function is not exported, because it makes no sense for
+ * The driver to punt back to this function */
+BOOL
+APIENTRY
+EngRealizeBrush(
+ BRUSHOBJ *pbo,
+ SURFOBJ *psoDst,
+ SURFOBJ *psoPattern,
+ SURFOBJ *psoMask,
+ XLATEOBJ *pxlo,
+ ULONG iHatch)
+{
+ EBRUSHOBJ *pebo;
+ HBITMAP hbmpRealize;
+ SURFOBJ *psoRealize;
+ POINTL ptlSrc = {0, 0};
+ RECTL rclDest;
+ ULONG lWidth;
+
+ /* Calculate width in bytes of the realized brush */
+ lWidth = DIB_GetDIBWidthBytes(psoPattern->sizlBitmap.cx,
+ BitsPerFormat(psoDst->iBitmapFormat));
+
+ /* Allocate a bitmap */
+ hbmpRealize = EngCreateBitmap(psoPattern->sizlBitmap,
+ lWidth,
+ psoDst->iBitmapFormat,
+ BMF_NOZEROINIT,
+ NULL);
+ if (!hbmpRealize)
+ {
+ return FALSE;
+ }
+
+ /* Lock the bitmap */
+ psoRealize = EngLockSurface(hbmpRealize);
+ if (!psoRealize)
+ {
+ EngDeleteSurface(hbmpRealize);
+ return FALSE;
+ }
+
+ /* Copy the bits to the new format bitmap */
+ rclDest.left = rclDest.top = 0;
+ rclDest.right = psoPattern->sizlBitmap.cx;
+ rclDest.bottom = psoPattern->sizlBitmap.cy;
+ EngCopyBits(psoRealize, psoPattern, NULL, pxlo, &rclDest, &ptlSrc);
+
+ /* Unlock the bitmap again */
+ EngUnlockSurface(psoRealize);
+
+ pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
+ pebo->pengbrush = (PVOID)hbmpRealize;
+
+ return TRUE;
+}
+
+BOOL
+NTAPI
+EBRUSHOBJ_bRealizeBrush(EBRUSHOBJ *pebo, BOOL bCallDriver)
+{
+ BOOL bResult;
+ PFN_DrvRealizeBrush pfnRealzizeBrush = NULL;
+ PSURFACE psurfPattern, psurfMask;
+ PPDEVOBJ ppdev = NULL;
+ EXLATEOBJ exlo;
+
+ /* All EBRUSHOBJs have a surface, see EBRUSHOBJ_vInit */
+ ASSERT(pebo->psurfTrg);
+
+ ppdev = (PPDEVOBJ)pebo->psurfTrg->SurfObj.hdev;
+
+ // FIXME: all SURFACEs need a PDEV
+ if (ppdev && bCallDriver)
+ pfnRealzizeBrush = ppdev->DriverFunctions.RealizeBrush;
+
+ if (!pfnRealzizeBrush)
+ pfnRealzizeBrush = EngRealizeBrush;
+
+ psurfPattern = SURFACE_ShareLockSurface(pebo->pbrush->hbmPattern);
+ ASSERT(psurfPattern);
+ ASSERT(psurfPattern->ppal);
+
+ /* FIXME: implement mask */
+ psurfMask = NULL;
+
+ /* Initialize XLATEOBJ for the brush */
+ EXLATEOBJ_vInitialize(&exlo,
+ psurfPattern->ppal,
+ pebo->psurfTrg->ppal,
+ 0,
+ pebo->crCurrentBack,
+ pebo->crCurrentText);
+
+ /* Create the realization */
+ bResult = pfnRealzizeBrush(&pebo->BrushObject,
+ &pebo->psurfTrg->SurfObj,
+ &psurfPattern->SurfObj,
+ psurfMask ? &psurfMask->SurfObj : NULL,
+ &exlo.xlo,
+ -1); // FIXME: what about hatch brushes?
+
+ /* Cleanup the XLATEOBJ */
+ EXLATEOBJ_vCleanup(&exlo);
+
+ /* Unlock surfaces */
+ if (psurfPattern)
+ SURFACE_ShareUnlockSurface(psurfPattern);
+ if (psurfMask)
+ SURFACE_ShareUnlockSurface(psurfMask);
+
+ return bResult;
+}
+
+PVOID
+NTAPI
+EBRUSHOBJ_pvGetEngBrush(EBRUSHOBJ *pebo)
+{
+ BOOL bResult;
+
+ if (!pebo->pengbrush)
+ {
+ bResult = EBRUSHOBJ_bRealizeBrush(pebo, FALSE);
+ if (!bResult)
+ {
+ if (pebo->pengbrush)
+ EngDeleteSurface(pebo->pengbrush);
+ pebo->pengbrush = NULL;
+ }
+ }
+
+ return pebo->pengbrush;
+}
+
+
+/** Exported DDI functions ****************************************************/
+
+/*
+ * @implemented
+ */
+PVOID APIENTRY
+BRUSHOBJ_pvAllocRbrush(
+ IN BRUSHOBJ *pbo,
+ IN ULONG cj)
+{
++ pbo->pvRbrush = EngAllocMem(0, cj, GDITAG_RBRUSH);
+ return pbo->pvRbrush;
+}
+
+/*
+ * @implemented
+ */
+PVOID APIENTRY
+BRUSHOBJ_pvGetRbrush(
+ IN BRUSHOBJ *pbo)
+{
+ EBRUSHOBJ *pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
+ BOOL bResult;
+
+ if (!pbo->pvRbrush)
+ {
+ bResult = EBRUSHOBJ_bRealizeBrush(pebo, TRUE);
+ if (!bResult)
+ {
+ if (pbo->pvRbrush)
+ {
+ EngFreeMem(pbo->pvRbrush);
+ pbo->pvRbrush = NULL;
+ }
+ }
+ }
+
+ return pbo->pvRbrush;
+}
+
+/*
+ * @implemented
+ */
+ULONG APIENTRY
+BRUSHOBJ_ulGetBrushColor(
+ IN BRUSHOBJ *pbo)
+{
+ EBRUSHOBJ *pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
+ return pebo->ulRGBColor;
+}
+
+/* EOF */
--- /dev/null
- Process->Win32Process = ExAllocatePool(NonPagedPool, sizeof(PROCESSINFO));
+/*
+ * ReactOS W32 Subsystem
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 ReactOS Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ * Entry Point for win32k.sys
+ */
+
+#include <win32k.h>
+#include <include/napi.h>
+
+#define NDEBUG
+#include <debug.h>
+
+HANDLE hModuleWin;
+
+PGDI_HANDLE_TABLE INTERNAL_CALL GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject);
+BOOL INTERNAL_CALL GDI_CleanupForProcess (struct _EPROCESS *Process);
+/* FIXME */
+PGDI_HANDLE_TABLE GdiHandleTable = NULL;
+PSECTION_OBJECT GdiTableSection = NULL;
+
+HANDLE GlobalUserHeap = NULL;
+PSECTION_OBJECT GlobalUserHeapSection = NULL;
+
+PSERVERINFO gpsi = NULL; // Global User Server Information.
+
+HSEMAPHORE hsemDriverMgmt = NULL;
+
+SHORT gusLanguageID;
+
+extern ULONG_PTR Win32kSSDT[];
+extern UCHAR Win32kSSPT[];
+extern ULONG Win32kNumberOfSysCalls;
+
+NTSTATUS
+APIENTRY
+Win32kProcessCallback(struct _EPROCESS *Process,
+ BOOLEAN Create)
+{
+ PPROCESSINFO Win32Process;
+ DECLARE_RETURN(NTSTATUS);
+
+ DPRINT("Enter Win32kProcessCallback\n");
+ UserEnterExclusive();
+
+ /* Get the Win32 Process */
+ Win32Process = PsGetProcessWin32Process(Process);
+
+ /* Allocate one if needed */
+ if (!Win32Process)
+ {
+ /* FIXME - lock the process */
+ Win32Process = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(PROCESSINFO),
+ 'p23W');
+
+ if (Win32Process == NULL) RETURN( STATUS_NO_MEMORY);
+
+ RtlZeroMemory(Win32Process, sizeof(PROCESSINFO));
+
+ PsSetProcessWin32Process(Process, Win32Process);
+ /* FIXME - unlock the process */
+ }
+
+ if (Create)
+ {
+ SIZE_T ViewSize = 0;
+ LARGE_INTEGER Offset;
+ PVOID UserBase = NULL;
+ NTSTATUS Status;
+ extern PSECTION_OBJECT GlobalUserHeapSection;
+ DPRINT("Creating W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql());
+
+ /* map the global heap into the process */
+ Offset.QuadPart = 0;
+ Status = MmMapViewOfSection(GlobalUserHeapSection,
+ PsGetCurrentProcess(),
+ &UserBase,
+ 0,
+ 0,
+ &Offset,
+ &ViewSize,
+ ViewUnmap,
+ SEC_NO_CHANGE,
+ PAGE_EXECUTE_READ); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to map the global heap! 0x%x\n", Status);
+ RETURN(Status);
+ }
+ Win32Process->HeapMappings.Next = NULL;
+ Win32Process->HeapMappings.KernelMapping = (PVOID)GlobalUserHeap;
+ Win32Process->HeapMappings.UserMapping = UserBase;
+ Win32Process->HeapMappings.Count = 1;
+
+ InitializeListHead(&Win32Process->ClassList);
+
+ InitializeListHead(&Win32Process->MenuListHead);
+
+ InitializeListHead(&Win32Process->GDIBrushAttrFreeList);
+ InitializeListHead(&Win32Process->GDIDcAttrFreeList);
+
+ InitializeListHead(&Win32Process->PrivateFontListHead);
+ ExInitializeFastMutex(&Win32Process->PrivateFontListLock);
+
+ InitializeListHead(&Win32Process->DriverObjListHead);
+ ExInitializeFastMutex(&Win32Process->DriverObjListLock);
+
+ Win32Process->KeyboardLayout = W32kGetDefaultKeyLayout();
+
+ if(Process->Peb != NULL)
+ {
+ /* map the gdi handle table to user land */
+ Process->Peb->GdiSharedHandleTable = GDI_MapHandleTable(GdiTableSection, Process);
+ Process->Peb->GdiDCAttributeList = GDI_BATCH_LIMIT;
+ }
+
+ Win32Process->peProcess = Process;
+ /* setup process flags */
+ Win32Process->W32PF_flags = 0;
+ }
+ else
+ {
+ DPRINT("Destroying W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql());
+ IntCleanupMenus(Process, Win32Process);
+ IntCleanupCurIcons(Process, Win32Process);
+ CleanupMonitorImpl();
+
+ /* no process windows should exist at this point, or the function will assert! */
+ DestroyProcessClasses(Win32Process);
+
+ GDI_CleanupForProcess(Process);
+
+ co_IntGraphicsCheck(FALSE);
+
+ /*
+ * Deregister logon application automatically
+ */
+ if(LogonProcess == Win32Process)
+ {
+ LogonProcess = NULL;
+ }
+ }
+
+ RETURN( STATUS_SUCCESS);
+
+CLEANUP:
+ UserLeave();
+ DPRINT("Leave Win32kProcessCallback, ret=%i\n",_ret_);
+ END_CLEANUP;
+}
+
+
+NTSTATUS
+APIENTRY
+Win32kThreadCallback(struct _ETHREAD *Thread,
+ PSW32THREADCALLOUTTYPE Type)
+{
+ struct _EPROCESS *Process;
+ PTHREADINFO Win32Thread;
+ DECLARE_RETURN(NTSTATUS);
+
+ DPRINT("Enter Win32kThreadCallback\n");
+ UserEnterExclusive();
+
+ Process = Thread->ThreadsProcess;
+
+ /* Get the Win32 Thread */
+ Win32Thread = PsGetThreadWin32Thread(Thread);
+
+ /* Allocate one if needed */
+ if (!Win32Thread)
+ {
+ /* FIXME - lock the process */
+ Win32Thread = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(THREADINFO),
+ 't23W');
+
+ if (Win32Thread == NULL) RETURN( STATUS_NO_MEMORY);
+
+ RtlZeroMemory(Win32Thread, sizeof(THREADINFO));
+
+ PsSetThreadWin32Thread(Thread, Win32Thread);
+ /* FIXME - unlock the process */
+ }
+ if (Type == PsW32ThreadCalloutInitialize)
+ {
+ HWINSTA hWinSta = NULL;
+ PTEB pTeb;
+ HDESK hDesk = NULL;
+ NTSTATUS Status;
+ PUNICODE_STRING DesktopPath;
+ PRTL_USER_PROCESS_PARAMETERS ProcessParams = (Process->Peb ? Process->Peb->ProcessParameters : NULL);
+
+ DPRINT("Creating W32 thread TID:%d at IRQ level: %lu\n", Thread->Cid.UniqueThread, KeGetCurrentIrql());
+
+ InitializeListHead(&Win32Thread->WindowListHead);
+ InitializeListHead(&Win32Thread->W32CallbackListHead);
+ InitializeListHead(&Win32Thread->PtiLink);
+
+ /*
+ * inherit the thread desktop and process window station (if not yet inherited) from the process startup
+ * info structure. See documentation of CreateProcess()
+ */
+ DesktopPath = (ProcessParams ? ((ProcessParams->DesktopInfo.Length > 0) ? &ProcessParams->DesktopInfo : NULL) : NULL);
+ Status = IntParseDesktopPath(Process,
+ DesktopPath,
+ &hWinSta,
+ &hDesk);
+ if(NT_SUCCESS(Status))
+ {
+ if(hWinSta != NULL)
+ {
+ if(Process != CsrProcess)
+ {
+ HWINSTA hProcessWinSta = (HWINSTA)InterlockedCompareExchangePointer((PVOID)&Process->Win32WindowStation, (PVOID)hWinSta, NULL);
+ if(hProcessWinSta != NULL)
+ {
+ /* our process is already assigned to a different window station, we don't need the handle anymore */
+ NtClose(hWinSta);
+ }
+ }
+ else
+ {
+ NtClose(hWinSta);
+ }
+ }
+
+ if (hDesk != NULL)
+ {
+ PDESKTOP DesktopObject;
+ Win32Thread->rpdesk = NULL;
+ Status = ObReferenceObjectByHandle(hDesk,
+ 0,
+ ExDesktopObjectType,
+ KernelMode,
+ (PVOID*)&DesktopObject,
+ NULL);
+ NtClose(hDesk);
+ if(NT_SUCCESS(Status))
+ {
+ if (!IntSetThreadDesktop(DesktopObject,
+ FALSE))
+ {
+ DPRINT1("Unable to set thread desktop\n");
+ }
+ }
+ else
+ {
+ DPRINT1("Unable to reference thread desktop handle 0x%x\n", hDesk);
+ }
+ }
+ }
+ Win32Thread->TIF_flags &= ~TIF_INCLEANUP;
+ co_IntDestroyCaret(Win32Thread);
+ Win32Thread->ppi = PsGetCurrentProcessWin32Process();
+ pTeb = NtCurrentTeb();
+ if (pTeb)
+ {
+ Win32Thread->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo;
+ Win32Thread->pClientInfo->pClientThreadInfo = NULL;
+ }
+ Win32Thread->MessageQueue = MsqCreateMessageQueue(Thread);
+ Win32Thread->KeyboardLayout = W32kGetDefaultKeyLayout();
+ Win32Thread->pEThread = Thread;
+ }
+ else
+ {
+ PSINGLE_LIST_ENTRY e;
+
+ DPRINT("Destroying W32 thread TID:%d at IRQ level: %lu\n", Thread->Cid.UniqueThread, KeGetCurrentIrql());
+
+ Win32Thread->TIF_flags |= TIF_INCLEANUP;
+ DceFreeThreadDCE(Win32Thread);
+ HOOK_DestroyThreadHooks(Thread);
+ /* Cleanup timers */
+ DestroyTimersForThread(Win32Thread);
+ KeSetEvent(Win32Thread->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
+ UnregisterThreadHotKeys(Thread);
+ /* what if this co_ func crash in umode? what will clean us up then? */
+ co_DestroyThreadWindows(Thread);
+ IntBlockInput(Win32Thread, FALSE);
+ MsqDestroyMessageQueue(Win32Thread->MessageQueue);
+ IntCleanupThreadCallbacks(Win32Thread);
+
+ /* cleanup user object references stack */
+ e = PopEntryList(&Win32Thread->ReferencesList);
+ while (e)
+ {
+ PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(e, USER_REFERENCE_ENTRY, Entry);
+ DPRINT("thread clean: remove reference obj 0x%x\n",ref->obj);
+ UserDereferenceObject(ref->obj);
+
+ e = PopEntryList(&Win32Thread->ReferencesList);
+ }
+
+ IntSetThreadDesktop(NULL,
+ TRUE);
+
+ PsSetThreadWin32Thread(Thread, NULL);
+ }
+
+ RETURN( STATUS_SUCCESS);
+
+CLEANUP:
+ UserLeave();
+ DPRINT("Leave Win32kThreadCallback, ret=%i\n",_ret_);
+ END_CLEANUP;
+}
+
+/* Only used in ntuser/input.c KeyboardThreadMain(). If it's
+ not called there anymore, please delete */
+NTSTATUS
+Win32kInitWin32Thread(PETHREAD Thread)
+{
+ PEPROCESS Process;
+
+ Process = Thread->ThreadsProcess;
+
+ if (Process->Win32Process == NULL)
+ {
+ /* FIXME - lock the process */
- Thread->Tcb.Win32Thread = ExAllocatePool (NonPagedPool, sizeof(THREADINFO));
++ Process->Win32Process = ExAllocatePoolWithTag(NonPagedPool, sizeof(PROCESSINFO), USERTAG_PROCESSINFO);
+
+ if (Process->Win32Process == NULL)
+ return STATUS_NO_MEMORY;
+
+ RtlZeroMemory(Process->Win32Process, sizeof(PROCESSINFO));
+ /* FIXME - unlock the process */
+
+ Win32kProcessCallback(Process, TRUE);
+ }
+
+ if (Thread->Tcb.Win32Thread == NULL)
+ {
++ Thread->Tcb.Win32Thread = ExAllocatePoolWithTag(NonPagedPool, sizeof(THREADINFO), USERTAG_THREADINFO);
+ if (Thread->Tcb.Win32Thread == NULL)
+ return STATUS_NO_MEMORY;
+
+ RtlZeroMemory(Thread->Tcb.Win32Thread, sizeof(THREADINFO));
+
+ Win32kThreadCallback(Thread, PsW32ThreadCalloutInitialize);
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+C_ASSERT(sizeof(SERVERINFO) <= PAGE_SIZE);
+
+/*
+ * This definition doesn't work
+ */
+NTSTATUS APIENTRY
+DriverEntry (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath)
+{
+ NTSTATUS Status;
+ BOOLEAN Result;
+ WIN32_CALLOUTS_FPNS CalloutData = {0};
+ PVOID GlobalUserHeapBase = NULL;
+
+ /*
+ * Register user mode call interface
+ * (system service table index = 1)
+ */
+ Result = KeAddSystemServiceTable (Win32kSSDT,
+ NULL,
+ Win32kNumberOfSysCalls,
+ Win32kSSPT,
+ 1);
+ if (Result == FALSE)
+ {
+ DPRINT1("Adding system services failed!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ hModuleWin = MmPageEntireDriver(DriverEntry);
+ DPRINT("Win32k hInstance 0x%x!\n",hModuleWin);
+ /*
+ * Register Object Manager Callbacks
+ */
+ CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
+ CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
+ CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
+ CalloutData.ProcessCallout = Win32kProcessCallback;
+ CalloutData.ThreadCallout = Win32kThreadCallback;
+ CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
+
+ /*
+ * Register our per-process and per-thread structures.
+ */
+ PsEstablishWin32Callouts((PWIN32_CALLOUTS_FPNS)&CalloutData);
+
+ GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
+ &GlobalUserHeapBase,
+ 1 * 1024 * 1024); /* FIXME - 1 MB for now... */
+ if (GlobalUserHeap == NULL)
+ {
+ DPRINT1("Failed to initialize the global heap!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if (!gpsi)
+ {
+ gpsi = UserHeapAlloc(sizeof(SERVERINFO));
+ if (gpsi)
+ {
+ RtlZeroMemory(gpsi, sizeof(SERVERINFO));
+ DPRINT("Global Server Data -> %x\n", gpsi);
+ }
+ else
+ {
+ ASSERT(FALSE);
+ }
+ }
+
+ if(!hsemDriverMgmt) hsemDriverMgmt = EngCreateSemaphore();
+
+ GdiHandleTable = GDIOBJ_iAllocHandleTable(&GdiTableSection);
+ if (GdiHandleTable == NULL)
+ {
+ DPRINT1("Failed to initialize the GDI handle table.\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ /* Initialize default palettes */
+ PALETTE_Init();
+
+ /* Create stock objects, ie. precreated objects commonly
+ used by win32 applications */
+ CreateStockObjects();
+ CreateSysColorObjects();
+
+ InitXlateImpl();
+ InitPDEVImpl();
+ InitLDEVImpl();
+ InitDeviceImpl();
+
+ Status = InitDcImpl();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to initialize Device context implementation!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ Status = InitUserImpl();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to initialize user implementation!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ Status = InitHotkeyImpl();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to initialize hotkey implementation!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ Status = InitWindowStationImpl();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to initialize window station implementation!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ Status = InitDesktopImpl();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to initialize desktop implementation!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ Status = InitWindowImpl();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to initialize window implementation!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ Status = InitMenuImpl();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to initialize menu implementation!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ Status = InitInputImpl();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to initialize input implementation.\n");
+ return(Status);
+ }
+
+ Status = InitKeyboardImpl();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to initialize keyboard implementation.\n");
+ return(Status);
+ }
+
+ Status = InitMonitorImpl();
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("Failed to initialize monitor implementation!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ Status = MsqInitializeImpl();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to initialize message queue implementation.\n");
+ return(Status);
+ }
+
+ Status = InitTimerImpl();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to initialize timer implementation.\n");
+ return(Status);
+ }
+
+ Status = InitAcceleratorImpl();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to initialize accelerator implementation.\n");
+ return(Status);
+ }
+
+ Status = InitGuiCheckImpl();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to initialize GUI check implementation.\n");
+ return(Status);
+ }
+
+ /* Initialize FreeType library */
+ if (! InitFontSupport())
+ {
+ DPRINT1("Unable to initialize font support\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ gusLanguageID = IntGdiGetLanguageID();
+
+ return STATUS_SUCCESS;
+}
+
+/* EOF */
--- /dev/null
- wce = ExAllocatePool(PagedPool, sizeof(CLIPBOARDCHAINELEMENT));
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: Clipboard routines
+ * FILE: subsys/win32k/ntuser/clipboard.c
+ * PROGRAMER: Filip Navara <xnavara@volny.cz>
+ * Pablo Borobia <pborobia@gmail.com>
+ */
+
+#include <win32k.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#define DATA_DELAYED_RENDER 0
+#define DATA_SYNTHESIZED_RENDER -1
+
+PTHREADINFO ClipboardThread;
+PTHREADINFO ClipboardOwnerThread;
+PWINDOW_OBJECT ClipboardWindow;
+PWINDOW_OBJECT ClipboardViewerWindow;
+PWINDOW_OBJECT ClipboardOwnerWindow;
+BOOL sendDrawClipboardMsg;
+BOOL recentlySetClipboard;
+BOOL delayedRender;
+UINT lastEnumClipboardFormats;
+DWORD ClipboardSequenceNumber = 0;
+
+PCLIPBOARDCHAINELEMENT WindowsChain = NULL;
+PCLIPBOARDELEMENT ClipboardData = NULL;
+
+PCHAR synthesizedData;
+DWORD synthesizedDataSize;
+
+
+/*==============================================================*/
+
+/* return the pointer to the prev window of the finded window,
+ if NULL does not exists in the chain */
+PCLIPBOARDCHAINELEMENT FASTCALL
+IntIsWindowInChain(PWINDOW_OBJECT window)
+{
+ PCLIPBOARDCHAINELEMENT wce = WindowsChain;
+
+ while (wce)
+ {
+ if (wce->window == window)
+ {
+ break;
+ }
+ wce = wce->next;
+ }
+
+ return wce;
+}
+
+VOID FASTCALL printChain(VOID)
+{
+ /*test*/
+ PCLIPBOARDCHAINELEMENT wce2 = WindowsChain;
+ while (wce2)
+ {
+ DPRINT1("chain: %p\n", wce2->window->hSelf);
+ wce2 = wce2->next;
+ }
+}
+
+/* the new window always have to be the first in the chain */
+PCLIPBOARDCHAINELEMENT FASTCALL
+IntAddWindowToChain(PWINDOW_OBJECT window)
+{
+ PCLIPBOARDCHAINELEMENT wce = NULL;
+
+ if (!IntIsWindowInChain(window))
+ {
+ wce = WindowsChain;
+
- ce = ExAllocatePool(PagedPool, sizeof(CLIPBOARDELEMENT));
++ wce = ExAllocatePoolWithTag(PagedPool, sizeof(CLIPBOARDCHAINELEMENT), USERTAG_CLIPBOARD);
+ if (wce == NULL)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ goto exit_addChain;
+ }
+
+ wce->window = window;
+ wce->next = WindowsChain;
+
+ WindowsChain = wce;
+
+ //printChain();
+ }
+exit_addChain:
+
+ /* return the next window to beremoved later */
+ return wce;
+}
+
+PCLIPBOARDCHAINELEMENT FASTCALL
+IntRemoveWindowFromChain(PWINDOW_OBJECT window)
+{
+ PCLIPBOARDCHAINELEMENT wce = WindowsChain;
+ PCLIPBOARDCHAINELEMENT *link = &WindowsChain;
+
+ if (IntIsWindowInChain(window))
+ {
+ while (wce != NULL)
+ {
+ if (wce->window == window)
+ {
+ *link = wce->next;
+ break;
+ }
+
+ link = &wce->next;
+ wce = wce->next;
+ }
+
+ //printChain();
+
+ return wce;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+/*==============================================================*/
+/* if format exists, returns a non zero value (pointing to format object) */
+PCLIPBOARDELEMENT FASTCALL
+intIsFormatAvailable(UINT format)
+{
+ PCLIPBOARDELEMENT ret = NULL;
+ PCLIPBOARDELEMENT ce = ClipboardData;
+
+ while(ce)
+ {
+ if (ce->format == format)
+ {
+ ret = ce;
+ break;
+ }
+ ce = ce->next;
+ }
+ return ret;
+}
+
+/* counts how many distinct format were are in the clipboard */
+DWORD FASTCALL
+IntCountClipboardFormats(VOID)
+{
+ DWORD ret = 0;
+ PCLIPBOARDELEMENT ce = ClipboardData;
+
+ while(ce)
+ {
+ ret++;
+ ce = ce->next;
+ }
+ return ret;
+}
+
+/* adds a new format and data to the clipboard */
+PCLIPBOARDELEMENT FASTCALL
+intAddFormatedData(UINT format, HANDLE hData, DWORD size)
+{
+ PCLIPBOARDELEMENT ce = NULL;
+
- hCBData = ExAllocatePool(PagedPool, size);
++ ce = ExAllocatePoolWithTag(PagedPool, sizeof(CLIPBOARDELEMENT), USERTAG_CLIPBOARD);
+ if (ce == NULL)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ else
+ {
+ ce->format = format;
+ ce->size = size;
+ ce->hData = hData;
+ ce->next = ClipboardData;
+
+ ClipboardData = ce;
+
+ IntIncrementSequenceNumber();
+ }
+
+ return ce;
+}
+
+/* removes a format and its data from the clipboard */
+BOOL FASTCALL
+intRemoveFormatedData(UINT format)
+{
+ BOOL ret = FALSE;
+ PCLIPBOARDELEMENT ce = ClipboardData;
+ PCLIPBOARDELEMENT *link = &ClipboardData;
+
+ if (intIsFormatAvailable(format))
+ {
+ while (ce != NULL)
+ {
+ if (ce->format == format)
+ {
+ *link = ce->next;
+ break;
+ }
+
+ link = &ce->next;
+ ce = ce->next;
+ }
+
+ if (ce->hData)
+ {
+ ExFreePool(ce->hData);
+ }
+ ExFreePool(ce);
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+VOID FASTCALL
+IntEmptyClipboardData(VOID)
+{
+ PCLIPBOARDELEMENT ce = ClipboardData;
+ PCLIPBOARDELEMENT tmp;
+
+ while(ce)
+ {
+ tmp = ce->next;
+ if (ce->hData)
+ {
+ ExFreePool(ce->hData);
+ }
+ ExFreePool(ce);
+ ce = tmp;
+ }
+
+ ClipboardData = NULL;
+}
+
+/*==============================================================*/
+
+HANDLE FASTCALL
+renderBITMAPfromDIB(LPBYTE pDIB)
+{
+ HDC hdc;
+ HBITMAP hbitmap;
+ unsigned int offset;
+ BITMAPV5INFO bmi;
+ NTSTATUS Status ;
+
+ //hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE);
+ hdc = UserGetDCEx(ClipboardWindow, NULL, DCX_USESTYLE);
+
+ /* Probe it */
+ _SEH2_TRY
+ {
+ Status = ProbeAndConvertToBitmapV5Info(&bmi, (BITMAPINFO*)pDIB, DIB_RGB_COLORS, 0);
+ offset = DIB_BitmapInfoSize((BITMAPINFO*)pDIB, DIB_RGB_COLORS);
+ ProbeForRead(pDIB + offset, bmi.bmiHeader.bV5SizeImage, 1);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if(!NT_SUCCESS(Status))
+ {
+ UserReleaseDC(ClipboardWindow, hdc, FALSE);
+ return NULL;
+ }
+
+ hbitmap = GreCreateDIBitmapInternal(hdc,
+ bmi.bmiHeader.bV5Width,
+ bmi.bmiHeader.bV5Height,
+ CBM_INIT,
+ pDIB+offset,
+ &bmi,
+ DIB_RGB_COLORS,
+ 0,
+ 0);
+ //UserReleaseDC(NULL, hdc, FALSE);
+ UserReleaseDC(ClipboardWindow, hdc, FALSE);
+
+ return hbitmap;
+}
+
+BOOL FASTCALL
+canSinthesize(UINT format)
+{
+ BOOL ret = FALSE;
+
+ switch(format)
+ {
+ case CF_BITMAP:
+ case CF_METAFILEPICT:
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+/* returns the size of the sinthesized data */
+DWORD FASTCALL
+synthesizeData(UINT format)
+{
+ DWORD ret = 0;
+
+ synthesizedData = NULL;
+ synthesizedDataSize = 0;
+
+ if (!canSinthesize(format))
+ {
+ return 0;
+ }
+
+ switch (format)
+ {
+ case CF_BITMAP:
+ {
+ break;
+ }
+
+ case CF_METAFILEPICT:
+ {
+ break;
+ }
+ }
+
+ ret = 1;
+
+ return ret;
+}
+
+VOID FASTCALL
+freeSynthesizedData(VOID)
+{
+ ExFreePool(synthesizedData);
+}
+
+/*==============================================================*/
+
+BOOL FASTCALL
+intIsClipboardOpenByMe(VOID)
+{
+ /* check if we open the clipboard */
+ if (ClipboardThread && ClipboardThread == PsGetCurrentThreadWin32Thread())
+ {
+ /* yes, we got a thread and its the same that opens the clipboard */
+ return TRUE;
+
+ }
+ /* will fail if not thread (closed) or not open by me*/
+ return FALSE;
+}
+
+/* IntClipboardFreeWindow it's called when a window was destroyed */
+VOID FASTCALL
+IntClipboardFreeWindow(PWINDOW_OBJECT window)
+{
+ /* called from co_UserFreeWindow in window.c */
+ /* check if clipboard is not locked by this window, if yes, unlock it */
+ if (ClipboardThread == PsGetCurrentThreadWin32Thread())
+ {
+ /* the window that opens the clipboard was destroyed */
+ ClipboardThread = NULL;
+ ClipboardWindow = NULL;
+ //TODO: free clipboard
+ }
+ if (window == ClipboardOwnerWindow)
+ {
+ /* the owner window was destroyed */
+ ClipboardOwnerWindow = NULL;
+ ClipboardOwnerThread = NULL;
+ }
+ /* remove window from window chain */
+ if (IntIsWindowInChain(window))
+ {
+ PCLIPBOARDCHAINELEMENT w = IntRemoveWindowFromChain(window);
+ if (w)
+ {
+ ExFreePool(w);
+ }
+ }
+}
+
+BOOL APIENTRY
+NtUserOpenClipboard(HWND hWnd, DWORD Unknown1)
+{
+
+ PWINDOW_OBJECT Window;
+ BOOL ret = FALSE;
+
+ UserEnterExclusive();
+
+ sendDrawClipboardMsg = FALSE;
+ recentlySetClipboard = FALSE;
+
+ if (ClipboardThread)
+ {
+ /* clipboard is already open */
+ if (ClipboardThread == PsGetCurrentThreadWin32Thread())
+ {
+ if (ClipboardOwnerWindow)
+ {
+ if (ClipboardOwnerWindow->hSelf == hWnd)
+ {
+ ret = TRUE;
+ }
+ }
+ else
+ {
+ if (hWnd == NULL)
+ {
+ ret = TRUE;
+ }
+ }
+ }
+ }
+ else
+ {
+
+ if (hWnd != NULL)
+ {
+ Window = UserGetWindowObject(hWnd);
+
+ if (Window != NULL)
+ {
+ ClipboardWindow = Window;
+ ClipboardThread = PsGetCurrentThreadWin32Thread();
+ ret = TRUE;
+ }
+ else
+ {
+ ClipboardWindow = NULL;
+ ClipboardThread = NULL;
+ ClipboardOwnerWindow = NULL;
+ ClipboardOwnerThread = NULL;
+ }
+ }
+ else
+ {
+ ClipboardWindow = NULL;
+ ClipboardThread = PsGetCurrentThreadWin32Thread();
+ ret = TRUE;
+ }
+ }
+
+ UserLeave();
+
+ return ret;
+}
+
+BOOL APIENTRY
+NtUserCloseClipboard(VOID)
+{
+ BOOL ret = FALSE;
+
+ UserEnterExclusive();
+
+ if (intIsClipboardOpenByMe())
+ {
+ ClipboardWindow = NULL;
+ ClipboardThread = NULL;
+ ret = TRUE;
+ }
+ else
+ {
+ SetLastWin32Error(ERROR_CLIPBOARD_NOT_OPEN);
+ }
+
+ recentlySetClipboard = FALSE;
+
+ UserLeave();
+
+ if (sendDrawClipboardMsg && WindowsChain)
+ {
+ /* only send message to the first window in the chain, then they'll do the chain */
+ /* commented because it makes a crash in co_MsqSendMessage
+ ASSERT(WindowsChain->window);
+ ASSERT(WindowsChain->window->hSelf);
+ DPRINT1("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", WindowsChain->window->hSelf);
+ co_IntSendMessage(WindowsChain->window->hSelf, WM_DRAWCLIPBOARD, 0, 0);
+ */
+ }
+
+ return ret;
+}
+
+HWND APIENTRY
+NtUserGetOpenClipboardWindow(VOID)
+{
+ HWND ret = NULL;
+
+ UserEnterShared();
+
+ if (ClipboardWindow)
+ {
+ ret = ClipboardWindow->hSelf;
+ }
+
+ UserLeave();
+
+ return ret;
+}
+
+BOOL APIENTRY
+NtUserChangeClipboardChain(HWND hWndRemove, HWND hWndNewNext)
+{
+ BOOL ret = FALSE;
+ PCLIPBOARDCHAINELEMENT w = NULL;
+ PWINDOW_OBJECT removeWindow;
+ UserEnterExclusive();
+
+ removeWindow = UserGetWindowObject(hWndRemove);
+
+ if (removeWindow)
+ {
+ if ((ret = !!IntIsWindowInChain(removeWindow)))
+ {
+ w = IntRemoveWindowFromChain(removeWindow);
+ if (w)
+ {
+ ExFreePool(w);
+ }
+ }
+ }
+
+ if (ret && WindowsChain)
+ {
+ // only send message to the first window in the chain,
+ // then they do the chain
+
+ /* WindowsChain->window may be NULL */
+ LPARAM lparam = WindowsChain->window == NULL ? 0 : (LPARAM)WindowsChain->window->hSelf;
+ DPRINT1("Message: WM_CHANGECBCHAIN to %p", WindowsChain->window->hSelf);
+ co_IntSendMessage(WindowsChain->window->hSelf, WM_CHANGECBCHAIN, (WPARAM)hWndRemove, lparam);
+ }
+
+ UserLeave();
+
+ return ret;
+}
+
+DWORD APIENTRY
+NtUserCountClipboardFormats(VOID)
+{
+ DWORD ret = 0;
+
+ if (ClipboardData)
+ {
+ ret = IntCountClipboardFormats();
+ }
+
+ return ret;
+}
+
+DWORD APIENTRY
+NtUserEmptyClipboard(VOID)
+{
+ BOOL ret = FALSE;
+
+ UserEnterExclusive();
+
+ if (intIsClipboardOpenByMe())
+ {
+ if (ClipboardData)
+ {
+ IntEmptyClipboardData();
+ }
+
+ ClipboardOwnerWindow = ClipboardWindow;
+ ClipboardOwnerThread = ClipboardThread;
+
+ IntIncrementSequenceNumber();
+
+ ret = TRUE;
+ }
+ else
+ {
+ SetLastWin32Error(ERROR_CLIPBOARD_NOT_OPEN);
+ }
+
+ if (ret && ClipboardOwnerWindow)
+ {
+ DPRINT("Clipboard: WM_DESTROYCLIPBOARD to %p", ClipboardOwnerWindow->hSelf);
+ co_IntSendMessage( ClipboardOwnerWindow->hSelf, WM_DESTROYCLIPBOARD, 0, 0);
+ }
+
+ UserLeave();
+
+ return ret;
+}
+
+HANDLE APIENTRY
+NtUserGetClipboardData(UINT uFormat, PVOID pBuffer)
+{
+ HANDLE ret = NULL;
+
+ UserEnterShared();
+
+ if (intIsClipboardOpenByMe())
+ {
+ /* when Unknown1 is zero, we returns to user32 the data size */
+ if (!pBuffer)
+ {
+ PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
+
+ if (data)
+ {
+ /* format exists in clipboard */
+ if (data->size == DATA_DELAYED_RENDER)
+ {
+ /* tell owner what data needs to be rendered */
+ if (ClipboardOwnerWindow)
+ {
+ ASSERT(ClipboardOwnerWindow->hSelf);
+ co_IntSendMessage(ClipboardOwnerWindow->hSelf, WM_RENDERFORMAT, (WPARAM)uFormat, 0);
+ data = intIsFormatAvailable(uFormat);
+ ASSERT(data->size);
+ ret = (HANDLE)(ULONG_PTR)data->size;
+ }
+ }
+ else
+ {
+ if (data->size == DATA_SYNTHESIZED_RENDER)
+ {
+ data->size = synthesizeData(uFormat);
+ }
+
+ }
+ ret = (HANDLE)(ULONG_PTR)data->size;
+ }
+ else
+ {
+ /* there is no data in this format */
+ //ret = (HANDLE)FALSE;
+ }
+ }
+ else
+ {
+ PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
+
+ if (data)
+ {
+ if (data->size == DATA_DELAYED_RENDER)
+ {
+ // we rendered it in 1st call of getclipboard data
+ }
+ else
+ {
+ if (data->size == DATA_SYNTHESIZED_RENDER)
+ {
+ if (uFormat == CF_BITMAP)
+ {
+ /* BITMAP & METAFILEs returns a GDI handle */
+ PCLIPBOARDELEMENT data = intIsFormatAvailable(CF_DIB);
+ if (data)
+ {
+ ret = renderBITMAPfromDIB(data->hData);
+ }
+ }
+ else
+ {
+ ret = (HANDLE)pBuffer;
+
+ _SEH2_TRY
+ {
+ ProbeForWrite(pBuffer, synthesizedDataSize, 1);
+ memcpy(pBuffer, (PCHAR)synthesizedData, synthesizedDataSize);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ret = NULL;
+ }
+ _SEH2_END
+
+ freeSynthesizedData();
+ }
+ }
+ else
+ {
+ ret = (HANDLE)pBuffer;
+
+ _SEH2_TRY
+ {
+ ProbeForWrite(pBuffer, data->size, 1);
+ memcpy(pBuffer, (PCHAR)data->hData, data->size);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ret = NULL;
+ }
+ _SEH2_END
+ }
+ }
+
+ }
+
+ }
+ }
+ else
+ {
+ SetLastWin32Error(ERROR_CLIPBOARD_NOT_OPEN);
+ }
+
+ UserLeave();
+
+ return ret;
+}
+
+INT APIENTRY
+NtUserGetClipboardFormatName(UINT format, PUNICODE_STRING FormatName,
+ INT cchMaxCount)
+{
+ UNICODE_STRING sFormatName;
+ INT ret = 0;
+
+ /* if the format is built-in we fail */
+ if (format < 0xc000)
+ {
+ /* registetrated formats are >= 0xc000 */
+ return 0;
+ }
+
+ if((cchMaxCount < 1) || !FormatName)
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForWriteUnicodeString(FormatName);
+ sFormatName = *(volatile UNICODE_STRING *)FormatName;
+ ProbeForWrite(sFormatName.Buffer, sFormatName.MaximumLength, 1);
+
+ ret = IntGetAtomName((RTL_ATOM)format, sFormatName.Buffer, cchMaxCount * sizeof(WCHAR));
+
+ if (ret >= 0)
+ {
+ ret = ret / sizeof(WCHAR);
+ sFormatName.Length = ret;
+ }
+ else
+ {
+ ret = 0;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ return ret;
+}
+
+HWND APIENTRY
+NtUserGetClipboardOwner(VOID)
+{
+ HWND ret = NULL;
+
+ UserEnterShared();
+
+ if (ClipboardOwnerWindow)
+ {
+ ret = ClipboardOwnerWindow->hSelf;
+ }
+
+ UserLeave();
+
+ return ret;
+}
+
+HWND APIENTRY
+NtUserGetClipboardViewer(VOID)
+{
+ HWND ret = NULL;
+
+ UserEnterShared();
+
+ if (WindowsChain)
+ {
+ ret = WindowsChain->window->hSelf;
+ }
+
+ UserLeave();
+
+ return ret;
+}
+
+INT APIENTRY
+NtUserGetPriorityClipboardFormat(UINT *paFormatPriorityList, INT cFormats)
+{
+ INT i;
+ UINT *priorityList;
+ INT ret = 0;
+
+ UserEnterExclusive();
+
+ _SEH2_TRY
+ {
+ if (IntCountClipboardFormats() == 0)
+ {
+ ret = 0;
+ }
+ else
+ {
+ ProbeForRead(paFormatPriorityList, cFormats, sizeof(UINT));
+
+ priorityList = paFormatPriorityList;
+
+ ret = -1;
+
+ for (i = 0; i < cFormats; i++)
+ {
+ if (intIsFormatAvailable(priorityList[i]))
+ {
+ ret = priorityList[i];
+ break;
+ }
+ }
+
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ UserLeave();
+
+ return ret;
+
+}
+
+BOOL APIENTRY
+NtUserIsClipboardFormatAvailable(UINT format)
+{
+ BOOL ret = FALSE;
+
+ UserEnterShared();
+
+ ret = (intIsFormatAvailable(format) != NULL);
+
+ UserLeave();
+
+ return ret;
+}
+
+
+
+HANDLE APIENTRY
+NtUserSetClipboardData(UINT uFormat, HANDLE hMem, DWORD size)
+{
+ HANDLE hCBData = NULL;
+ UNICODE_STRING unicodeString;
+ OEM_STRING oemString;
+ ANSI_STRING ansiString;
+
+ UserEnterExclusive();
+
+ /* to place data here the we need to be the owner */
+ if (ClipboardOwnerThread == PsGetCurrentThreadWin32Thread())
+ {
+ PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
+ if (data)
+ {
+
+ if (data->size == DATA_DELAYED_RENDER)
+ {
+ intRemoveFormatedData(uFormat);
+ }
+ else
+ {
+ // we already have this format on clipboard
+ goto exit_setCB;
+ }
+ }
+
+ if (hMem)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead(hMem, size, 1);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ _SEH2_YIELD(goto exit_setCB);
+ }
+ _SEH2_END;
+
+ if (intIsClipboardOpenByMe())
+ {
+ delayedRender = FALSE;
+ }
+
+ if (!canSinthesize(uFormat))
+ {
- hCBData = ExAllocatePool(PagedPool, size);
++ hCBData = ExAllocatePoolWithTag(PagedPool, size, USERTAG_CLIPBOARD);
+ memcpy(hCBData, hMem, size);
+ intAddFormatedData(uFormat, hCBData, size);
+ DPRINT1("Data stored\n");
+ }
+
+ sendDrawClipboardMsg = TRUE;
+ recentlySetClipboard = TRUE;
+ lastEnumClipboardFormats = uFormat;
+
+ /* conversions */
+ switch (uFormat)
+ {
+ case CF_TEXT:
+ {
+ //TODO : sinthesize CF_UNICODETEXT & CF_OEMTEXT
+ // CF_TEXT -> CF_UNICODETEXT
+ ansiString.Buffer = hCBData;
+ ansiString.Length = size;
+ RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
+ intAddFormatedData(CF_UNICODETEXT, unicodeString.Buffer, unicodeString.Length * sizeof(WCHAR));
+ // CF_TEXT -> CF_OEMTEXT
+ RtlUnicodeStringToOemString(&oemString, &unicodeString, TRUE);
+ intAddFormatedData(CF_OEMTEXT, oemString.Buffer, oemString.Length);
+ //HKCU\Control Panel\International\Locale
+ //intAddFormatedData(CF_LOCALE, oemString.Buffer, oemString.Length);
+ break;
+ }
+ case CF_UNICODETEXT:
+ {
+ //TODO : sinthesize CF_TEXT & CF_OEMTEXT
+ //CF_UNICODETEXT -> CF_TEXT
+ unicodeString.Buffer = hCBData;
+ unicodeString.Length = size;
+ RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
+ intAddFormatedData(CF_TEXT, ansiString.Buffer, ansiString.Length);
+ //CF_UNICODETEXT -> CF_OEMTEXT
+ RtlUnicodeStringToOemString(&oemString, &unicodeString, TRUE);
+ intAddFormatedData(CF_OEMTEXT, oemString.Buffer, oemString.Length);
+ break;
+ }
+ case CF_OEMTEXT:
+ {
+ //TODO : sinthesize CF_TEXT & CF_UNICODETEXT
+ //CF_OEMTEXT -> CF_UNICODETEXT
+ oemString.Buffer = hCBData;
+ oemString.Length = size;
+ RtlOemStringToUnicodeString(&unicodeString, &oemString, TRUE);
+ intAddFormatedData(CF_UNICODETEXT, unicodeString.Buffer, unicodeString.Length * sizeof(WCHAR));
+ //CF_OEMTEXT -> CF_TEXT
+ RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
+ intAddFormatedData(CF_TEXT, ansiString.Buffer, ansiString.Length);
+ break;
+ }
+ case CF_BITMAP:
+ {
+ // we need to render the DIB or DIBV5 format as soon as possible
+ // because pallette information may change
+
+ HDC hdc;
+ INT ret;
+ BITMAP bm;
+ BITMAPINFO bi;
+ SURFACE *psurf;
+
+ hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE);
+
+
+ psurf = SURFACE_LockSurface(hMem);
+ BITMAP_GetObject(psurf, sizeof(BITMAP), (PVOID)&bm);
+ if(psurf)
+ {
+ SURFACE_UnlockSurface(psurf);
+ }
+
+ bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bi.bmiHeader.biWidth = bm.bmWidth;
+ bi.bmiHeader.biHeight = bm.bmHeight;
+ bi.bmiHeader.biPlanes = 1;
+ bi.bmiHeader.biBitCount = bm.bmPlanes * bm.bmBitsPixel;
+ bi.bmiHeader.biCompression = BI_RGB;
+ bi.bmiHeader.biSizeImage = 0;
+ bi.bmiHeader.biXPelsPerMeter = 0;
+ bi.bmiHeader.biYPelsPerMeter = 0;
+ bi.bmiHeader.biClrUsed = 0;
+
+ ret = NtGdiGetDIBitsInternal(hdc, hMem, 0, bm.bmHeight, NULL, &bi, DIB_RGB_COLORS, 0, 0);
+
+ size = bi.bmiHeader.biSizeImage + sizeof(BITMAPINFOHEADER);
+
++ hCBData = ExAllocatePoolWithTag(PagedPool, size, USERTAG_CLIPBOARD);
+ memcpy(hCBData, &bi, sizeof(BITMAPINFOHEADER));
+
+ ret = NtGdiGetDIBitsInternal(hdc, hMem, 0, bm.bmHeight, (LPBYTE)hCBData + sizeof(BITMAPINFOHEADER), &bi, DIB_RGB_COLORS, 0, 0);
+
+ UserReleaseDC(NULL, hdc, FALSE);
+
+ intAddFormatedData(CF_DIB, hCBData, size);
+ intAddFormatedData(CF_BITMAP, 0, DATA_SYNTHESIZED_RENDER);
+ // intAddFormatedData(CF_DIBV5, hCBData, size);
+
+ break;
+ }
+ case CF_DIB:
+ {
+ intAddFormatedData(CF_BITMAP, 0, DATA_SYNTHESIZED_RENDER);
+ // intAddFormatedData(CF_DIBV5, hCBData, size);
+ /* investigate */
+ // intAddFormatedData(CF_PALETTE, hCBData, size);
+ break;
+ }
+ case CF_DIBV5:
+ // intAddFormatedData(CF_BITMAP, hCBData, size);
+ // intAddFormatedData(CF_PALETTE, hCBData, size);
+ // intAddFormatedData(CF_DIB, hCBData, size);
+ break;
+ case CF_ENHMETAFILE:
+ // intAddFormatedData(CF_METAFILEPICT, hCBData, size);
+ break;
+ case CF_METAFILEPICT:
+ // intAddFormatedData(CF_ENHMETAFILE, hCBData, size);
+ break;
+ }
+
+ }
+ else
+ {
+ // the window provides data in the specified format
+ delayedRender = TRUE;
+ sendDrawClipboardMsg = TRUE;
+ intAddFormatedData(uFormat, NULL, 0);
+ DPRINT1("SetClipboardData delayed format: %d\n", uFormat);
+ }
+
+
+ }
+
+exit_setCB:
+
+ UserLeave();
+
+ return hMem;
+}
+
+HWND APIENTRY
+NtUserSetClipboardViewer(HWND hWndNewViewer)
+{
+ HWND ret = NULL;
+ PCLIPBOARDCHAINELEMENT newWC = NULL;
+ PWINDOW_OBJECT window;
+
+ UserEnterExclusive();
+
+ window = UserGetWindowObject(hWndNewViewer);
+
+ if (window)
+ {
+ if ((newWC = IntAddWindowToChain(window)))
+ {
+ if (newWC)
+ {
+ // newWC->next may be NULL if we are the first window in the chain
+ if (newWC->next)
+ {
+ // return the next HWND available window in the chain
+ ret = newWC->next->window->hSelf;
+ }
+ }
+ }
+ }
+
+ UserLeave();
+
+ return ret;
+}
+
+UINT APIENTRY
+IntEnumClipboardFormats(UINT uFormat)
+{
+ UINT ret = 0;
+
+ if (intIsClipboardOpenByMe())
+ {
+ if (uFormat == 0)
+ {
+ if (recentlySetClipboard)
+ {
+ ret = lastEnumClipboardFormats;
+ }
+ else
+ {
+ /* return the first available format */
+ if (ClipboardData)
+ {
+ ret = ClipboardData->format;
+ }
+ }
+ }
+ else
+ {
+ if (recentlySetClipboard)
+ {
+ ret = 0;
+ }
+ else
+ {
+ /* querying nextt available format */
+ PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
+
+ if (data)
+ {
+ if (data->next)
+ {
+ ret = data->next->format;
+ }
+ else
+ {
+ /* reached the end */
+ ret = 0;
+ }
+ }
+ }
+
+ }
+ }
+ else
+ {
+ SetLastWin32Error(ERROR_CLIPBOARD_NOT_OPEN);
+ }
+
+ return ret;
+}
+
+// This number is incremented whenever the contents of the clipboard change
+// or the clipboard is emptied.
+// If clipboard rendering is delayed,
+// the sequence number is not incremented until the changes are rendered.
+VOID FASTCALL
+IntIncrementSequenceNumber(VOID)
+{
+ PTHREADINFO pti;
+ PWINSTATION_OBJECT WinStaObj;
+
+ pti = PsGetCurrentThreadWin32Thread();
+ WinStaObj = pti->rpdesk->rpwinstaParent;
+
+ WinStaObj->Clipboard->ClipboardSequenceNumber++;
+}
+
+DWORD APIENTRY
+NtUserGetClipboardSequenceNumber(VOID)
+{
+ //windowstation sequence number
+ //if no WINSTA_ACCESSCLIPBOARD access to the window station,
+ //the function returns zero.
+ DWORD sn;
+
+ HWINSTA WinSta;
+ PWINSTATION_OBJECT WinStaObj;
+ NTSTATUS Status;
+
+ WinSta = UserGetProcessWindowStation();
+
+ Status = IntValidateWindowStationHandle(WinSta, KernelMode, WINSTA_ACCESSCLIPBOARD, &WinStaObj);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("No WINSTA_ACCESSCLIPBOARD access\n");
+ SetLastNtError(Status);
+ return 0;
+ }
+
+ sn = WinStaObj->ClipboardSequenceNumber;
+
+ ObDereferenceObject(WinStaObj);
+
+ //local copy
+ //sn = ClipboardSequenceNumber;
+
+ return sn;
+}
+
+
+/**************** VISTA FUNCTIONS******************/
+
+BOOL APIENTRY NtUserAddClipboardFormatListener(
+ HWND hwnd
+)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL APIENTRY NtUserRemoveClipboardFormatListener(
+ HWND hwnd
+)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL APIENTRY NtUserGetUpdatedClipboardFormats(
+ PUINT lpuiFormats,
+ UINT cFormats,
+ PUINT pcFormatsOut
+)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+/* EOF */
--- /dev/null
- list = ExAllocatePool(PagedPool, sizeof(HWND) * (entries + 1)); /* alloc one extra for nullterm */
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: Desktops
+ * FILE: subsystems/win32/win32k/ntuser/desktop.c
+ * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISION HISTORY:
+ * 06-06-2001 CSH Created
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <win32k.h>
+
+#define NDEBUG
+#include <debug.h>
+#define TRACE DPRINT
+#define WARN DPRINT1
+#define ERR DPRINT1
+
+static
+VOID
+IntFreeDesktopHeap(
+ IN OUT PDESKTOP Desktop
+);
+
+/* GLOBALS *******************************************************************/
+
+/* Currently active desktop */
+PDESKTOP InputDesktop = NULL;
+HDESK InputDesktopHandle = NULL;
+HDC ScreenDeviceContext = NULL;
+BOOL g_PaintDesktopVersion = FALSE;
+
+GENERIC_MAPPING IntDesktopMapping =
+{
+ STANDARD_RIGHTS_READ | DESKTOP_ENUMERATE |
+ DESKTOP_READOBJECTS,
+ STANDARD_RIGHTS_WRITE | DESKTOP_CREATEMENU |
+ DESKTOP_CREATEWINDOW |
+ DESKTOP_HOOKCONTROL |
+ DESKTOP_JOURNALPLAYBACK |
+ DESKTOP_JOURNALRECORD |
+ DESKTOP_WRITEOBJECTS,
+ STANDARD_RIGHTS_EXECUTE | DESKTOP_SWITCHDESKTOP,
+ STANDARD_RIGHTS_REQUIRED | DESKTOP_CREATEMENU |
+ DESKTOP_CREATEWINDOW |
+ DESKTOP_ENUMERATE |
+ DESKTOP_HOOKCONTROL |
+ DESKTOP_JOURNALPLAYBACK |
+ DESKTOP_JOURNALRECORD |
+ DESKTOP_READOBJECTS |
+ DESKTOP_SWITCHDESKTOP |
+ DESKTOP_WRITEOBJECTS
+};
+
+/* OBJECT CALLBACKS **********************************************************/
+
+NTSTATUS
+APIENTRY
+IntDesktopObjectParse(IN PVOID ParseObject,
+ IN PVOID ObjectType,
+ IN OUT PACCESS_STATE AccessState,
+ IN KPROCESSOR_MODE AccessMode,
+ IN ULONG Attributes,
+ IN OUT PUNICODE_STRING CompleteName,
+ IN OUT PUNICODE_STRING RemainingName,
+ IN OUT PVOID Context OPTIONAL,
+ IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
+ OUT PVOID *Object)
+{
+ NTSTATUS Status;
+ PDESKTOP Desktop;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PLIST_ENTRY NextEntry, ListHead;
+ PWINSTATION_OBJECT WinStaObject = (PWINSTATION_OBJECT)ParseObject;
+ PUNICODE_STRING DesktopName;
+
+ /* Set the list pointers and loop the window station */
+ ListHead = &WinStaObject->DesktopListHead;
+ NextEntry = ListHead->Flink;
+ while (NextEntry != ListHead)
+ {
+ /* Get the current desktop */
+ Desktop = CONTAINING_RECORD(NextEntry, DESKTOP, ListEntry);
+
+ /* Get its name */
+ DesktopName = GET_DESKTOP_NAME(Desktop);
+ if (DesktopName)
+ {
+ /* Compare the name */
+ if (RtlEqualUnicodeString(RemainingName,
+ DesktopName,
+ (Attributes & OBJ_CASE_INSENSITIVE)))
+ {
+ /* We found a match. Did this come from a create? */
+ if (Context)
+ {
+ /* Unless OPEN_IF was given, fail with an error */
+ if (!(Attributes & OBJ_OPENIF))
+ {
+ /* Name collision */
+ return STATUS_OBJECT_NAME_COLLISION;
+ }
+ else
+ {
+ /* Otherwise, return with a warning only */
+ Status = STATUS_OBJECT_NAME_EXISTS;
+ }
+ }
+ else
+ {
+ /* This was a real open, so this is OK */
+ Status = STATUS_SUCCESS;
+ }
+
+ /* Reference the desktop and return it */
+ ObReferenceObject(Desktop);
+ *Object = Desktop;
+ return Status;
+ }
+ }
+
+ /* Go to the next desktop */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* If we got here but this isn't a create, then fail */
+ if (!Context) return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ /* Create the desktop object */
+ InitializeObjectAttributes(&ObjectAttributes, RemainingName, 0, NULL, NULL);
+ Status = ObCreateObject(KernelMode,
+ ExDesktopObjectType,
+ &ObjectAttributes,
+ KernelMode,
+ NULL,
+ sizeof(DESKTOP),
+ 0,
+ 0,
+ (PVOID)&Desktop);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Initialize shell hook window list and set the parent */
+ RtlZeroMemory(Desktop, sizeof(DESKTOP));
+ InitializeListHead(&Desktop->ShellHookWindows);
+ Desktop->rpwinstaParent = (PWINSTATION_OBJECT)ParseObject;
+
+ /* Put the desktop on the window station's list of associated desktops */
+ InsertTailList(&Desktop->rpwinstaParent->DesktopListHead,
+ &Desktop->ListEntry);
+
+ /* Set the desktop object and return success */
+ *Object = Desktop;
+ return STATUS_SUCCESS;
+}
+
+VOID APIENTRY
+IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters)
+{
+ PDESKTOP Desktop = (PDESKTOP)Parameters->Object;
+
+ DPRINT("Deleting desktop (0x%X)\n", Desktop);
+
+ /* Remove the desktop from the window station's list of associcated desktops */
+ RemoveEntryList(&Desktop->ListEntry);
+
+ IntFreeDesktopHeap(Desktop);
+}
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+NTSTATUS
+FASTCALL
+InitDesktopImpl(VOID)
+{
+ /* Set Desktop Object Attributes */
+ ExDesktopObjectType->TypeInfo.DefaultNonPagedPoolCharge = sizeof(DESKTOP);
+ ExDesktopObjectType->TypeInfo.GenericMapping = IntDesktopMapping;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+FASTCALL
+CleanupDesktopImpl(VOID)
+{
+ return STATUS_SUCCESS;
+}
+
+static int GetSystemVersionString(LPWSTR buffer)
+{
+ RTL_OSVERSIONINFOEXW versionInfo;
+ int len;
+
+ versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
+
+ if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo)))
+ return 0;
+
+ if (versionInfo.dwMajorVersion <= 4)
+ len = swprintf(buffer,
+ L"ReactOS Version %d.%d %s Build %d",
+ versionInfo.dwMajorVersion, versionInfo.dwMinorVersion,
+ versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
+ else
+ len = swprintf(buffer,
+ L"ReactOS %s (Build %d)",
+ versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
+
+ return len;
+}
+
+
+NTSTATUS FASTCALL
+IntParseDesktopPath(PEPROCESS Process,
+ PUNICODE_STRING DesktopPath,
+ HWINSTA *hWinSta,
+ HDESK *hDesktop)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING WinSta, Desktop, FullName;
+ BOOL DesktopPresent = FALSE;
+ BOOL WinStaPresent = FALSE;
+ NTSTATUS Status;
+
+ ASSERT(hWinSta);
+
+ *hWinSta = NULL;
+
+ if(hDesktop != NULL)
+ {
+ *hDesktop = NULL;
+ }
+
+ RtlInitUnicodeString(&WinSta, NULL);
+ RtlInitUnicodeString(&Desktop, NULL);
+
+ if(DesktopPath != NULL && DesktopPath->Buffer != NULL && DesktopPath->Length > sizeof(WCHAR))
+ {
+ PWCHAR c = DesktopPath->Buffer;
+ USHORT wl = 0;
+ USHORT l = DesktopPath->Length;
+
+ /*
+ * Parse the desktop path string which can be in the form "WinSta\Desktop"
+ * or just "Desktop". In latter case WinSta0 will be used.
+ */
+
+ while(l > 0)
+ {
+ if(*c == L'\\')
+ {
+ wl = (ULONG_PTR)c - (ULONG_PTR)DesktopPath->Buffer;
+ break;
+ }
+ l -= sizeof(WCHAR);
+ c++;
+ }
+
+ if(wl > 0)
+ {
+ WinSta.Length = wl;
+ WinSta.MaximumLength = wl + sizeof(WCHAR);
+ WinSta.Buffer = DesktopPath->Buffer;
+
+ WinStaPresent = TRUE;
+ c++;
+ }
+
+ Desktop.Length = DesktopPath->Length - wl;
+ if(wl > 0)
+ {
+ Desktop.Length -= sizeof(WCHAR);
+ }
+ if(Desktop.Length > 0)
+ {
+ Desktop.MaximumLength = Desktop.Length + sizeof(WCHAR);
+ Desktop.Buffer = ((wl > 0) ? c : DesktopPath->Buffer);
+ DesktopPresent = TRUE;
+ }
+ }
+
+ if(!WinStaPresent)
+ {
+#if 0
+ /* search the process handle table for (inherited) window station
+ handles, use a more appropriate one than WinSta0 if possible. */
+ if (!ObFindHandleForObject(Process,
+ NULL,
+ ExWindowStationObjectType,
+ NULL,
+ (PHANDLE)hWinSta))
+#endif
+ {
+ /* we had no luck searching for opened handles, use WinSta0 now */
+ RtlInitUnicodeString(&WinSta, L"WinSta0");
+ }
+ }
+
+ if(!DesktopPresent && hDesktop != NULL)
+ {
+#if 0
+ /* search the process handle table for (inherited) desktop
+ handles, use a more appropriate one than Default if possible. */
+ if (!ObFindHandleForObject(Process,
+ NULL,
+ ExDesktopObjectType,
+ NULL,
+ (PHANDLE)hDesktop))
+#endif
+ {
+ /* we had no luck searching for opened handles, use Desktop now */
+ RtlInitUnicodeString(&Desktop, L"Default");
+ }
+ }
+
+ if(*hWinSta == NULL)
+ {
+ if(!IntGetFullWindowStationName(&FullName, &WinSta, NULL))
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* open the window station */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &FullName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = ObOpenObjectByName(&ObjectAttributes,
+ ExWindowStationObjectType,
+ KernelMode,
+ NULL,
+ 0,
+ NULL,
+ (HANDLE*)hWinSta);
+
+ ExFreePoolWithTag(FullName.Buffer, TAG_STRING);
+
+ if(!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ DPRINT("Failed to reference window station %wZ PID: %d!\n", &WinSta, PsGetCurrentProcessId());
+ return Status;
+ }
+ }
+
+ if(hDesktop != NULL && *hDesktop == NULL)
+ {
+ if(!IntGetFullWindowStationName(&FullName, &WinSta, &Desktop))
+ {
+ NtClose(*hWinSta);
+ *hWinSta = NULL;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* open the desktop object */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &FullName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = ObOpenObjectByName(&ObjectAttributes,
+ ExDesktopObjectType,
+ KernelMode,
+ NULL,
+ 0,
+ NULL,
+ (HANDLE*)hDesktop);
+
+ ExFreePoolWithTag(FullName.Buffer, TAG_STRING);
+
+ if(!NT_SUCCESS(Status))
+ {
+ *hDesktop = NULL;
+ NtClose(*hWinSta);
+ *hWinSta = NULL;
+ SetLastNtError(Status);
+ DPRINT("Failed to reference desktop %wZ PID: %d!\n", &Desktop, PsGetCurrentProcessId());
+ return Status;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * IntValidateDesktopHandle
+ *
+ * Validates the desktop handle.
+ *
+ * Remarks
+ * If the function succeeds, the handle remains referenced. If the
+ * fucntion fails, last error is set.
+ */
+
+NTSTATUS FASTCALL
+IntValidateDesktopHandle(
+ HDESK Desktop,
+ KPROCESSOR_MODE AccessMode,
+ ACCESS_MASK DesiredAccess,
+ PDESKTOP *Object)
+{
+ NTSTATUS Status;
+
+ Status = ObReferenceObjectByHandle(
+ Desktop,
+ DesiredAccess,
+ ExDesktopObjectType,
+ AccessMode,
+ (PVOID*)Object,
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ SetLastNtError(Status);
+
+ return Status;
+}
+
+PDESKTOP FASTCALL
+IntGetActiveDesktop(VOID)
+{
+ return InputDesktop;
+}
+
+/*
+ * returns or creates a handle to the desktop object
+ */
+HDESK FASTCALL
+IntGetDesktopObjectHandle(PDESKTOP DesktopObject)
+{
+ NTSTATUS Status;
+ HDESK Ret;
+
+ ASSERT(DesktopObject);
+
+ if (!ObFindHandleForObject(PsGetCurrentProcess(),
+ DesktopObject,
+ ExDesktopObjectType,
+ NULL,
+ (PHANDLE)&Ret))
+ {
+ Status = ObOpenObjectByPointer(DesktopObject,
+ 0,
+ NULL,
+ 0,
+ ExDesktopObjectType,
+ UserMode,
+ (PHANDLE)&Ret);
+ if(!NT_SUCCESS(Status))
+ {
+ /* unable to create a handle */
+ DPRINT1("Unable to create a desktop handle\n");
+ return NULL;
+ }
+ }
+ else
+ {
+ DPRINT1("Got handle: %lx\n", Ret);
+ }
+
+ return Ret;
+}
+
+PUSER_MESSAGE_QUEUE FASTCALL
+IntGetFocusMessageQueue(VOID)
+{
+ PDESKTOP pdo = IntGetActiveDesktop();
+ if (!pdo)
+ {
+ DPRINT("No active desktop\n");
+ return(NULL);
+ }
+ return (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
+}
+
+VOID FASTCALL
+IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue)
+{
+ PUSER_MESSAGE_QUEUE Old;
+ PDESKTOP pdo = IntGetActiveDesktop();
+ if (!pdo)
+ {
+ DPRINT("No active desktop\n");
+ return;
+ }
+ if(NewQueue != NULL)
+ {
+ if(NewQueue->Desktop != NULL)
+ {
+ DPRINT("Message Queue already attached to another desktop!\n");
+ return;
+ }
+ IntReferenceMessageQueue(NewQueue);
+ (void)InterlockedExchangePointer((PVOID*)&NewQueue->Desktop, pdo);
+ }
+ Old = (PUSER_MESSAGE_QUEUE)InterlockedExchangePointer((PVOID*)&pdo->ActiveMessageQueue, NewQueue);
+ if(Old != NULL)
+ {
+ (void)InterlockedExchangePointer((PVOID*)&Old->Desktop, 0);
+ IntDereferenceMessageQueue(Old);
+ }
+}
+
+HWND FASTCALL IntGetDesktopWindow(VOID)
+{
+ PDESKTOP pdo = IntGetActiveDesktop();
+ if (!pdo)
+ {
+ DPRINT("No active desktop\n");
+ return NULL;
+ }
+ return pdo->DesktopWindow;
+}
+
+PWINDOW_OBJECT FASTCALL UserGetDesktopWindow(VOID)
+{
+ PDESKTOP pdo = IntGetActiveDesktop();
+
+ if (!pdo)
+ {
+ DPRINT("No active desktop\n");
+ return NULL;
+ }
+
+ return UserGetWindowObject(pdo->DesktopWindow);
+}
+
+HWND FASTCALL IntGetMessageWindow(VOID)
+{
+ PDESKTOP pdo = IntGetActiveDesktop();
+
+ if (!pdo)
+ {
+ DPRINT("No active desktop\n");
+ return NULL;
+ }
+ return pdo->spwndMessage->head.h;
+}
+
+HWND FASTCALL IntGetCurrentThreadDesktopWindow(VOID)
+{
+ PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+ PDESKTOP pdo = pti->rpdesk;
+ if (NULL == pdo)
+ {
+ DPRINT1("Thread doesn't have a desktop\n");
+ return NULL;
+ }
+ return pdo->DesktopWindow;
+}
+
+BOOL FASTCALL IntDesktopUpdatePerUserSettings(BOOL bEnable)
+{
+ if (bEnable)
+ {
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ NTSTATUS Status;
+
+ RtlZeroMemory(QueryTable, sizeof(QueryTable));
+
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ QueryTable[0].Name = L"PaintDesktopVersion";
+ QueryTable[0].EntryContext = &g_PaintDesktopVersion;
+
+ /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_USER,
+ L"Control Panel\\Desktop",
+ QueryTable, NULL, NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
+ Status);
+ g_PaintDesktopVersion = FALSE;
+ return FALSE;
+ }
+
+ DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion);
+
+ return TRUE;
+ }
+ else
+ {
+ g_PaintDesktopVersion = FALSE;
+ return TRUE;
+ }
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+HDC FASTCALL
+UserGetDesktopDC(ULONG DcType, BOOL EmptyDC, BOOL ValidatehWnd)
+{
+ PWINDOW_OBJECT DesktopObject = 0;
+ HDC DesktopHDC = 0;
+
+ if (DcType == DC_TYPE_DIRECT)
+ {
+ DesktopObject = UserGetDesktopWindow();
+ DesktopHDC = (HDC)UserGetWindowDC(DesktopObject);
+ }
+ else
+ {
+ HDEV hDev;
+ hDev = (HDEV)pPrimarySurface;
+ DesktopHDC = IntGdiCreateDisplayDC(hDev, DcType, EmptyDC);
+ }
+
+ return DesktopHDC;
+}
+
+VOID APIENTRY
+UserRedrawDesktop()
+{
+ PWINDOW_OBJECT Window = NULL;
+
+ Window = UserGetDesktopWindow();
+
+ IntInvalidateWindows( Window,
+ Window->hrgnUpdate,
+ RDW_FRAME |
+ RDW_ERASE |
+ RDW_INVALIDATE |
+ RDW_ALLCHILDREN);
+}
+
+
+NTSTATUS FASTCALL
+co_IntShowDesktop(PDESKTOP Desktop, ULONG Width, ULONG Height)
+{
+ CSR_API_MESSAGE Request;
+
+ Request.Type = MAKE_CSR_API(SHOW_DESKTOP, CSR_GUI);
+ Request.Data.ShowDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
+ Request.Data.ShowDesktopRequest.Width = Width;
+ Request.Data.ShowDesktopRequest.Height = Height;
+
+ return co_CsrNotify(&Request);
+}
+
+NTSTATUS FASTCALL
+IntHideDesktop(PDESKTOP Desktop)
+{
+#if 0
+ CSRSS_API_REQUEST Request;
+ CSRSS_API_REPLY Reply;
+
+ Request.Type = CSRSS_HIDE_DESKTOP;
+ Request.Data.HideDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
+
+ return NotifyCsrss(&Request, &Reply);
+#else
+
+ PWINDOW_OBJECT DesktopWindow;
+ PWND DesktopWnd;
+
+ DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow);
+ if (! DesktopWindow)
+ {
+ return ERROR_INVALID_WINDOW_HANDLE;
+ }
+ DesktopWnd = DesktopWindow->Wnd;
+ DesktopWnd->style &= ~WS_VISIBLE;
+
+ return STATUS_SUCCESS;
+#endif
+}
+
+
+
+
+static
+HWND* FASTCALL
+UserBuildShellHookHwndList(PDESKTOP Desktop)
+{
+ ULONG entries=0;
+ PSHELL_HOOK_WINDOW Current;
+ HWND* list;
+
+ /* fixme: if we save nb elements in desktop, we dont have to loop to find nb entries */
+ LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
+ entries++;
+
+ if (!entries) return NULL;
+
++ list = ExAllocatePoolWithTag(PagedPool, sizeof(HWND) * (entries + 1), USERTAG_WINDOWLIST); /* alloc one extra for nullterm */
+ if (list)
+ {
+ HWND* cursor = list;
+
+ LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
+ *cursor++ = Current->hWnd;
+
+ *cursor = NULL; /* nullterm list */
+ }
+
+ return list;
+}
+
+/*
+ * Send the Message to the windows registered for ShellHook
+ * notifications. The lParam contents depend on the Message. See
+ * MSDN for more details (RegisterShellHookWindow)
+ */
+VOID co_IntShellHookNotify(WPARAM Message, LPARAM lParam)
+{
+ PDESKTOP Desktop = IntGetActiveDesktop();
+ HWND* HwndList;
+
+ static UINT MsgType = 0;
+
+ if (!MsgType)
+ {
+
+ /* Too bad, this doesn't work.*/
+#if 0
+ UNICODE_STRING Str;
+ RtlInitUnicodeString(&Str, L"SHELLHOOK");
+ MsgType = UserRegisterWindowMessage(&Str);
+#endif
+
+ MsgType = IntAddAtom(L"SHELLHOOK");
+
+ DPRINT("MsgType = %x\n", MsgType);
+ if (!MsgType)
+ DPRINT1("LastError: %x\n", GetLastNtError());
+ }
+
+ if (!Desktop)
+ {
+ DPRINT("IntShellHookNotify: No desktop!\n");
+ return;
+ }
+
+ HwndList = UserBuildShellHookHwndList(Desktop);
+ if (HwndList)
+ {
+ HWND* cursor = HwndList;
+
+ for (; *cursor; cursor++)
+ {
+ DPRINT("Sending notify\n");
+ co_IntPostOrSendMessage(*cursor,
+ MsgType,
+ Message,
+ lParam);
+ }
+
+ ExFreePool(HwndList);
+ }
+
+}
+
+/*
+ * Add the window to the ShellHookWindows list. The windows
+ * on that list get notifications that are important to shell
+ * type applications.
+ *
+ * TODO: Validate the window? I'm not sure if sending these messages to
+ * an unsuspecting application that is not your own is a nice thing to do.
+ */
+BOOL IntRegisterShellHookWindow(HWND hWnd)
+{
+ PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+ PDESKTOP Desktop = pti->rpdesk;
+ PSHELL_HOOK_WINDOW Entry;
+
+ DPRINT("IntRegisterShellHookWindow\n");
+
+ /* First deregister the window, so we can be sure it's never twice in the
+ * list.
+ */
+ IntDeRegisterShellHookWindow(hWnd);
+
+ Entry = ExAllocatePoolWithTag(PagedPool,
+ sizeof(SHELL_HOOK_WINDOW),
+ TAG_WINSTA);
+
+ if (!Entry)
+ return FALSE;
+
+ Entry->hWnd = hWnd;
+
+ InsertTailList(&Desktop->ShellHookWindows, &Entry->ListEntry);
+
+ return TRUE;
+}
+
+/*
+ * Remove the window from the ShellHookWindows list. The windows
+ * on that list get notifications that are important to shell
+ * type applications.
+ */
+BOOL IntDeRegisterShellHookWindow(HWND hWnd)
+{
+ PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+ PDESKTOP Desktop = pti->rpdesk;
+ PSHELL_HOOK_WINDOW Current;
+
+ LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
+ {
+ if (Current->hWnd == hWnd)
+ {
+ RemoveEntryList(&Current->ListEntry);
+ ExFreePool(Current);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static VOID
+IntFreeDesktopHeap(IN OUT PDESKTOP Desktop)
+{
+ if (Desktop->hsectionDesktop != NULL)
+ {
+ ObDereferenceObject(Desktop->hsectionDesktop);
+ Desktop->hsectionDesktop = NULL;
+ }
+}
+/* SYSCALLS *******************************************************************/
+
+/*
+ * NtUserCreateDesktop
+ *
+ * Creates a new desktop.
+ *
+ * Parameters
+ * poaAttribs
+ * Object Attributes.
+ *
+ * lpszDesktopDevice
+ * Name of the device.
+ *
+ * pDeviceMode
+ * Device Mode.
+ *
+ * dwFlags
+ * Interaction flags.
+ *
+ * dwDesiredAccess
+ * Requested type of access.
+ *
+ *
+ * Return Value
+ * If the function succeeds, the return value is a handle to the newly
+ * created desktop. If the specified desktop already exists, the function
+ * succeeds and returns a handle to the existing desktop. When you are
+ * finished using the handle, call the CloseDesktop function to close it.
+ * If the function fails, the return value is NULL.
+ *
+ * Status
+ * @implemented
+ */
+
+HDESK APIENTRY
+NtUserCreateDesktop(
+ POBJECT_ATTRIBUTES poa,
+ PUNICODE_STRING lpszDesktopDevice,
+ LPDEVMODEW lpdmw,
+ DWORD dwFlags,
+ ACCESS_MASK dwDesiredAccess)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PTHREADINFO W32Thread;
+ PWINSTATION_OBJECT WinStaObject;
+ PDESKTOP DesktopObject;
+ UNICODE_STRING DesktopName;
+ NTSTATUS Status = STATUS_SUCCESS;
+ HDESK Desktop;
+ CSR_API_MESSAGE Request;
+ PVOID DesktopHeapSystemBase = NULL;
+ SIZE_T DesktopInfoSize;
+ UNICODE_STRING SafeDesktopName;
+ ULONG DummyContext;
+ ULONG_PTR HeapSize = 4 * 1024 * 1024; /* FIXME */
+ HWINSTA hWindowStation = NULL ;
+ PUNICODE_STRING lpszDesktopName = NULL;
+ UNICODE_STRING ClassName, MenuName;
+ LARGE_STRING WindowName;
+ PWND pWnd = NULL;
+ CREATESTRUCTW Cs;
+ DECLARE_RETURN(HDESK);
+
+ DPRINT("Enter NtUserCreateDesktop: %wZ\n", lpszDesktopName);
+ UserEnterExclusive();
+
+ _SEH2_TRY
+ {
+ ProbeForRead( poa,
+ sizeof(OBJECT_ATTRIBUTES),
+ 1);
+
+ hWindowStation = poa->RootDirectory;
+ lpszDesktopName = poa->ObjectName;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status =_SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed reading Object Attributes from user space.\n");
+ SetLastNtError(Status);
+ RETURN( NULL);
+ }
+
+ Status = IntValidateWindowStationHandle(
+ hWindowStation,
+ KernelMode,
+ 0, /* FIXME - WINSTA_CREATEDESKTOP */
+ &WinStaObject);
+
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
+ hWindowStation, lpszDesktopName);
+ SetLastNtError(Status);
+ RETURN( NULL);
+ }
+ if(lpszDesktopName != NULL)
+ {
+ Status = IntSafeCopyUnicodeString(&SafeDesktopName, lpszDesktopName);
+ if(!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( NULL);
+ }
+ }
+ else
+ {
+ RtlInitUnicodeString(&SafeDesktopName, NULL);
+ }
+
+ if (! IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
+ &SafeDesktopName))
+ {
+ SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
+ ObDereferenceObject(WinStaObject);
+ if (lpszDesktopName)
+ ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
+ RETURN( NULL);
+ }
+ if (lpszDesktopName)
+ ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
+ ObDereferenceObject(WinStaObject);
+
+ /*
+ * Try to open already existing desktop
+ */
+
+ DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
+
+ /* Initialize ObjectAttributes for the desktop object */
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &DesktopName,
+ 0,
+ NULL,
+ NULL);
+
+ Status = ObOpenObjectByName(
+ &ObjectAttributes,
+ ExDesktopObjectType,
+ KernelMode,
+ NULL,
+ dwDesiredAccess,
+ (PVOID)&DummyContext,
+ (HANDLE*)&Desktop);
+ if (!NT_SUCCESS(Status)) RETURN(NULL);
+ if (Status == STATUS_OBJECT_NAME_EXISTS)
+ {
+ ExFreePoolWithTag(DesktopName.Buffer, TAG_STRING);
+ RETURN( Desktop);
+ }
+
+ /* Reference the desktop */
+ Status = ObReferenceObjectByHandle(Desktop,
+ 0,
+ ExDesktopObjectType,
+ KernelMode,
+ (PVOID)&DesktopObject,
+ NULL);
+ if (!NT_SUCCESS(Status)) RETURN(NULL);
+
+ DesktopObject->hsectionDesktop = NULL;
+ DesktopObject->pheapDesktop = UserCreateHeap(&DesktopObject->hsectionDesktop,
+ &DesktopHeapSystemBase,
+ HeapSize);
+ if (DesktopObject->pheapDesktop == NULL)
+ {
+ ObDereferenceObject(DesktopObject);
+ DPRINT1("Failed to create desktop heap!\n");
+ RETURN(NULL);
+ }
+
+ DesktopInfoSize = FIELD_OFFSET(DESKTOPINFO,
+ szDesktopName[(lpszDesktopName->Length / sizeof(WCHAR)) + 1]);
+
+ DesktopObject->pDeskInfo = RtlAllocateHeap(DesktopObject->pheapDesktop,
+ HEAP_NO_SERIALIZE,
+ DesktopInfoSize);
+
+ if (DesktopObject->pDeskInfo == NULL)
+ {
+ ObDereferenceObject(DesktopObject);
+ DPRINT1("Failed to create the DESKTOP structure!\n");
+ RETURN(NULL);
+ }
+
+ RtlZeroMemory(DesktopObject->pDeskInfo,
+ DesktopInfoSize);
+
+ DesktopObject->pDeskInfo->pvDesktopBase = DesktopHeapSystemBase;
+ DesktopObject->pDeskInfo->pvDesktopLimit = (PVOID)((ULONG_PTR)DesktopHeapSystemBase + HeapSize);
+ RtlCopyMemory(DesktopObject->pDeskInfo->szDesktopName,
+ lpszDesktopName->Buffer,
+ lpszDesktopName->Length);
+
+ /* Initialize some local (to win32k) desktop state. */
+ InitializeListHead(&DesktopObject->PtiList);
+ DesktopObject->ActiveMessageQueue = NULL;
+ ExFreePoolWithTag(DesktopName.Buffer, TAG_STRING);
+
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to create desktop handle\n");
+ SetLastNtError(Status);
+ RETURN( NULL);
+ }
+
+ /*
+ * Create a handle for CSRSS and notify CSRSS for Creating Desktop Window.
+ *
+ * Honestly, I believe this is a cleverly written hack that allowed ReactOS
+ * to function at the beginning of the project by ramroding the GUI into
+ * operation and making the desktop window work from user space.
+ * (jt)
+ */
+ Request.Type = MAKE_CSR_API(CREATE_DESKTOP, CSR_GUI);
+ Status = CsrInsertObject(Desktop,
+ GENERIC_ALL,
+ (HANDLE*)&Request.Data.CreateDesktopRequest.DesktopHandle);
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to create desktop handle for CSRSS\n");
+ ZwClose(Desktop);
+ SetLastNtError(Status);
+ RETURN( NULL);
+ }
+
+ Status = co_CsrNotify(&Request);
+ if (! NT_SUCCESS(Status))
+ {
+ CsrCloseHandle(Request.Data.CreateDesktopRequest.DesktopHandle);
+ DPRINT1("Failed to notify CSRSS about new desktop\n");
+ ZwClose(Desktop);
+ SetLastNtError(Status);
+ RETURN( NULL);
+ }
+
+ W32Thread = PsGetCurrentThreadWin32Thread();
+
+ if (!W32Thread->rpdesk) IntSetThreadDesktop(DesktopObject,FALSE);
+
+ /*
+ Based on wine/server/window.c in get_desktop_window.
+ */
+
+ ClassName.Buffer = ((PWSTR)((ULONG_PTR)(WORD)(gpsi->atomSysClass[ICLS_HWNDMESSAGE])));
+ ClassName.Length = 0;
+ RtlZeroMemory(&MenuName, sizeof(MenuName));
+ RtlZeroMemory(&WindowName, sizeof(WindowName));
+
+ RtlZeroMemory(&Cs, sizeof(Cs));
+ Cs.cx = Cs.cy = 100;
+ Cs.style = WS_POPUP|WS_CLIPCHILDREN;
+ Cs.hInstance = hModClient;
+ Cs.lpszName = (LPCWSTR) &WindowName;
+ Cs.lpszClass = (LPCWSTR) &ClassName;
+
+ pWnd = co_UserCreateWindowEx(&Cs, &ClassName, &WindowName);
+ if (!pWnd)
+ {
+ DPRINT1("Failed to create Message window handle\n");
+ }
+ else
+ {
+ DesktopObject->spwndMessage = pWnd;
+ }
+
+ RETURN( Desktop);
+
+CLEANUP:
+ DPRINT("Leave NtUserCreateDesktop, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ * NtUserOpenDesktop
+ *
+ * Opens an existing desktop.
+ *
+ * Parameters
+ * lpszDesktopName
+ * Name of the existing desktop.
+ *
+ * dwFlags
+ * Interaction flags.
+ *
+ * dwDesiredAccess
+ * Requested type of access.
+ *
+ * Return Value
+ * Handle to the desktop or zero on failure.
+ *
+ * Status
+ * @implemented
+ */
+
+HDESK APIENTRY
+NtUserOpenDesktop(
+ PUNICODE_STRING lpszDesktopName,
+ DWORD dwFlags,
+ ACCESS_MASK dwDesiredAccess)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HWINSTA WinSta;
+ PWINSTATION_OBJECT WinStaObject;
+ UNICODE_STRING DesktopName;
+ UNICODE_STRING SafeDesktopName;
+ NTSTATUS Status;
+ HDESK Desktop;
+ BOOL Result;
+ DECLARE_RETURN(HDESK);
+
+ DPRINT("Enter NtUserOpenDesktop: %wZ\n", lpszDesktopName);
+ UserEnterExclusive();
+
+ /*
+ * Validate the window station handle and compose the fully
+ * qualified desktop name
+ */
+
+ WinSta = UserGetProcessWindowStation();
+ Status = IntValidateWindowStationHandle(
+ WinSta,
+ KernelMode,
+ 0,
+ &WinStaObject);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed validation of window station handle (0x%X)\n", WinSta);
+ SetLastNtError(Status);
+ RETURN( 0);
+ }
+
+ if(lpszDesktopName != NULL)
+ {
+ Status = IntSafeCopyUnicodeString(&SafeDesktopName, lpszDesktopName);
+ if(!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( NULL);
+ }
+ }
+ else
+ {
+ RtlInitUnicodeString(&SafeDesktopName, NULL);
+ }
+
+ Result = IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
+ &SafeDesktopName);
+
+ if (lpszDesktopName)
+ ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
+ ObDereferenceObject(WinStaObject);
+
+
+ if (!Result)
+ {
+ SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
+ RETURN( 0);
+ }
+
+
+ DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
+
+ /* Initialize ObjectAttributes for the desktop object */
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &DesktopName,
+ 0,
+ NULL,
+ NULL);
+
+ Status = ObOpenObjectByName(
+ &ObjectAttributes,
+ ExDesktopObjectType,
+ KernelMode,
+ NULL,
+ dwDesiredAccess,
+ NULL,
+ (HANDLE*)&Desktop);
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ ExFreePool(DesktopName.Buffer);
+ RETURN( 0);
+ }
+
+ DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
+ ExFreePool(DesktopName.Buffer);
+
+ RETURN( Desktop);
+
+CLEANUP:
+ DPRINT("Leave NtUserOpenDesktop, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ * NtUserOpenInputDesktop
+ *
+ * Opens the input (interactive) desktop.
+ *
+ * Parameters
+ * dwFlags
+ * Interaction flags.
+ *
+ * fInherit
+ * Inheritance option.
+ *
+ * dwDesiredAccess
+ * Requested type of access.
+ *
+ * Return Value
+ * Handle to the input desktop or zero on failure.
+ *
+ * Status
+ * @implemented
+ */
+
+HDESK APIENTRY
+NtUserOpenInputDesktop(
+ DWORD dwFlags,
+ BOOL fInherit,
+ ACCESS_MASK dwDesiredAccess)
+{
+ PDESKTOP Object;
+ NTSTATUS Status;
+ HDESK Desktop;
+ DECLARE_RETURN(HDESK);
+
+ DPRINT("Enter NtUserOpenInputDesktop\n");
+ UserEnterExclusive();
+
+ DPRINT("About to open input desktop\n");
+
+ /* Get a pointer to the desktop object */
+
+ Status = IntValidateDesktopHandle(
+ InputDesktopHandle,
+ UserMode,
+ 0,
+ &Object);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop);
+ RETURN((HDESK)0);
+ }
+
+ /* Create a new handle to the object */
+
+ Status = ObOpenObjectByPointer(
+ Object,
+ 0,
+ NULL,
+ dwDesiredAccess,
+ ExDesktopObjectType,
+ UserMode,
+ (HANDLE*)&Desktop);
+
+ ObDereferenceObject(Object);
+
+ if (NT_SUCCESS(Status))
+ {
+ DPRINT("Successfully opened input desktop\n");
+ RETURN((HDESK)Desktop);
+ }
+
+ SetLastNtError(Status);
+ RETURN((HDESK)0);
+
+CLEANUP:
+ DPRINT("Leave NtUserOpenInputDesktop, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ * NtUserCloseDesktop
+ *
+ * Closes a desktop handle.
+ *
+ * Parameters
+ * hDesktop
+ * Handle to the desktop.
+ *
+ * Return Value
+ * Status
+ *
+ * Remarks
+ * The desktop handle can be created with NtUserCreateDesktop or
+ * NtUserOpenDesktop. This function will fail if any thread in the calling
+ * process is using the specified desktop handle or if the handle refers
+ * to the initial desktop of the calling process.
+ *
+ * Status
+ * @implemented
+ */
+
+BOOL APIENTRY
+NtUserCloseDesktop(HDESK hDesktop)
+{
+ PDESKTOP Object;
+ NTSTATUS Status;
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserCloseDesktop\n");
+ UserEnterExclusive();
+
+ DPRINT("About to close desktop handle (0x%X)\n", hDesktop);
+
+ Status = IntValidateDesktopHandle(
+ hDesktop,
+ UserMode,
+ 0,
+ &Object);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
+ RETURN(FALSE);
+ }
+
+ ObDereferenceObject(Object);
+
+ DPRINT("Closing desktop handle (0x%X)\n", hDesktop);
+
+ Status = ZwClose(hDesktop);
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN(FALSE);
+ }
+
+ RETURN(TRUE);
+
+CLEANUP:
+ DPRINT("Leave NtUserCloseDesktop, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+
+
+
+/*
+ * NtUserPaintDesktop
+ *
+ * The NtUserPaintDesktop function fills the clipping region in the
+ * specified device context with the desktop pattern or wallpaper. The
+ * function is provided primarily for shell desktops.
+ *
+ * Parameters
+ * hDC
+ * Handle to the device context.
+ *
+ * Status
+ * @implemented
+ */
+
+BOOL APIENTRY
+NtUserPaintDesktop(HDC hDC)
+{
+ RECTL Rect;
+ HBRUSH DesktopBrush, PreviousBrush;
+ HWND hWndDesktop;
+ BOOL doPatBlt = TRUE;
+ PWINDOW_OBJECT WndDesktop;
+ int len;
+ COLORREF color_old;
+ UINT align_old;
+ int mode_old;
+ PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+ PWINSTATION_OBJECT WinSta = pti->rpdesk->rpwinstaParent;
+ DECLARE_RETURN(BOOL);
+
+ UserEnterExclusive();
+ DPRINT("Enter NtUserPaintDesktop\n");
+
+ GdiGetClipBox(hDC, &Rect);
+
+ hWndDesktop = IntGetDesktopWindow();
+
+ WndDesktop = UserGetWindowObject(hWndDesktop);
+ if (!WndDesktop)
+ {
+ RETURN(FALSE);
+ }
+
+ DesktopBrush = (HBRUSH)WndDesktop->Wnd->pcls->hbrBackground;
+
+
+ /*
+ * Paint desktop background
+ */
+
+ if (WinSta->hbmWallpaper != NULL)
+ {
+ PWINDOW_OBJECT DeskWin;
+
+ DeskWin = UserGetWindowObject(hWndDesktop);
+
+ if (DeskWin)
+ {
+ SIZE sz;
+ int x, y;
+ HDC hWallpaperDC;
+
+ sz.cx = DeskWin->Wnd->rcWindow.right - DeskWin->Wnd->rcWindow.left;
+ sz.cy = DeskWin->Wnd->rcWindow.bottom - DeskWin->Wnd->rcWindow.top;
+
+ if (WinSta->WallpaperMode == wmStretch ||
+ WinSta->WallpaperMode == wmTile)
+ {
+ x = 0;
+ y = 0;
+ }
+ else
+ {
+ /* Find the upper left corner, can be negtive if the bitmap is bigger then the screen */
+ x = (sz.cx / 2) - (WinSta->cxWallpaper / 2);
+ y = (sz.cy / 2) - (WinSta->cyWallpaper / 2);
+ }
+
+ hWallpaperDC = NtGdiCreateCompatibleDC(hDC);
+ if(hWallpaperDC != NULL)
+ {
+ HBITMAP hOldBitmap;
+
+ /* fill in the area that the bitmap is not going to cover */
+ if (x > 0 || y > 0)
+ {
+ /* FIXME - clip out the bitmap
+ can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
+ once we support DSTINVERT */
+ PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
+ NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
+ NtGdiSelectBrush(hDC, PreviousBrush);
+ }
+
+ /*Do not fill the background after it is painted no matter the size of the picture */
+ doPatBlt = FALSE;
+
+ hOldBitmap = NtGdiSelectBitmap(hWallpaperDC, WinSta->hbmWallpaper);
+
+ if (WinSta->WallpaperMode == wmStretch)
+ {
+ if(Rect.right && Rect.bottom)
+ NtGdiStretchBlt(hDC,
+ x,
+ y,
+ sz.cx,
+ sz.cy,
+ hWallpaperDC,
+ 0,
+ 0,
+ WinSta->cxWallpaper,
+ WinSta->cyWallpaper,
+ SRCCOPY,
+ 0);
+
+ }
+ else if (WinSta->WallpaperMode == wmTile)
+ {
+ /* paint the bitmap across the screen then down */
+ for(y = 0; y < Rect.bottom; y += WinSta->cyWallpaper)
+ {
+ for(x = 0; x < Rect.right; x += WinSta->cxWallpaper)
+ {
+ NtGdiBitBlt(hDC,
+ x,
+ y,
+ WinSta->cxWallpaper,
+ WinSta->cyWallpaper,
+ hWallpaperDC,
+ 0,
+ 0,
+ SRCCOPY,
+ 0,
+ 0);
+ }
+ }
+ }
+ else
+ {
+ NtGdiBitBlt(hDC,
+ x,
+ y,
+ WinSta->cxWallpaper,
+ WinSta->cyWallpaper,
+ hWallpaperDC,
+ 0,
+ 0,
+ SRCCOPY,
+ 0,
+ 0);
+ }
+ NtGdiSelectBitmap(hWallpaperDC, hOldBitmap);
+ NtGdiDeleteObjectApp(hWallpaperDC);
+ }
+ }
+ }
+
+ /* Back ground is set to none, clear the screen */
+ if (doPatBlt)
+ {
+ PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
+ NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
+ NtGdiSelectBrush(hDC, PreviousBrush);
+ }
+
+ /*
+ * Display system version on the desktop background
+ */
+
+ if (g_PaintDesktopVersion)
+ {
+ static WCHAR s_wszVersion[256] = {0};
+ RECTL rect;
+
+ if (*s_wszVersion)
+ {
+ len = wcslen(s_wszVersion);
+ }
+ else
+ {
+ len = GetSystemVersionString(s_wszVersion);
+ }
+
+ if (len)
+ {
+ if (!UserSystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0))
+ {
+ rect.right = UserGetSystemMetrics(SM_CXSCREEN);
+ rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
+ }
+
+ color_old = IntGdiSetTextColor(hDC, RGB(255,255,255));
+ align_old = IntGdiSetTextAlign(hDC, TA_RIGHT);
+ mode_old = IntGdiSetBkMode(hDC, TRANSPARENT);
+
+ GreExtTextOutW(hDC, rect.right-16, rect.bottom-48, 0, NULL, s_wszVersion, len, NULL, 0);
+
+ IntGdiSetBkMode(hDC, mode_old);
+ IntGdiSetTextAlign(hDC, align_old);
+ IntGdiSetTextColor(hDC, color_old);
+ }
+ }
+
+ RETURN(TRUE);
+
+CLEANUP:
+ DPRINT("Leave NtUserPaintDesktop, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+
+/*
+ * NtUserSwitchDesktop
+ *
+ * Sets the current input (interactive) desktop.
+ *
+ * Parameters
+ * hDesktop
+ * Handle to desktop.
+ *
+ * Return Value
+ * Status
+ *
+ * Status
+ * @unimplemented
+ */
+
+BOOL APIENTRY
+NtUserSwitchDesktop(HDESK hDesktop)
+{
+ PDESKTOP DesktopObject;
+ NTSTATUS Status;
+ DECLARE_RETURN(BOOL);
+
+ UserEnterExclusive();
+ DPRINT("Enter NtUserSwitchDesktop\n");
+
+ DPRINT("About to switch desktop (0x%X)\n", hDesktop);
+
+ Status = IntValidateDesktopHandle(
+ hDesktop,
+ UserMode,
+ 0,
+ &DesktopObject);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
+ RETURN(FALSE);
+ }
+
+ /*
+ * Don't allow applications switch the desktop if it's locked, unless the caller
+ * is the logon application itself
+ */
+ if((DesktopObject->rpwinstaParent->Flags & WSS_LOCKED) &&
+ LogonProcess != NULL && LogonProcess != PsGetCurrentProcessWin32Process())
+ {
+ ObDereferenceObject(DesktopObject);
+ DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop);
+ RETURN(FALSE);
+ }
+
+ if(DesktopObject->rpwinstaParent != InputWindowStation)
+ {
+ ObDereferenceObject(DesktopObject);
+ DPRINT1("Switching desktop 0x%x denied because desktop doesn't belong to the interactive winsta!\n", hDesktop);
+ RETURN(FALSE);
+ }
+
+ /* FIXME: Fail if the process is associated with a secured
+ desktop such as Winlogon or Screen-Saver */
+ /* FIXME: Connect to input device */
+
+ /* Set the active desktop in the desktop's window station. */
+ InputWindowStation->ActiveDesktop = DesktopObject;
+
+ /* Set the global state. */
+ InputDesktop = DesktopObject;
+ InputDesktopHandle = hDesktop;
+
+ ObDereferenceObject(DesktopObject);
+
+ RETURN(TRUE);
+
+CLEANUP:
+ DPRINT("Leave NtUserSwitchDesktop, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ * NtUserResolveDesktopForWOW
+ *
+ * Status
+ * @unimplemented
+ */
+
+DWORD APIENTRY
+NtUserResolveDesktopForWOW(DWORD Unknown0)
+{
+ UNIMPLEMENTED
+ return 0;
+}
+
+/*
+ * NtUserGetThreadDesktop
+ *
+ * Status
+ * @implemented
+ */
+
+HDESK APIENTRY
+NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
+{
+ NTSTATUS Status;
+ PETHREAD Thread;
+ PDESKTOP DesktopObject;
+ HDESK Ret, hThreadDesktop;
+ OBJECT_HANDLE_INFORMATION HandleInformation;
+ DECLARE_RETURN(HDESK);
+
+ UserEnterExclusive();
+ DPRINT("Enter NtUserGetThreadDesktop\n");
+
+ if(!dwThreadId)
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ RETURN(0);
+ }
+
+ Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &Thread);
+ if(!NT_SUCCESS(Status))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ RETURN(0);
+ }
+
+ if(Thread->ThreadsProcess == PsGetCurrentProcess())
+ {
+ /* just return the handle, we queried the desktop handle of a thread running
+ in the same context */
+ Ret = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk;
+ ObDereferenceObject(Thread);
+ RETURN(Ret);
+ }
+
+ /* get the desktop handle and the desktop of the thread */
+ if(!(hThreadDesktop = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk) ||
+ !(DesktopObject = ((PTHREADINFO)Thread->Tcb.Win32Thread)->rpdesk))
+ {
+ ObDereferenceObject(Thread);
+ DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId);
+ RETURN(NULL);
+ }
+
+ /* we could just use DesktopObject instead of looking up the handle, but latter
+ may be a bit safer (e.g. when the desktop is being destroyed */
+ /* switch into the context of the thread we're trying to get the desktop from,
+ so we can use the handle */
+ KeAttachProcess(&Thread->ThreadsProcess->Pcb);
+ Status = ObReferenceObjectByHandle(hThreadDesktop,
+ GENERIC_ALL,
+ ExDesktopObjectType,
+ UserMode,
+ (PVOID*)&DesktopObject,
+ &HandleInformation);
+ KeDetachProcess();
+
+ /* the handle couldn't be found, there's nothing to get... */
+ if(!NT_SUCCESS(Status))
+ {
+ ObDereferenceObject(Thread);
+ RETURN(NULL);
+ }
+
+ /* lookup our handle table if we can find a handle to the desktop object,
+ if not, create one */
+ Ret = IntGetDesktopObjectHandle(DesktopObject);
+
+ /* all done, we got a valid handle to the desktop */
+ ObDereferenceObject(DesktopObject);
+ ObDereferenceObject(Thread);
+ RETURN(Ret);
+
+CLEANUP:
+ DPRINT("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+static NTSTATUS
+IntUnmapDesktopView(IN PDESKTOP DesktopObject)
+{
+ PTHREADINFO ti;
+ PPROCESSINFO CurrentWin32Process;
+ PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ TRACE("DO %p\n");
+
+ CurrentWin32Process = PsGetCurrentProcessWin32Process();
+ PrevLink = &CurrentWin32Process->HeapMappings.Next;
+
+ /* unmap if we're the last thread using the desktop */
+ HeapMapping = *PrevLink;
+ while (HeapMapping != NULL)
+ {
+ if (HeapMapping->KernelMapping == (PVOID)DesktopObject->pheapDesktop)
+ {
+ if (--HeapMapping->Count == 0)
+ {
+ *PrevLink = HeapMapping->Next;
+
+ Status = MmUnmapViewOfSection(PsGetCurrentProcess(),
+ HeapMapping->UserMapping);
+
+ ObDereferenceObject(DesktopObject);
+
+ UserHeapFree(HeapMapping);
+ break;
+ }
+ }
+
+ PrevLink = &HeapMapping->Next;
+ HeapMapping = HeapMapping->Next;
+ }
+
+ ti = GetW32ThreadInfo();
+ if (ti != NULL)
+ {
+ GetWin32ClientInfo()->pDeskInfo = NULL;
+ }
+ GetWin32ClientInfo()->ulClientDelta = 0;
+
+ return Status;
+}
+
+static NTSTATUS
+IntMapDesktopView(IN PDESKTOP DesktopObject)
+{
+ PTHREADINFO ti;
+ PPROCESSINFO CurrentWin32Process;
+ PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
+ PVOID UserBase = NULL;
+ SIZE_T ViewSize = 0;
+ LARGE_INTEGER Offset;
+ NTSTATUS Status;
+
+ CurrentWin32Process = PsGetCurrentProcessWin32Process();
+ PrevLink = &CurrentWin32Process->HeapMappings.Next;
+
+ /* find out if another thread already mapped the desktop heap */
+ HeapMapping = *PrevLink;
+ while (HeapMapping != NULL)
+ {
+ if (HeapMapping->KernelMapping == (PVOID)DesktopObject->pheapDesktop)
+ {
+ HeapMapping->Count++;
+ return STATUS_SUCCESS;
+ }
+
+ PrevLink = &HeapMapping->Next;
+ HeapMapping = HeapMapping->Next;
+ }
+
+ /* we're the first, map the heap */
+ DPRINT("Noone mapped the desktop heap %p yet, so - map it!\n", DesktopObject->pheapDesktop);
+ Offset.QuadPart = 0;
+ Status = MmMapViewOfSection(DesktopObject->hsectionDesktop,
+ PsGetCurrentProcess(),
+ &UserBase,
+ 0,
+ 0,
+ &Offset,
+ &ViewSize,
+ ViewUnmap,
+ SEC_NO_CHANGE,
+ PAGE_EXECUTE_READ); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to map desktop\n");
+ return Status;
+ }
+
+ /* add the mapping */
+ HeapMapping = UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING));
+ if (HeapMapping == NULL)
+ {
+ MmUnmapViewOfSection(PsGetCurrentProcess(),
+ UserBase);
+ DPRINT1("UserHeapAlloc() failed!\n");
+ return STATUS_NO_MEMORY;
+ }
+
+ HeapMapping->Next = NULL;
+ HeapMapping->KernelMapping = (PVOID)DesktopObject->pheapDesktop;
+ HeapMapping->UserMapping = UserBase;
+ HeapMapping->Limit = ViewSize;
+ HeapMapping->Count = 1;
+ *PrevLink = HeapMapping;
+
+ ObReferenceObject(DesktopObject);
+
+ /* create a W32THREADINFO structure if not already done, or update it */
+ ti = GetW32ThreadInfo();
+ GetWin32ClientInfo()->ulClientDelta = DesktopHeapGetUserDelta();
+ if (ti != NULL)
+ {
+ if (GetWin32ClientInfo()->pDeskInfo == NULL)
+ {
+ GetWin32ClientInfo()->pDeskInfo =
+ (PVOID)((ULONG_PTR)DesktopObject->pDeskInfo -
+ GetWin32ClientInfo()->ulClientDelta);
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+BOOL
+IntSetThreadDesktop(IN PDESKTOP DesktopObject,
+ IN BOOL FreeOnFailure)
+{
+ PDESKTOP OldDesktop;
+ PTHREADINFO W32Thread;
+ NTSTATUS Status;
+ BOOL MapHeap;
+
+ DPRINT("IntSetThreadDesktop() DO=%p, FOF=%d\n", DesktopObject, FreeOnFailure);
+ MapHeap = (PsGetCurrentProcess() != PsInitialSystemProcess);
+ W32Thread = PsGetCurrentThreadWin32Thread();
+
+ if (W32Thread->rpdesk != DesktopObject)
+ {
+ OldDesktop = W32Thread->rpdesk;
+
+ if (!IsListEmpty(&W32Thread->WindowListHead))
+ {
+ DPRINT1("Attempted to change thread desktop although the thread has windows!\n");
+ SetLastWin32Error(ERROR_BUSY);
+ return FALSE;
+ }
+
+ W32Thread->rpdesk = DesktopObject;
+
+ if (MapHeap && DesktopObject != NULL)
+ {
+ Status = IntMapDesktopView(DesktopObject);
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ return FALSE;
+ }
+ }
+
+ /* Hack for system threads */
+ if (NtCurrentTeb())
+ {
+ PCLIENTINFO pci = GetWin32ClientInfo();
+ pci->ulClientDelta = DesktopHeapGetUserDelta();
+ if (DesktopObject)
+ {
+ pci->pDeskInfo = (PVOID)((ULONG_PTR)DesktopObject->pDeskInfo - pci->ulClientDelta);
+ }
+ }
+
+ if (OldDesktop != NULL &&
+ !IntCheckProcessDesktopClasses(OldDesktop,
+ FreeOnFailure))
+ {
+ DPRINT1("Failed to move process classes to shared heap!\n");
+
+ /* failed to move desktop classes to the shared heap,
+ unmap the view and return the error */
+ if (MapHeap && DesktopObject != NULL)
+ IntUnmapDesktopView(DesktopObject);
+
+ return FALSE;
+ }
+
+ /* Remove the thread from the old desktop's list */
+ RemoveEntryList(&W32Thread->PtiLink);
+
+ if (DesktopObject != NULL)
+ {
+ ObReferenceObject(DesktopObject);
+ /* Insert into new desktop's list */
+ InsertTailList(&DesktopObject->PtiList, &W32Thread->PtiLink);
+ }
+
+ if (OldDesktop != NULL)
+ {
+ if (MapHeap)
+ {
+ IntUnmapDesktopView(OldDesktop);
+ }
+
+ ObDereferenceObject(OldDesktop);
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * NtUserSetThreadDesktop
+ *
+ * Status
+ * @implemented
+ */
+
+BOOL APIENTRY
+NtUserSetThreadDesktop(HDESK hDesktop)
+{
+ PDESKTOP DesktopObject;
+ NTSTATUS Status;
+ DECLARE_RETURN(BOOL);
+
+ UserEnterExclusive();
+ DPRINT("Enter NtUserSetThreadDesktop\n");
+
+ /* Validate the new desktop. */
+ Status = IntValidateDesktopHandle(
+ hDesktop,
+ UserMode,
+ 0,
+ &DesktopObject);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
+ RETURN(FALSE);
+ }
+
+ /* FIXME: Should check here to see if the thread has any windows. */
+
+ if (!IntSetThreadDesktop(DesktopObject,
+ FALSE))
+ {
+ RETURN(FALSE);
+ }
+
+ RETURN(TRUE);
+
+CLEANUP:
+ DPRINT("Leave NtUserSetThreadDesktop, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/* EOF */
--- /dev/null
- safeHMonitorList = ExAllocatePool(PagedPool, sizeof (HMONITOR) * listSize);
+/*
+ * ReactOS W32 Subsystem
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 ReactOS Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: Monitor support
+ * FILE: subsys/win32k/ntuser/monitor.c
+ * PROGRAMER: Anich Gregor (blight@blight.eu.org)
+ * REVISION HISTORY:
+ * 26-02-2004 Created
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <win32k.h>
+
+/* FIXME: find include file for these */
+#define MONITORINFOF_PRIMARY 1
+#define MONITOR_DEFAULTTONULL 0
+#define MONITOR_DEFAULTTOPRIMARY 1
+#define MONITOR_DEFAULTTONEAREST 2
+
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS *******************************************************************/
+
+/* list of monitors */
+static PMONITOR gMonitorList = NULL;
+
+/* INITALIZATION FUNCTIONS ****************************************************/
+
+NTSTATUS
+InitMonitorImpl()
+{
+ DPRINT("Initializing monitor implementation...\n");
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CleanupMonitorImpl()
+{
+ DPRINT("Cleaning up monitor implementation...\n");
+ /* FIXME: Destroy monitor objects? */
+
+ return STATUS_SUCCESS;
+}
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+#ifndef MIN
+# define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef ABS
+# define ABS(a) ((a) < (0) ? (-(a)) : (a))
+#endif
+
+/* IntCreateMonitorObject
+ *
+ * Creates a MONITOR
+ *
+ * Return value
+ * If the function succeeds a pointer to a MONITOR is returned. On failure
+ * NULL is returned.
+ */
+static
+PMONITOR
+IntCreateMonitorObject()
+{
+ HANDLE Handle;
+ PMONITOR Monitor;
+
+ Monitor = UserCreateObject(gHandleTable, NULL, &Handle, otMonitor, sizeof (MONITOR));
+ if (Monitor == NULL)
+ {
+ return NULL;
+ }
+
+ ExInitializeFastMutex(&Monitor->Lock);
+
+ return Monitor;
+}
+
+/* IntDestroyMonitorObject
+ *
+ * Destroys a MONITOR
+ * You have to be the owner of the monitors lock to safely destroy it.
+ *
+ * Arguments
+ *
+ * pMonitor
+ * Pointer to the MONITOR which shall be deleted
+ */
+static
+void
+IntDestroyMonitorObject(IN PMONITOR pMonitor)
+{
+ RtlFreeUnicodeString(&pMonitor->DeviceName);
+ UserDereferenceObject(pMonitor);
+}
+
+
+PMONITOR FASTCALL
+UserGetMonitorObject(IN HMONITOR hMonitor)
+{
+ PMONITOR Monitor;
+
+ if (!hMonitor)
+ {
+ SetLastWin32Error(ERROR_INVALID_MONITOR_HANDLE);
+ return NULL;
+ }
+
+
+ Monitor = (PMONITOR)UserGetObject(gHandleTable, hMonitor, otMonitor);
+ if (!Monitor)
+ {
+ SetLastWin32Error(ERROR_INVALID_MONITOR_HANDLE);
+ return NULL;
+ }
+
+ ASSERT(Monitor->head.cLockObj >= 0);
+
+ return Monitor;
+}
+
+
+/* IntAttachMonitor
+ *
+ * Creates a new MONITOR and appends it to the list of monitors.
+ *
+ * Arguments
+ *
+ * pGdiDevice Pointer to the PDEVOBJ onto which the monitor was attached
+ * DisplayNumber Display Number (starting with 0)
+ *
+ * Return value
+ * Returns a NTSTATUS
+ */
+NTSTATUS
+IntAttachMonitor(IN PDEVOBJ *pGdiDevice,
+ IN ULONG DisplayNumber)
+{
+ PMONITOR Monitor;
+ WCHAR Buffer[CCHDEVICENAME];
+
+ DPRINT("Attaching monitor...\n");
+
+ /* create new monitor object */
+ Monitor = IntCreateMonitorObject();
+ if (Monitor == NULL)
+ {
+ DPRINT("Couldnt create monitor object\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ _snwprintf(Buffer, CCHDEVICENAME, L"\\\\.\\DISPLAY%d", DisplayNumber + 1);
+ if (!RtlCreateUnicodeString(&Monitor->DeviceName, Buffer))
+ {
+ DPRINT("Couldn't duplicate monitor name!\n");
+ UserDereferenceObject(Monitor);
+ UserDeleteObject(UserHMGetHandle(Monitor), otMonitor);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Monitor->GdiDevice = pGdiDevice;
+ Monitor->rcMonitor.left = 0;
+ Monitor->rcMonitor.top = 0;
+ Monitor->rcMonitor.right = Monitor->rcMonitor.left + pGdiDevice->gdiinfo.ulHorzRes;
+ Monitor->rcMonitor.bottom = Monitor->rcMonitor.top + pGdiDevice->gdiinfo.ulVertRes;
+ Monitor->rcWork = Monitor->rcMonitor;
+ Monitor->cWndStack = 0;
+
+ Monitor->hrgnMonitor = IntSysCreateRectRgnIndirect( &Monitor->rcMonitor );
+
+ IntGdiSetRegionOwner(Monitor->hrgnMonitor, GDI_OBJ_HMGR_PUBLIC);
+
+ if (gMonitorList == NULL)
+ {
+ DPRINT("Primary monitor is beeing attached\n");
+ Monitor->IsPrimary = TRUE;
+ gMonitorList = Monitor;
+ }
+ else
+ {
+ PMONITOR p;
+ DPRINT("Additional monitor is beeing attached\n");
+ for (p = gMonitorList; p->Next != NULL; p = p->Next)
+ {
+ p->Next = Monitor;
+ }
+ Monitor->Prev = p;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/* IntDetachMonitor
+ *
+ * Deletes a MONITOR and removes it from the list of monitors.
+ *
+ * Arguments
+ *
+ * pGdiDevice Pointer to the PDEVOBJ from which the monitor was detached
+ *
+ * Return value
+ * Returns a NTSTATUS
+ */
+NTSTATUS
+IntDetachMonitor(IN PDEVOBJ *pGdiDevice)
+{
+ PMONITOR Monitor;
+
+ for (Monitor = gMonitorList; Monitor != NULL; Monitor = Monitor->Next)
+ {
+ if (Monitor->GdiDevice == pGdiDevice)
+ break;
+ }
+
+ if (Monitor == NULL)
+ {
+ /* no monitor for given device found */
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (Monitor->IsPrimary && (Monitor->Next != NULL || Monitor->Prev != NULL))
+ {
+ PMONITOR NewPrimaryMonitor = (Monitor->Prev != NULL) ? (Monitor->Prev) : (Monitor->Next);
+
+ ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&NewPrimaryMonitor->Lock);
+ NewPrimaryMonitor->IsPrimary = TRUE;
+ ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&NewPrimaryMonitor->Lock);
+ }
+
+ if (gMonitorList == Monitor)
+ {
+ gMonitorList = Monitor->Next;
+ if (Monitor->Next != NULL)
+ Monitor->Next->Prev = NULL;
+ }
+ else
+ {
+ Monitor->Prev->Next = Monitor->Next;
+ if (Monitor->Next != NULL)
+ Monitor->Next->Prev = Monitor->Prev;
+ }
+
+ if (Monitor->hrgnMonitor)
+ REGION_FreeRgnByHandle(Monitor->hrgnMonitor);
+
+ IntDestroyMonitorObject(Monitor);
+
+ return STATUS_SUCCESS;
+}
+
+/* IntGetPrimaryMonitor
+ *
+ * Returns a PMONITOR for the primary monitor
+ *
+ * Return value
+ * PMONITOR
+ */
+PMONITOR
+FASTCALL
+IntGetPrimaryMonitor()
+{
+ PMONITOR Monitor;
+
+ for (Monitor = gMonitorList; Monitor != NULL; Monitor = Monitor->Next)
+ {
+ /* FIXME: I guess locking the monitor is not neccessary to read 1 int */
+ if (Monitor->IsPrimary)
+ break;
+ }
+
+ return Monitor;
+}
+
+/* IntGetMonitorsFromRect
+ *
+ * Returns a list of monitor handles/rectangles. The rectangles in the list are
+ * the areas of intersection with the monitors.
+ *
+ * Arguments
+ *
+ * pRect
+ * Rectangle in desktop coordinates. If this is NULL all monitors are
+ * returned and the rect list is filled with the sizes of the monitors.
+ *
+ * hMonitorList
+ * Pointer to an array of HMONITOR which is filled with monitor handles.
+ * Can be NULL
+ *
+ * monitorRectList
+ * Pointer to an array of RECT which is filled with intersection rects in
+ * desktop coordinates.
+ * Can be NULL, will be ignored if no intersecting monitor is found and
+ * flags is MONITOR_DEFAULTTONEAREST
+ *
+ * listSize
+ * Size of the hMonitorList and monitorRectList arguments. If this is zero
+ * hMonitorList and monitorRectList are ignored.
+ *
+ * flags
+ * Either 0 or MONITOR_DEFAULTTONEAREST (ignored if rect is NULL)
+ *
+ * Returns
+ * The number of monitors which intersect the specified region.
+ */
+static
+UINT
+IntGetMonitorsFromRect(OPTIONAL IN LPCRECTL pRect,
+ OPTIONAL OUT HMONITOR *hMonitorList,
+ OPTIONAL OUT PRECTL monitorRectList,
+ OPTIONAL IN DWORD listSize,
+ OPTIONAL IN DWORD flags)
+{
+ PMONITOR Monitor, NearestMonitor = NULL, PrimaryMonitor = NULL;
+ UINT iCount = 0;
+ LONG iNearestDistanceX = 0x7fffffff, iNearestDistanceY = 0x7fffffff;
+
+ /* find monitors which intersect the rectangle */
+ for (Monitor = gMonitorList; Monitor != NULL; Monitor = Monitor->Next)
+ {
+ RECTL MonitorRect, IntersectionRect;
+
+ ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&Monitor->Lock);
+ MonitorRect = Monitor->rcMonitor;
+ ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&Monitor->Lock);
+
+ DPRINT("MonitorRect: left = %d, top = %d, right = %d, bottom = %d\n",
+ MonitorRect.left, MonitorRect.top, MonitorRect.right, MonitorRect.bottom);
+
+ if (flags == MONITOR_DEFAULTTOPRIMARY && Monitor->IsPrimary)
+ {
+ PrimaryMonitor = Monitor;
+ }
+
+ if (pRect != NULL)
+ {
+ BOOL intersects = TRUE;
+
+ /* check if the rect intersects the monitor */
+ if ((pRect->right < MonitorRect.left) || (pRect->left > MonitorRect.right) ||
+ (pRect->bottom < MonitorRect.top) || (pRect->top > MonitorRect.bottom))
+ {
+ intersects = FALSE;
+ }
+
+ if (flags == MONITOR_DEFAULTTONEAREST && !intersects)
+ {
+ INT distanceX, distanceY;
+
+ distanceX = MIN(ABS(MonitorRect.left - pRect->right),
+ ABS(pRect->left - MonitorRect.right));
+ distanceY = MIN(ABS(MonitorRect.top - pRect->bottom),
+ ABS(pRect->top - MonitorRect.bottom));
+
+ if (((distanceX < iNearestDistanceX) && (distanceY <= iNearestDistanceY)) ||
+ ((distanceX <= iNearestDistanceX) && (distanceY < iNearestDistanceY)))
+ {
+ iNearestDistanceX = distanceX;
+ iNearestDistanceY = distanceY;
+ NearestMonitor = Monitor;
+ }
+ }
+
+ if (!intersects)
+ continue;
+
+ /* calculate intersection */
+ IntersectionRect.left = MAX(MonitorRect.left, pRect->left);
+ IntersectionRect.top = MAX(MonitorRect.top, pRect->top);
+ IntersectionRect.right = MIN(MonitorRect.right, pRect->right);
+ IntersectionRect.bottom = MIN(MonitorRect.bottom, pRect->bottom);
+ }
+ else
+ {
+ IntersectionRect = MonitorRect;
+ }
+
+ if (iCount < listSize)
+ {
+ if (hMonitorList != NULL)
+ hMonitorList[iCount] = UserHMGetHandle(Monitor);
+ if (monitorRectList != NULL)
+ monitorRectList[iCount] = IntersectionRect;
+ }
+ iCount++;
+ }
+
+ if (iCount == 0 && flags == MONITOR_DEFAULTTONEAREST)
+ {
+ if (iCount < listSize)
+ {
+ if (hMonitorList != NULL)
+ hMonitorList[iCount] = UserHMGetHandle(NearestMonitor);
+ }
+ iCount++;
+ }
+ else if (iCount == 0 && flags == MONITOR_DEFAULTTOPRIMARY)
+ {
+ if (iCount < listSize)
+ {
+ if (hMonitorList != NULL)
+ hMonitorList[iCount] = UserHMGetHandle(PrimaryMonitor);
+ }
+ iCount++;
+ }
+ return iCount;
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+/* NtUserEnumDisplayMonitors
+ *
+ * Enumerates display monitors which intersect the given HDC/cliprect
+ *
+ * Arguments
+ *
+ * hDC
+ * Handle to a DC for which to enum intersecting monitors. If this is NULL
+ * it returns all monitors which are part of the current virtual screen.
+ *
+ * pRect
+ * Clipping rectangle with coordinate system origin at the DCs origin if the
+ * given HDC is not NULL or in virtual screen coordinated if it is NULL.
+ * Can be NULL
+ *
+ * hMonitorList
+ * Pointer to an array of HMONITOR which is filled with monitor handles.
+ * Can be NULL
+ *
+ * monitorRectList
+ * Pointer to an array of RECT which is filled with intersection rectangles.
+ * Can be NULL
+ *
+ * listSize
+ * Size of the hMonitorList and monitorRectList arguments. If this is zero
+ * hMonitorList and monitorRectList are ignored.
+ *
+ * Returns
+ * The number of monitors which intersect the specified region or -1 on failure.
+ */
+INT
+APIENTRY
+NtUserEnumDisplayMonitors(
+ OPTIONAL IN HDC hDC,
+ OPTIONAL IN LPCRECTL pRect,
+ OPTIONAL OUT HMONITOR *hMonitorList,
+ OPTIONAL OUT PRECTL monitorRectList,
+ OPTIONAL IN DWORD listSize)
+{
+ INT numMonitors, i;
+ HMONITOR *safeHMonitorList = NULL;
+ PRECTL safeRectList = NULL;
+ RECTL rect, *myRect;
+ RECTL dcRect;
+ NTSTATUS status;
+
+ /* get rect */
+ if (pRect != NULL)
+ {
+ status = MmCopyFromCaller(&rect, pRect, sizeof (RECT));
+ if (!NT_SUCCESS(status))
+ {
+ DPRINT("MmCopyFromCaller() failed!\n");
+ SetLastNtError(status);
+ return -1;
+ }
+ }
+
+ if (hDC != NULL)
+ {
+ PDC dc;
+ HRGN dcVisRgn;
+ INT regionType;
+
+ /* get visible region bounding rect */
+ dc = DC_LockDc(hDC);
+ if (dc == NULL)
+ {
+ DPRINT("DC_LockDc() failed!\n");
+ /* FIXME: setlasterror? */
+ return -1;
+ }
+ dcVisRgn = dc->prgnVis->BaseObject.hHmgr;
+ DC_UnlockDc(dc);
+
+ regionType = NtGdiGetRgnBox(dcVisRgn, &dcRect);
+ if (regionType == 0)
+ {
+ DPRINT("NtGdiGetRgnBox() failed!\n");
+ return -1;
+ }
+ if (regionType == NULLREGION)
+ return 0;
+ if (regionType == COMPLEXREGION)
+ { /* TODO: warning */
+ }
+
+ /* if hDC and pRect are given the area of interest is pRect with
+ coordinate origin at the DC position */
+ if (pRect != NULL)
+ {
+ rect.left += dcRect.left;
+ rect.right += dcRect.left;
+ rect.top += dcRect.top;
+ rect.bottom += dcRect.top;
+ }
+ /* if hDC is given and pRect is not the area of interest is the
+ bounding rect of hDC */
+ else
+ {
+ rect = dcRect;
+ }
+ }
+
+ if (hDC == NULL && pRect == NULL)
+ myRect = NULL;
+ else
+ myRect = ▭
+
+ /* find intersecting monitors */
+ numMonitors = IntGetMonitorsFromRect(myRect, NULL, NULL, 0, 0);
+ if (numMonitors == 0 || listSize == 0 ||
+ (hMonitorList == NULL && monitorRectList == NULL))
+ {
+ DPRINT("numMonitors = %d\n", numMonitors);
+ return numMonitors;
+ }
+
+ if (hMonitorList != NULL && listSize != 0)
+ {
- safeRectList = ExAllocatePool(PagedPool, sizeof (RECT) * listSize);
++ safeHMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof (HMONITOR) * listSize, USERTAG_MONITORRECTS);
+ if (safeHMonitorList == NULL)
+ {
+ /* FIXME: SetLastWin32Error? */
+ return -1;
+ }
+ }
+ if (monitorRectList != NULL && listSize != 0)
+ {
- ExFreePool(safeHMonitorList);
++ safeRectList = ExAllocatePoolWithTag(PagedPool, sizeof (RECT) * listSize, USERTAG_MONITORRECTS);
+ if (safeRectList == NULL)
+ {
- ExFreePool(safeRectList);
++ ExFreePoolWithTag(safeHMonitorList, USERTAG_MONITORRECTS);
+ /* FIXME: SetLastWin32Error? */
+ return -1;
+ }
+ }
+
+ /* get intersecting monitors */
+ numMonitors = IntGetMonitorsFromRect(myRect, safeHMonitorList, safeRectList,
+ listSize, 0 );
+
+ if (hDC != NULL && pRect != NULL && safeRectList != NULL)
+ for (i = 0; i < numMonitors; i++)
+ {
+ safeRectList[i].left -= dcRect.left;
+ safeRectList[i].right -= dcRect.left;
+ safeRectList[i].top -= dcRect.top;
+ safeRectList[i].bottom -= dcRect.top;
+ }
+
+ /* output result */
+ if (hMonitorList != NULL && listSize != 0)
+ {
+ status = MmCopyToCaller(hMonitorList, safeHMonitorList, sizeof (HMONITOR) * listSize);
+ ExFreePool(safeHMonitorList);
+ if (!NT_SUCCESS(status))
+ {
- ExFreePool(safeRectList);
++ ExFreePoolWithTag(safeRectList, USERTAG_MONITORRECTS);
+ SetLastNtError(status);
+ return -1;
+ }
+ }
+ if (monitorRectList != NULL && listSize != 0)
+ {
+ status = MmCopyToCaller(monitorRectList, safeRectList, sizeof (RECT) * listSize);
- hMonitorList = ExAllocatePool(PagedPool, sizeof (HMONITOR) * numMonitors);
++ ExFreePoolWithTag(safeRectList, USERTAG_MONITORRECTS);
+ if (!NT_SUCCESS(status))
+ {
+ SetLastNtError(status);
+ return -1;
+ }
+ }
+
+ return numMonitors;
+}
+
+/* NtUserGetMonitorInfo
+ *
+ * Retrieves information about a given monitor
+ *
+ * Arguments
+ *
+ * hMonitor
+ * Handle to a monitor for which to get information
+ *
+ * pMonitorInfo
+ * Pointer to a MONITORINFO struct which is filled with the information.
+ * The cbSize member must be set to sizeof(MONITORINFO) or
+ * sizeof(MONITORINFOEX). Even if set to sizeof(MONITORINFOEX) only parts
+ * from MONITORINFO will be filled.
+ *
+ * pDevice
+ * Pointer to a UNICODE_STRING which will recieve the device's name. The
+ * length should be CCHDEVICENAME
+ * Can be NULL
+ *
+ * Return value
+ * TRUE on success; FALSE on failure (calls SetLastNtError())
+ *
+ */
+BOOL
+APIENTRY
+NtUserGetMonitorInfo(
+ IN HMONITOR hMonitor,
+ OUT LPMONITORINFO pMonitorInfo)
+{
+ PMONITOR Monitor;
+ MONITORINFOEXW MonitorInfo;
+ NTSTATUS Status;
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserGetMonitorInfo\n");
+ UserEnterShared();
+
+ /* get monitor object */
+ if (!(Monitor = UserGetMonitorObject(hMonitor)))
+ {
+ DPRINT("Couldnt find monitor 0x%lx\n", hMonitor);
+ RETURN(FALSE);
+ }
+
+ if(pMonitorInfo == NULL)
+ {
+ SetLastNtError(STATUS_INVALID_PARAMETER);
+ RETURN(FALSE);
+ }
+
+ /* get size of pMonitorInfo */
+ Status = MmCopyFromCaller(&MonitorInfo.cbSize, &pMonitorInfo->cbSize, sizeof (MonitorInfo.cbSize));
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN(FALSE);
+ }
+ if ((MonitorInfo.cbSize != sizeof (MONITORINFO)) &&
+ (MonitorInfo.cbSize != sizeof (MONITORINFOEXW)))
+ {
+ SetLastNtError(STATUS_INVALID_PARAMETER);
+ RETURN(FALSE);
+ }
+
+ /* fill monitor info */
+ MonitorInfo.rcMonitor = Monitor->rcMonitor;
+ MonitorInfo.rcWork = Monitor->rcWork;
+ MonitorInfo.dwFlags = 0;
+
+ if (Monitor->IsPrimary)
+ MonitorInfo.dwFlags |= MONITORINFOF_PRIMARY;
+
+ /* fill device name */
+ if (MonitorInfo.cbSize == sizeof (MONITORINFOEXW))
+ {
+ WCHAR nul = L'\0';
+ INT len = Monitor->DeviceName.Length;
+ if (len >= CCHDEVICENAME * sizeof (WCHAR))
+ len = (CCHDEVICENAME - 1) * sizeof (WCHAR);
+
+ memcpy(MonitorInfo.szDevice, Monitor->DeviceName.Buffer, len);
+ memcpy(MonitorInfo.szDevice + (len / sizeof (WCHAR)), &nul, sizeof (WCHAR));
+ }
+
+ /* output data */
+ Status = MmCopyToCaller(pMonitorInfo, &MonitorInfo, MonitorInfo.cbSize);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("GetMonitorInfo: MmCopyToCaller failed\n");
+ SetLastNtError(Status);
+ RETURN(FALSE);
+ }
+
+ DPRINT("GetMonitorInfo: success\n");
+
+ RETURN(TRUE);
+
+CLEANUP:
+ DPRINT("Leave NtUserGetMonitorInfo, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/* NtUserMonitorFromPoint
+ *
+ * Returns a handle to the monitor containing the given point.
+ *
+ * Arguments
+ *
+ * point
+ * Point for which to find monitor
+ *
+ * dwFlags
+ * Specifies the behaviour if the point isn't on any of the monitors.
+ *
+ * Return value
+ * If the point is found a handle to the monitor is returned; if not the
+ * return value depends on dwFlags
+ */
+HMONITOR
+APIENTRY
+NtUserMonitorFromPoint(
+ IN POINT point,
+ IN DWORD dwFlags)
+{
+ INT NumMonitors;
+ RECTL InRect;
+ HMONITOR hMonitor = NULL;
+
+ /* fill inRect */
+ InRect.left = InRect.right = point.x;
+ InRect.top = InRect.bottom = point.y;
+
+ /* find intersecting monitor */
+ NumMonitors = IntGetMonitorsFromRect(&InRect, &hMonitor, NULL, 1, 0);
+ if (NumMonitors < 0)
+ {
+ return (HMONITOR)NULL;
+ }
+
+ if (hMonitor == NULL)
+ {
+ if (dwFlags == MONITOR_DEFAULTTOPRIMARY)
+ {
+ PMONITOR MonitorObj = IntGetPrimaryMonitor();
+ if (MonitorObj)
+ hMonitor = UserHMGetHandle(MonitorObj);
+ }
+ else if (dwFlags == MONITOR_DEFAULTTONEAREST)
+ {
+ NumMonitors = IntGetMonitorsFromRect(&InRect, &hMonitor, NULL,
+ 1, MONITOR_DEFAULTTONEAREST);
+ /*ASSERT( (numMonitors > 0) && (hMonitor != NULL) );*/
+ }
+ /* else flag is DEFAULTTONULL */
+ }
+
+ return hMonitor;
+}
+
+/* NtUserMonitorFromRect
+ *
+ * Returns a handle to the monitor having the largest intersection with a
+ * given rectangle
+ *
+ * Arguments
+ *
+ * pRect
+ * Pointer to a RECT for which to find monitor
+ *
+ * dwFlags
+ * Specifies the behaviour if no monitor intersects the given rect
+ *
+ * Return value
+ * If a monitor intersects the rect a handle to it is returned; if not the
+ * return value depends on dwFlags
+ */
+HMONITOR
+APIENTRY
+NtUserMonitorFromRect(
+ IN LPCRECTL pRect,
+ IN DWORD dwFlags)
+{
+ INT numMonitors, iLargestArea = -1, i;
+ PRECTL rectList;
+ HMONITOR *hMonitorList;
+ HMONITOR hMonitor = NULL;
+ RECTL rect;
+ NTSTATUS status;
+
+ /* get rect */
+ status = MmCopyFromCaller(&rect, pRect, sizeof (RECT));
+ if (!NT_SUCCESS(status))
+ {
+ SetLastNtError(status);
+ return (HMONITOR)NULL;
+ }
+
+ /* find intersecting monitors */
+ numMonitors = IntGetMonitorsFromRect(&rect, NULL, NULL, 0, 0);
+ if (numMonitors < 0)
+ {
+ return (HMONITOR)NULL;
+ }
+
+ if (numMonitors == 0)
+ {
+ if (dwFlags == MONITOR_DEFAULTTOPRIMARY)
+ {
+ PMONITOR monitorObj = IntGetPrimaryMonitor();
+ if (monitorObj)
+ return UserHMGetHandle(monitorObj);
+ }
+ else if (dwFlags == MONITOR_DEFAULTTONEAREST)
+ {
+ numMonitors = IntGetMonitorsFromRect(&rect, &hMonitor, NULL,
+ 1, MONITOR_DEFAULTTONEAREST);
+ if (numMonitors <= 0)
+ {
+ /* error? */
+ return (HMONITOR)NULL;
+ }
+
+ if (numMonitors > 0)
+ return hMonitor;
+ }
+ /* else flag is DEFAULTTONULL */
+ return (HMONITOR)NULL;
+ }
+
- rectList = ExAllocatePool(PagedPool, sizeof (RECT) * numMonitors);
++ hMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof (HMONITOR) * numMonitors, USERTAG_MONITORRECTS);
+ if (hMonitorList == NULL)
+ {
+ /* FIXME: SetLastWin32Error? */
+ return (HMONITOR)NULL;
+ }
- ExFreePool(hMonitorList);
++ rectList = ExAllocatePoolWithTag(PagedPool, sizeof (RECT) * numMonitors, USERTAG_MONITORRECTS);
+ if (rectList == NULL)
+ {
- ExFreePool(hMonitorList);
- ExFreePool(rectList);
++ ExFreePoolWithTag(hMonitorList, USERTAG_MONITORRECTS);
+ /* FIXME: SetLastWin32Error? */
+ return (HMONITOR)NULL;
+ }
+
+ /* get intersecting monitors */
+ numMonitors = IntGetMonitorsFromRect(&rect, hMonitorList, rectList,
+ numMonitors, 0);
+ if (numMonitors <= 0)
+ {
- ExFreePool(hMonitorList);
- ExFreePool(rectList);
++ ExFreePoolWithTag(hMonitorList, USERTAG_MONITORRECTS);
++ ExFreePoolWithTag(rectList, USERTAG_MONITORRECTS);
+ return (HMONITOR)NULL;
+ }
+
+ /* find largest intersection */
+ for (i = 0; i < numMonitors; i++)
+ {
+ INT area = (rectList[i].right - rectList[i].left) *
+ (rectList[i].bottom - rectList[i].top);
+ if (area > iLargestArea)
+ {
+ hMonitor = hMonitorList[i];
+ }
+ }
+
++ ExFreePoolWithTag(hMonitorList, USERTAG_MONITORRECTS);
++ ExFreePoolWithTag(rectList, USERTAG_MONITORRECTS);
+
+ return hMonitor;
+}
+
+
+HMONITOR
+APIENTRY
+NtUserMonitorFromWindow(
+ IN HWND hWnd,
+ IN DWORD dwFlags)
+{
+ PWINDOW_OBJECT Window;
+ HMONITOR hMonitor = NULL;
+ RECTL Rect;
+ DECLARE_RETURN(HMONITOR);
+
+ DPRINT("Enter NtUserMonitorFromWindow\n");
+ UserEnterShared();
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ if (dwFlags == MONITOR_DEFAULTTONULL)
+ {
+ RETURN(hMonitor);
+ }
+ IntGetMonitorsFromRect(NULL, &hMonitor, NULL, 1, dwFlags);
+ RETURN(hMonitor);
+ }
+
+ if (!Window->Wnd)
+ RETURN(hMonitor);
+
+ Rect.left = Rect.right = Window->Wnd->rcWindow.left;
+ Rect.top = Rect.bottom = Window->Wnd->rcWindow.bottom;
+
+ IntGetMonitorsFromRect(&Rect, &hMonitor, NULL, 1, dwFlags);
+
+ RETURN(hMonitor);
+
+CLEANUP:
+ DPRINT("Leave NtUserMonitorFromWindow, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
--- /dev/null
- PDC_ATTR pdcattr;
+/*
+ * ReactOS W32 Subsystem
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <win32k.h>
+
+#define NDEBUG
+#include <debug.h>
+
+static const RGBQUAD EGAColorsQuads[16] = {
+/* rgbBlue, rgbGreen, rgbRed, rgbReserved */
+ { 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x80, 0x00 },
+ { 0x00, 0x80, 0x00, 0x00 },
+ { 0x00, 0x80, 0x80, 0x00 },
+ { 0x80, 0x00, 0x00, 0x00 },
+ { 0x80, 0x00, 0x80, 0x00 },
+ { 0x80, 0x80, 0x00, 0x00 },
+ { 0x80, 0x80, 0x80, 0x00 },
+ { 0xc0, 0xc0, 0xc0, 0x00 },
+ { 0x00, 0x00, 0xff, 0x00 },
+ { 0x00, 0xff, 0x00, 0x00 },
+ { 0x00, 0xff, 0xff, 0x00 },
+ { 0xff, 0x00, 0x00, 0x00 },
+ { 0xff, 0x00, 0xff, 0x00 },
+ { 0xff, 0xff, 0x00, 0x00 },
+ { 0xff, 0xff, 0xff, 0x00 }
+};
+
+static const RGBQUAD DefLogPaletteQuads[20] = { /* Copy of Default Logical Palette */
+/* rgbBlue, rgbGreen, rgbRed, rgbReserved */
+ { 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x80, 0x00 },
+ { 0x00, 0x80, 0x00, 0x00 },
+ { 0x00, 0x80, 0x80, 0x00 },
+ { 0x80, 0x00, 0x00, 0x00 },
+ { 0x80, 0x00, 0x80, 0x00 },
+ { 0x80, 0x80, 0x00, 0x00 },
+ { 0xc0, 0xc0, 0xc0, 0x00 },
+ { 0xc0, 0xdc, 0xc0, 0x00 },
+ { 0xf0, 0xca, 0xa6, 0x00 },
+ { 0xf0, 0xfb, 0xff, 0x00 },
+ { 0xa4, 0xa0, 0xa0, 0x00 },
+ { 0x80, 0x80, 0x80, 0x00 },
+ { 0x00, 0x00, 0xf0, 0x00 },
+ { 0x00, 0xff, 0x00, 0x00 },
+ { 0x00, 0xff, 0xff, 0x00 },
+ { 0xff, 0x00, 0x00, 0x00 },
+ { 0xff, 0x00, 0xff, 0x00 },
+ { 0xff, 0xff, 0x00, 0x00 },
+ { 0xff, 0xff, 0xff, 0x00 }
+};
+
+
+UINT
+APIENTRY
+IntSetDIBColorTable(
+ HDC hDC,
+ UINT StartIndex,
+ UINT Entries,
+ CONST RGBQUAD *Colors)
+{
+ PDC dc;
+ PSURFACE psurf;
+ PPALETTE PalGDI;
+ UINT Index;
+ ULONG biBitCount;
+
+ if (!(dc = DC_LockDc(hDC))) return 0;
+ if (dc->dctype == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(dc);
+ return 0;
+ }
+
+ psurf = dc->dclevel.pSurface;
+ if (psurf == NULL)
+ {
+ DC_UnlockDc(dc);
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ if (psurf->hSecure == NULL)
+ {
+ DC_UnlockDc(dc);
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ biBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
+ if (biBitCount <= 8 && StartIndex < (1 << biBitCount))
+ {
+ if (StartIndex + Entries > (1 << biBitCount))
+ Entries = (1 << biBitCount) - StartIndex;
+
+ if (psurf->ppal == NULL)
+ {
+ DC_UnlockDc(dc);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return 0;
+ }
+
+ PalGDI = PALETTE_LockPalette(psurf->ppal->BaseObject.hHmgr);
+
+ for (Index = StartIndex;
+ Index < StartIndex + Entries && Index < PalGDI->NumColors;
+ Index++)
+ {
+ PalGDI->IndexedColors[Index].peRed = Colors[Index - StartIndex].rgbRed;
+ PalGDI->IndexedColors[Index].peGreen = Colors[Index - StartIndex].rgbGreen;
+ PalGDI->IndexedColors[Index].peBlue = Colors[Index - StartIndex].rgbBlue;
+ }
+ PALETTE_UnlockPalette(PalGDI);
+ }
+ else
+ Entries = 0;
+
+ /* Mark the brushes invalid */
+ dc->pdcattr->ulDirty_ |= DIRTY_FILL|DIRTY_LINE|DIRTY_BACKGROUND|DIRTY_TEXT;
+
+ DC_UnlockDc(dc);
+
+ return Entries;
+}
+
+UINT
+APIENTRY
+IntGetDIBColorTable(
+ HDC hDC,
+ UINT StartIndex,
+ UINT Entries,
+ RGBQUAD *Colors)
+{
+ PDC dc;
+ PSURFACE psurf;
+ PPALETTE PalGDI;
+ UINT Index, Count = 0;
+ ULONG biBitCount;
+
+ if (!(dc = DC_LockDc(hDC))) return 0;
+ if (dc->dctype == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(dc);
+ return 0;
+ }
+
+ psurf = dc->dclevel.pSurface;
+ if (psurf == NULL)
+ {
+ DC_UnlockDc(dc);
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ if (psurf->hSecure == NULL)
+ {
+ DC_UnlockDc(dc);
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ biBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
+ if (biBitCount <= 8 &&
+ StartIndex < (1 << biBitCount))
+ {
+ if (StartIndex + Entries > (1 << biBitCount))
+ Entries = (1 << biBitCount) - StartIndex;
+
+ if (psurf->ppal == NULL)
+ {
+ DC_UnlockDc(dc);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return 0;
+ }
+
+ PalGDI = PALETTE_LockPalette(psurf->ppal->BaseObject.hHmgr);
+
+ for (Index = StartIndex;
+ Index < StartIndex + Entries && Index < PalGDI->NumColors;
+ Index++)
+ {
+ Colors[Index - StartIndex].rgbRed = PalGDI->IndexedColors[Index].peRed;
+ Colors[Index - StartIndex].rgbGreen = PalGDI->IndexedColors[Index].peGreen;
+ Colors[Index - StartIndex].rgbBlue = PalGDI->IndexedColors[Index].peBlue;
+ Colors[Index - StartIndex].rgbReserved = 0;
+ Count++;
+ }
+ PALETTE_UnlockPalette(PalGDI);
+ }
+
+ DC_UnlockDc(dc);
+
+ return Count;
+}
+
+// Converts a DIB to a device-dependent bitmap
+static INT
+FASTCALL
+IntSetDIBits(
+ PDC DC,
+ HBITMAP hBitmap,
+ UINT StartScan,
+ UINT ScanLines,
+ CONST VOID *Bits,
+ CONST BITMAPINFO *bmi,
+ UINT ColorUse)
+{
+ SURFACE *bitmap;
+ HBITMAP SourceBitmap;
+ INT result = 0;
+ BOOL copyBitsResult;
+ SURFOBJ *DestSurf, *SourceSurf;
+ SIZEL SourceSize;
+ POINTL ZeroPoint;
+ RECTL DestRect;
+ EXLATEOBJ exlo;
+ PPALETTE ppalDIB;
+ //RGBQUAD *lpRGB;
+ HPALETTE DIB_Palette;
+ ULONG DIB_Palette_Type;
+ INT DIBWidth;
+
+ // Check parameters
+ if (!(bitmap = SURFACE_LockSurface(hBitmap)))
+ {
+ return 0;
+ }
+
+ // Get RGB values
+ //if (ColorUse == DIB_PAL_COLORS)
+ // lpRGB = DIB_MapPaletteColors(hDC, bmi);
+ //else
+ // lpRGB = &bmi->bmiColors;
+
+ DestSurf = &bitmap->SurfObj;
+
+ // Create source surface
+ SourceSize.cx = bmi->bmiHeader.biWidth;
+ SourceSize.cy = ScanLines;
+
+ // Determine width of DIB
+ DIBWidth = DIB_GetDIBWidthBytes(SourceSize.cx, bmi->bmiHeader.biBitCount);
+
+ SourceBitmap = EngCreateBitmap(SourceSize,
+ DIBWidth,
+ BitmapFormat(bmi->bmiHeader.biBitCount, bmi->bmiHeader.biCompression),
+ bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
+ (PVOID) Bits);
+ if (0 == SourceBitmap)
+ {
+ SURFACE_UnlockSurface(bitmap);
+ SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
+ return 0;
+ }
+
+ SourceSurf = EngLockSurface((HSURF)SourceBitmap);
+ if (NULL == SourceSurf)
+ {
+ EngDeleteSurface((HSURF)SourceBitmap);
+ SURFACE_UnlockSurface(bitmap);
+ SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
+ return 0;
+ }
+
+ ASSERT(bitmap->ppal);
+
+ // Source palette obtained from the BITMAPINFO
+ DIB_Palette = BuildDIBPalette(bmi, (PINT)&DIB_Palette_Type);
+ if (NULL == DIB_Palette)
+ {
+ EngUnlockSurface(SourceSurf);
+ EngDeleteSurface((HSURF)SourceBitmap);
+ SURFACE_UnlockSurface(bitmap);
+ SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
+ return 0;
+ }
+
+ ppalDIB = PALETTE_LockPalette(DIB_Palette);
+
+ /* Initialize XLATEOBJ for color translation */
+ EXLATEOBJ_vInitialize(&exlo, ppalDIB, bitmap->ppal, 0, 0, 0);
+
+ // Zero point
+ ZeroPoint.x = 0;
+ ZeroPoint.y = 0;
+
+ // Determine destination rectangle
+ DestRect.left = 0;
+ DestRect.top = abs(bmi->bmiHeader.biHeight) - StartScan - ScanLines;
+ DestRect.right = SourceSize.cx;
+ DestRect.bottom = DestRect.top + ScanLines;
+
+ copyBitsResult = IntEngCopyBits(DestSurf, SourceSurf, NULL, &exlo.xlo, &DestRect, &ZeroPoint);
+
+ // If it succeeded, return number of scanlines copies
+ if (copyBitsResult == TRUE)
+ {
+ result = SourceSize.cy;
+// or
+// result = abs(bmi->bmiHeader.biHeight) - StartScan;
+ }
+
+ // Clean up
+ EXLATEOBJ_vCleanup(&exlo);
+ PALETTE_UnlockPalette(ppalDIB);
+ PALETTE_FreePaletteByHandle(DIB_Palette);
+ EngUnlockSurface(SourceSurf);
+ EngDeleteSurface((HSURF)SourceBitmap);
+
+// if (ColorUse == DIB_PAL_COLORS)
+// WinFree((LPSTR)lpRGB);
+
+ SURFACE_UnlockSurface(bitmap);
+
+ return result;
+}
+
+// FIXME by Removing NtGdiSetDIBits!!!
+// This is a victim of the Win32k Initialization BUG!!!!!
+// Converts a DIB to a device-dependent bitmap
+INT
+APIENTRY
+NtGdiSetDIBits(
+ HDC hDC,
+ HBITMAP hBitmap,
+ UINT StartScan,
+ UINT ScanLines,
+ CONST VOID *Bits,
+ CONST BITMAPINFO *bmi,
+ UINT ColorUse)
+{
+ PDC Dc;
+ INT Ret;
+ NTSTATUS Status = STATUS_SUCCESS;
+ BITMAPV5INFO bmiLocal;
+
+ if (!Bits) return 0;
+
+ _SEH2_TRY
+ {
+ Status = ProbeAndConvertToBitmapV5Info(&bmiLocal, bmi, ColorUse, 0);
+ ProbeForRead(Bits, bmiLocal.bmiHeader.bV5SizeImage, 1);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (!NT_SUCCESS(Status))
+ {
+ return 0;
+ }
+
+ Dc = DC_LockDc(hDC);
+ if (NULL == Dc)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return 0;
+ }
+ if (Dc->dctype == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(Dc);
+ return 0;
+ }
+
+ Ret = IntSetDIBits(Dc, hBitmap, StartScan, ScanLines, Bits, (PBITMAPINFO)&bmiLocal, ColorUse);
+
+ DC_UnlockDc(Dc);
+
+ return Ret;
+}
+
+W32KAPI
+INT
+APIENTRY
+NtGdiSetDIBitsToDeviceInternal(
+ IN HDC hDC,
+ IN INT XDest,
+ IN INT YDest,
+ IN DWORD Width,
+ IN DWORD Height,
+ IN INT XSrc,
+ IN INT YSrc,
+ IN DWORD StartScan,
+ IN DWORD ScanLines,
+ IN LPBYTE Bits,
+ IN LPBITMAPINFO bmi,
+ IN DWORD ColorUse,
+ IN UINT cjMaxBits,
+ IN UINT cjMaxInfo,
+ IN BOOL bTransformCoordinates,
+ IN OPTIONAL HANDLE hcmXform)
+{
+ INT ret = 0;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PDC pDC;
+ HBITMAP hSourceBitmap = NULL;
+ SURFOBJ *pDestSurf, *pSourceSurf = NULL;
+ SURFACE *pSurf;
+ RECTL rcDest;
+ POINTL ptSource;
+ INT DIBWidth;
+ SIZEL SourceSize;
+ EXLATEOBJ exlo;
+ PPALETTE ppalDIB = NULL;
+ HPALETTE hpalDIB = NULL;
+ ULONG DIBPaletteType;
+ BITMAPV5INFO bmiLocal ;
+
+ if (!Bits) return 0;
+
+ _SEH2_TRY
+ {
+ Status = ProbeAndConvertToBitmapV5Info(&bmiLocal, bmi, ColorUse, cjMaxInfo);
+ ProbeForRead(Bits, cjMaxBits, 1);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (!NT_SUCCESS(Status))
+ {
+ return 0;
+ }
+
+ pDC = DC_LockDc(hDC);
+ if (!pDC)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return 0;
+ }
+ if (pDC->dctype == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(pDC);
+ return 0;
+ }
+
+ pSurf = pDC->dclevel.pSurface;
+
+ pDestSurf = pSurf ? &pSurf->SurfObj : NULL;
+
+ ScanLines = min(ScanLines, abs(bmiLocal.bmiHeader.bV5Height) - StartScan);
+
+ rcDest.left = XDest;
+ rcDest.top = YDest;
+ if (bTransformCoordinates)
+ {
+ CoordLPtoDP(pDC, (LPPOINT)&rcDest);
+ }
+ rcDest.left += pDC->ptlDCOrig.x;
+ rcDest.top += pDC->ptlDCOrig.y;
+ rcDest.right = rcDest.left + Width;
+ rcDest.bottom = rcDest.top + Height;
+ rcDest.top += StartScan;
+
+ ptSource.x = XSrc;
+ ptSource.y = YSrc;
+
+ SourceSize.cx = bmiLocal.bmiHeader.bV5Width;
+ SourceSize.cy = ScanLines;
+
+ DIBWidth = DIB_GetDIBWidthBytes(SourceSize.cx, bmiLocal.bmiHeader.bV5BitCount);
+
+ hSourceBitmap = EngCreateBitmap(SourceSize,
+ DIBWidth,
+ BitmapFormat(bmiLocal.bmiHeader.bV5BitCount,
+ bmiLocal.bmiHeader.bV5Compression),
+ bmiLocal.bmiHeader.bV5Height < 0 ? BMF_TOPDOWN : 0,
+ (PVOID) Bits);
+ if (!hSourceBitmap)
+ {
+ SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
+ Status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ pSourceSurf = EngLockSurface((HSURF)hSourceBitmap);
+ if (!pSourceSurf)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ goto Exit;
+ }
+
+ ASSERT(pSurf->ppal);
+
+ /* Create a palette for the DIB */
+ hpalDIB = BuildDIBPalette((PBITMAPINFO)&bmiLocal, (PINT)&DIBPaletteType);
+ if (!hpalDIB)
+ {
+ SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
+ Status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ /* Lock the DIB palette */
+ ppalDIB = PALETTE_LockPalette(hpalDIB);
+ if (!ppalDIB)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ Status = STATUS_UNSUCCESSFUL;
+ goto Exit;
+ }
+
+ /* Initialize EXLATEOBJ */
+ EXLATEOBJ_vInitialize(&exlo, ppalDIB, pSurf->ppal, 0, 0, 0);
+
+ /* Copy the bits */
+ DPRINT("BitsToDev with dstsurf=(%d|%d) (%d|%d), src=(%d|%d) w=%d h=%d\n",
+ rcDest.left, rcDest.top, rcDest.right, rcDest.bottom,
+ ptSource.x, ptSource.y, SourceSize.cx, SourceSize.cy);
+ Status = IntEngBitBlt(pDestSurf,
+ pSourceSurf,
+ NULL,
+ pDC->rosdc.CombinedClip,
+ &exlo.xlo,
+ &rcDest,
+ &ptSource,
+ NULL,
+ NULL,
+ NULL,
+ ROP3_TO_ROP4(SRCCOPY));
+
+ /* Cleanup EXLATEOBJ */
+ EXLATEOBJ_vCleanup(&exlo);
+
+Exit:
+ if (NT_SUCCESS(Status))
+ {
+ ret = ScanLines;
+ }
+
+ if (ppalDIB) PALETTE_UnlockPalette(ppalDIB);
+
+ if (pSourceSurf) EngUnlockSurface(pSourceSurf);
+ if (hSourceBitmap) EngDeleteSurface((HSURF)hSourceBitmap);
+ if (hpalDIB) PALETTE_FreePaletteByHandle(hpalDIB);
+ DC_UnlockDc(pDC);
+
+ return ret;
+}
+
+
+/* Converts a device-dependent bitmap to a DIB */
+INT
+APIENTRY
+NtGdiGetDIBitsInternal(
+ HDC hDC,
+ HBITMAP hBitmap,
+ UINT StartScan,
+ UINT ScanLines,
+ LPBYTE Bits,
+ LPBITMAPINFO Info,
+ UINT Usage,
+ UINT MaxBits,
+ UINT MaxInfo)
+{
+ PDC Dc;
+ SURFACE *psurf = NULL;
+ HBITMAP hDestBitmap = NULL;
+ HPALETTE hDestPalette = NULL;
+ BITMAPV5INFO bmiLocal ;
+ PPALETTE ppalDst = NULL;
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG Result = 0;
+ BOOL bPaletteMatch = FALSE;
+ PBYTE ChkBits = Bits;
+ ULONG DestPaletteType;
+ ULONG Index;
+
+ DPRINT("Entered NtGdiGetDIBitsInternal()\n");
+
+ if ((Usage && Usage != DIB_PAL_COLORS) || !Info || !hBitmap)
+ return 0;
+
+ // if ScanLines == 0, no need to copy Bits.
+ if (!ScanLines)
+ ChkBits = NULL;
+
+ _SEH2_TRY
+ {
+ Status = ProbeAndConvertToBitmapV5Info(&bmiLocal, Info, Usage, MaxInfo);
+ if (ChkBits) ProbeForWrite(ChkBits, MaxBits, 1);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (!NT_SUCCESS(Status))
+ {
+ return 0;
+ }
+
+ Dc = DC_LockDc(hDC);
+ if (Dc == NULL) return 0;
+ if (Dc->dctype == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(Dc);
+ return 0;
+ }
+
+ /* Get a pointer to the source bitmap object */
+ psurf = SURFACE_LockSurface(hBitmap);
+ if (psurf == NULL)
+ {
+ DC_UnlockDc(Dc);
+ return 0;
+ }
+
+ ASSERT(psurf->ppal);
+
+ DC_UnlockDc(Dc);
+
+ /* Copy palette information
+ * Always create a palette for 15 & 16 bit. */
+ if ((bmiLocal.bmiHeader.bV5BitCount == BitsPerFormat(psurf->SurfObj.iBitmapFormat) &&
+ bmiLocal.bmiHeader.bV5BitCount != 15 && bmiLocal.bmiHeader.bV5BitCount != 16) ||
+ !ChkBits)
+ {
+ ppalDst = psurf->ppal;
+ bPaletteMatch = TRUE;
+ }
+ else
+ {
+ hDestPalette = BuildDIBPalette((PBITMAPINFO)&bmiLocal, (PINT)&DestPaletteType);
+ ppalDst = PALETTE_LockPalette(hDestPalette);
+ }
+
+ DPRINT("ppalDst : %p\n", ppalDst);
+ ASSERT(ppalDst);
+
+ /* Copy palette. */
+ switch (bmiLocal.bmiHeader.bV5BitCount)
+ {
+ case 1:
+ case 4:
+ case 8:
+ bmiLocal.bmiHeader.bV5ClrUsed = 0;
+ if (psurf->hSecure &&
+ BitsPerFormat(psurf->SurfObj.iBitmapFormat) == bmiLocal.bmiHeader.bV5BitCount)
+ {
+ if (Usage == DIB_RGB_COLORS)
+ {
+ if (ppalDst->NumColors != 1 << bmiLocal.bmiHeader.bV5BitCount)
+ bmiLocal.bmiHeader.bV5ClrUsed = ppalDst->NumColors;
+ for (Index = 0;
+ Index < (1 << bmiLocal.bmiHeader.bV5BitCount) && Index < ppalDst->NumColors;
+ Index++)
+ {
+ bmiLocal.bmiColors[Index].rgbRed = ppalDst->IndexedColors[Index].peRed;
+ bmiLocal.bmiColors[Index].rgbGreen = ppalDst->IndexedColors[Index].peGreen;
+ bmiLocal.bmiColors[Index].rgbBlue = ppalDst->IndexedColors[Index].peBlue;
+ bmiLocal.bmiColors[Index].rgbReserved = 0;
+ }
+ }
+ else
+ {
+ for (Index = 0;
+ Index < (1 << bmiLocal.bmiHeader.bV5BitCount);
+ Index++)
+ {
+ ((WORD*)bmiLocal.bmiColors)[Index] = Index;
+ }
+ }
+ }
+ else
+ {
+ if (Usage == DIB_PAL_COLORS)
+ {
+ for (Index = 0;
+ Index < (1 << bmiLocal.bmiHeader.bV5BitCount);
+ Index++)
+ {
+ ((WORD*)bmiLocal.bmiColors)[Index] = (WORD)Index;
+ }
+ }
+ else if (bmiLocal.bmiHeader.bV5BitCount > 1 && bPaletteMatch)
+ {
+ for (Index = 0;
+ Index < (1 << bmiLocal.bmiHeader.bV5BitCount) && Index < ppalDst->NumColors;
+ Index++)
+ {
+ bmiLocal.bmiColors[Index].rgbRed = ppalDst->IndexedColors[Index].peRed;
+ bmiLocal.bmiColors[Index].rgbGreen = ppalDst->IndexedColors[Index].peGreen;
+ bmiLocal.bmiColors[Index].rgbBlue = ppalDst->IndexedColors[Index].peBlue;
+ bmiLocal.bmiColors[Index].rgbReserved = 0;
+ }
+ }
+ else
+ {
+ switch (bmiLocal.bmiHeader.bV5BitCount)
+ {
+ case 1:
+ bmiLocal.bmiColors[0].rgbRed =0 ;
+ bmiLocal.bmiColors[0].rgbGreen = 0;
+ bmiLocal.bmiColors[0].rgbBlue = 0;
+ bmiLocal.bmiColors[0].rgbReserved = 0;
+ bmiLocal.bmiColors[1].rgbRed =0xFF ;
+ bmiLocal.bmiColors[1].rgbGreen = 0xFF;
+ bmiLocal.bmiColors[1].rgbBlue = 0xFF;
+ bmiLocal.bmiColors[1].rgbReserved = 0;
+ break;
+ case 4:
+ RtlCopyMemory(bmiLocal.bmiColors, EGAColorsQuads, sizeof(EGAColorsQuads));
+ break;
+ case 8:
+ {
+ INT r, g, b;
+ RGBQUAD *color;
+
+ RtlCopyMemory(bmiLocal.bmiColors, DefLogPaletteQuads, 10 * sizeof(RGBQUAD));
+ RtlCopyMemory(bmiLocal.bmiColors + 246, DefLogPaletteQuads + 10, 10 * sizeof(RGBQUAD));
+ color = bmiLocal.bmiColors + 10;
+ for (r = 0; r <= 5; r++) /* FIXME */
+ for (g = 0; g <= 5; g++)
+ for (b = 0; b <= 5; b++)
+ {
+ color->rgbRed = (r * 0xff) / 5;
+ color->rgbGreen = (g * 0xff) / 5;
+ color->rgbBlue = (b * 0xff) / 5;
+ color->rgbReserved = 0;
+ color++;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ case 15:
+ if (bmiLocal.bmiHeader.bV5Compression == BI_BITFIELDS)
+ {
+ bmiLocal.bmiHeader.bV5RedMask = 0x7c00;
+ bmiLocal.bmiHeader.bV5GreenMask = 0x03e0;
+ bmiLocal.bmiHeader.bV5BlueMask = 0x001f;
+ }
+ break;
+
+ case 16:
+ if (bmiLocal.bmiHeader.bV5Compression == BI_BITFIELDS)
+ {
+ bmiLocal.bmiHeader.bV5RedMask = 0xf800;
+ bmiLocal.bmiHeader.bV5GreenMask = 0x07e0;
+ bmiLocal.bmiHeader.bV5BlueMask = 0x001f;
+ }
+ break;
+
+ case 24:
+ case 32:
+ if (bmiLocal.bmiHeader.bV5Compression == BI_BITFIELDS)
+ {
+ bmiLocal.bmiHeader.bV5RedMask = 0xff0000;
+ bmiLocal.bmiHeader.bV5GreenMask = 0x00ff00;
+ bmiLocal.bmiHeader.bV5BlueMask = 0x0000ff;
+ }
+ break;
+ }
+
+ /* fill out the BITMAPINFO struct */
+ if (!ChkBits)
+ {
+ bmiLocal.bmiHeader.bV5Width = psurf->SurfObj.sizlBitmap.cx;
+ /* Report negative height for top-down bitmaps. */
+ if (psurf->SurfObj.fjBitmap & BMF_TOPDOWN)
+ bmiLocal.bmiHeader.bV5Height = - psurf->SurfObj.sizlBitmap.cy;
+ else
+ bmiLocal.bmiHeader.bV5Height = psurf->SurfObj.sizlBitmap.cy;
+ bmiLocal.bmiHeader.bV5Planes = 1;
+ bmiLocal.bmiHeader.bV5BitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
+ switch (psurf->SurfObj.iBitmapFormat)
+ {
+ /* FIXME: What about BI_BITFIELDS? */
+ case BMF_1BPP:
+ case BMF_4BPP:
+ case BMF_8BPP:
+ case BMF_16BPP:
+ case BMF_24BPP:
+ case BMF_32BPP:
+ bmiLocal.bmiHeader.bV5Compression = BI_RGB;
+ break;
+ case BMF_4RLE:
+ bmiLocal.bmiHeader.bV5Compression = BI_RLE4;
+ break;
+ case BMF_8RLE:
+ bmiLocal.bmiHeader.bV5Compression = BI_RLE8;
+ break;
+ case BMF_JPEG:
+ bmiLocal.bmiHeader.bV5Compression = BI_JPEG;
+ break;
+ case BMF_PNG:
+ bmiLocal.bmiHeader.bV5Compression = BI_PNG;
+ break;
+ }
+
+ bmiLocal.bmiHeader.bV5SizeImage = psurf->SurfObj.cjBits;
+ bmiLocal.bmiHeader.bV5XPelsPerMeter = psurf->sizlDim.cx; /* FIXME */
+ bmiLocal.bmiHeader.bV5YPelsPerMeter = psurf->sizlDim.cy; /* FIXME */
+ bmiLocal.bmiHeader.bV5ClrUsed = 0;
+ bmiLocal.bmiHeader.bV5ClrImportant = 1 << bmiLocal.bmiHeader.bV5BitCount; /* FIXME */
+ Result = psurf->SurfObj.sizlBitmap.cy;
+ }
+ else
+ {
+ SIZEL DestSize;
+ POINTL SourcePoint;
+
+//
+// If we have a good dib pointer, why not just copy bits from there w/o XLATE'ing them.
+//
+ /* Create the destination bitmap too for the copy operation */
+ if (StartScan > psurf->SurfObj.sizlBitmap.cy)
+ {
+ goto cleanup;
+ }
+ else
+ {
+ ScanLines = min(ScanLines, psurf->SurfObj.sizlBitmap.cy - StartScan);
+ DestSize.cx = psurf->SurfObj.sizlBitmap.cx;
+ DestSize.cy = ScanLines;
+
+ hDestBitmap = NULL;
+
+ bmiLocal.bmiHeader.bV5SizeImage = DIB_GetDIBWidthBytes(DestSize.cx,
+ bmiLocal.bmiHeader.bV5BitCount) * DestSize.cy;
+
+ hDestBitmap = EngCreateBitmap(DestSize,
+ DIB_GetDIBWidthBytes(DestSize.cx,
+ bmiLocal.bmiHeader.bV5BitCount),
+ BitmapFormat(bmiLocal.bmiHeader.bV5BitCount,
+ bmiLocal.bmiHeader.bV5Compression),
+ bmiLocal.bmiHeader.bV5Height > 0 ? 0 : BMF_TOPDOWN,
+ Bits);
+
+ if (hDestBitmap == NULL)
+ goto cleanup;
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ EXLATEOBJ exlo;
+ SURFOBJ *DestSurfObj;
+ RECTL DestRect;
+
+ EXLATEOBJ_vInitialize(&exlo, psurf->ppal, ppalDst, 0, 0, 0);
+
+ SourcePoint.x = 0;
+ SourcePoint.y = psurf->SurfObj.sizlBitmap.cy - (StartScan + ScanLines);
+
+ /* Determine destination rectangle */
+ DestRect.top = 0;
+ DestRect.left = 0;
+ DestRect.right = DestSize.cx;
+ DestRect.bottom = DestSize.cy;
+
+ DestSurfObj = EngLockSurface((HSURF)hDestBitmap);
+
+ if (IntEngCopyBits(DestSurfObj,
+ &psurf->SurfObj,
+ NULL,
+ &exlo.xlo,
+ &DestRect,
+ &SourcePoint))
+ {
+ DPRINT("GetDIBits %d \n",abs(bmiLocal.bmiHeader.bV5Height) - StartScan);
+ Result = ScanLines;
+ }
+
+ EXLATEOBJ_vCleanup(&exlo);
+ EngUnlockSurface(DestSurfObj);
+ }
+ }
+
+ /* Now that everything is over, get back the information to caller */
+ _SEH2_TRY
+ {
+ /* Note : Info has already been probed */
+ GetBMIFromBitmapV5Info(&bmiLocal, Info, Usage);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* FIXME: fail or something */
+ }
+ _SEH2_END
+
+cleanup:
+
+ if (hDestBitmap != NULL)
+ EngDeleteSurface((HSURF)hDestBitmap);
+
+ if (hDestPalette != NULL && !bPaletteMatch)
+ {
+ PALETTE_UnlockPalette(ppalDst);
+ PALETTE_FreePaletteByHandle(hDestPalette);
+ }
+
+ SURFACE_UnlockSurface(psurf);
+
+ DPRINT("leaving NtGdiGetDIBitsInternal\n");
+
+ return Result;
+}
+
+INT
+APIENTRY
+NtGdiStretchDIBitsInternal(
+ HDC hDC,
+ INT XDest,
+ INT YDest,
+ INT DestWidth,
+ INT DestHeight,
+ INT XSrc,
+ INT YSrc,
+ INT SrcWidth,
+ INT SrcHeight,
+ LPBYTE Bits,
+ LPBITMAPINFO BitsInfo,
+ DWORD Usage,
+ DWORD ROP,
+ UINT cjMaxInfo,
+ UINT cjMaxBits,
+ HANDLE hcmXform)
+{
+ HBITMAP hBitmap, hOldBitmap = NULL;
+ HDC hdcMem;
+ HPALETTE hPal = NULL;
+ PDC pDC;
+ NTSTATUS Status;
+ BITMAPV5INFO bmiLocal ;
+
+ if (!Bits || !BitsInfo)
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ _SEH2_TRY
+ {
+ Status = ProbeAndConvertToBitmapV5Info(&bmiLocal, BitsInfo, Usage, cjMaxInfo);
+ ProbeForRead(Bits, cjMaxBits, 1);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtGdiStretchDIBitsInternal fail to read BitMapInfo: %x or Bits: %x\n",BitsInfo,Bits);
+ return 0;
+ }
+
+ hdcMem = NtGdiCreateCompatibleDC(hDC);
+ if (hdcMem == NULL)
+ {
+ DPRINT1("NtGdiCreateCompatibleDC fail create hdc\n");
+ return 0;
+ }
+
+ hBitmap = NtGdiCreateCompatibleBitmap(hDC,
+ abs(bmiLocal.bmiHeader.bV5Width),
+ abs(bmiLocal.bmiHeader.bV5Height));
+ if (hBitmap == NULL)
+ {
+ DPRINT1("NtGdiCreateCompatibleBitmap fail create bitmap\n");
+ DPRINT1("hDC : 0x%08x \n", hDC);
+ DPRINT1("BitsInfo->bmiHeader.biWidth : 0x%08x \n", BitsInfo->bmiHeader.biWidth);
+ DPRINT1("BitsInfo->bmiHeader.biHeight : 0x%08x \n", BitsInfo->bmiHeader.biHeight);
+ return 0;
+ }
+
+ /* Select the bitmap into hdcMem, and save a handle to the old bitmap */
+ hOldBitmap = NtGdiSelectBitmap(hdcMem, hBitmap);
+
+ if (Usage == DIB_PAL_COLORS)
+ {
+ hPal = NtGdiGetDCObject(hDC, GDI_OBJECT_TYPE_PALETTE);
+ hPal = GdiSelectPalette(hdcMem, hPal, FALSE);
+ }
+
+ if (bmiLocal.bmiHeader.bV5Compression == BI_RLE4 ||
+ bmiLocal.bmiHeader.bV5Compression == BI_RLE8)
+ {
+ /* copy existing bitmap from destination dc */
+ if (SrcWidth == DestWidth && SrcHeight == DestHeight)
+ NtGdiBitBlt(hdcMem, XSrc, abs(bmiLocal.bmiHeader.bV5Height) - SrcHeight - YSrc,
+ SrcWidth, SrcHeight, hDC, XDest, YDest, ROP, 0, 0);
+ else
+ NtGdiStretchBlt(hdcMem, XSrc, abs(bmiLocal.bmiHeader.bV5Height) - SrcHeight - YSrc,
+ SrcWidth, SrcHeight, hDC, XDest, YDest, DestWidth, DestHeight,
+ ROP, 0);
+ }
+
+ pDC = DC_LockDc(hdcMem);
+ if (pDC != NULL)
+ {
+ /* Note BitsInfo->bmiHeader.biHeight is the number of scanline,
+ * if it negitve we getting to many scanline for scanline is UINT not
+ * a INT, so we need make the negtive value to positve and that make the
+ * count correct for negtive bitmap, TODO : we need testcase for this api */
+ IntSetDIBits(pDC, hBitmap, 0, abs(bmiLocal.bmiHeader.bV5Height), Bits,
+ (PBITMAPINFO)&bmiLocal, Usage);
+
+ DC_UnlockDc(pDC);
+ }
+
+
+ /* Origin for DIBitmap may be bottom left (positive biHeight) or top
+ left (negative biHeight) */
+ if (SrcWidth == DestWidth && SrcHeight == DestHeight)
+ NtGdiBitBlt(hDC, XDest, YDest, DestWidth, DestHeight,
+ hdcMem, XSrc, abs(bmiLocal.bmiHeader.bV5Height) - SrcHeight - YSrc,
+ ROP, 0, 0);
+ else
+ NtGdiStretchBlt(hDC, XDest, YDest, DestWidth, DestHeight,
+ hdcMem, XSrc, abs(bmiLocal.bmiHeader.bV5Height) - SrcHeight - YSrc,
+ SrcWidth, SrcHeight, ROP, 0);
+
+ /* cleanup */
+ if (hPal)
+ GdiSelectPalette(hdcMem, hPal, FALSE);
+
+ if (hOldBitmap)
+ NtGdiSelectBitmap(hdcMem, hOldBitmap);
+
+ NtGdiDeleteObjectApp(hdcMem);
+
+ GreDeleteObject(hBitmap);
+
+ return SrcHeight;
+}
+
+
+HBITMAP
+FASTCALL
+IntCreateDIBitmap(
+ PDC Dc,
+ INT width,
+ INT height,
+ UINT bpp,
+ DWORD init,
+ LPBYTE bits,
+ PBITMAPV5INFO data,
+ DWORD coloruse)
+{
+ HBITMAP handle;
+ BOOL fColor;
+
+ // Check if we should create a monochrome or color bitmap. We create a monochrome bitmap only if it has exactly 2
+ // colors, which are black followed by white, nothing else. In all other cases, we create a color bitmap.
+
+ if (bpp != 1) fColor = TRUE;
+ else if ((coloruse != DIB_RGB_COLORS) || (init != CBM_INIT) || !data) fColor = FALSE;
+ else
+ {
+ const RGBQUAD *rgb = data->bmiColors;
+ DWORD col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
+
+ // Check if the first color of the colormap is black
+ if ((col == RGB(0, 0, 0)))
+ {
+ rgb++;
+ col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
+
+ // If the second color is white, create a monochrome bitmap
+ fColor = (col != RGB(0xff,0xff,0xff));
+ }
+ else fColor = TRUE;
+ }
+
+ // Now create the bitmap
+ if (fColor)
+ {
+ handle = IntCreateCompatibleBitmap(Dc, width, height);
+ }
+ else
+ {
+ handle = GreCreateBitmap(width,
+ height,
+ 1,
+ 1,
+ NULL);
+ }
+
+ if (height < 0)
+ height = -height;
+
+ if (NULL != handle && CBM_INIT == init)
+ {
+ IntSetDIBits(Dc, handle, 0, height, bits, (BITMAPINFO*)data, coloruse);
+ }
+
+ return handle;
+}
+
+// The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits
+// The DDB that is created will be whatever bit depth your reference DC is
+HBITMAP
+APIENTRY
+NtGdiCreateDIBitmapInternal(
+ IN HDC hDc,
+ IN INT cx,
+ IN INT cy,
+ IN DWORD fInit,
+ IN OPTIONAL LPBYTE pjInit,
+ IN OPTIONAL LPBITMAPINFO pbmi,
+ IN DWORD iUsage,
+ IN UINT cjMaxInitInfo,
+ IN UINT cjMaxBits,
+ IN FLONG fl,
+ IN HANDLE hcmXform)
+{
+ BITMAPV5INFO bmiLocal ;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ _SEH2_TRY
+ {
+ if(pbmi) Status = ProbeAndConvertToBitmapV5Info(&bmiLocal, pbmi, iUsage, cjMaxInitInfo);
+ if(pjInit && (fInit == CBM_INIT)) ProbeForRead(pjInit, cjMaxBits, 1);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if(!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ return NULL;
+ }
+
+ return GreCreateDIBitmapInternal(hDc,
+ cx,
+ cy,
+ fInit,
+ pjInit,
+ pbmi ? &bmiLocal : NULL,
+ iUsage,
+ fl,
+ hcmXform);
+}
+
+HBITMAP
+FASTCALL
+GreCreateDIBitmapInternal(
+ IN HDC hDc,
+ IN INT cx,
+ IN INT cy,
+ IN DWORD fInit,
+ IN OPTIONAL LPBYTE pjInit,
+ IN OPTIONAL PBITMAPV5INFO pbmi,
+ IN DWORD iUsage,
+ IN FLONG fl,
+ IN HANDLE hcmXform)
+{
+ PDC Dc;
+ HBITMAP Bmp;
+ WORD bpp;
+ HDC hdcDest;
+
+ if (!hDc) /* 1bpp monochrome bitmap */
+ { // Should use System Bitmap DC hSystemBM, with CreateCompatibleDC for this.
+ hdcDest = IntGdiCreateDC(NULL, NULL, NULL, NULL,FALSE);
+ if(!hdcDest)
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ hdcDest = hDc;
+ }
+
+ Dc = DC_LockDc(hdcDest);
+ if (!Dc)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return NULL;
+ }
+ /* It's OK to set bpp=0 here, as IntCreateDIBitmap will create a compatible Bitmap
+ * if bpp != 1 and ignore the real value that was passed */
+ if (pbmi)
+ bpp = pbmi->bmiHeader.bV5BitCount;
+ else
+ bpp = 0;
+ Bmp = IntCreateDIBitmap(Dc, cx, cy, bpp, fInit, pjInit, pbmi, iUsage);
+ DC_UnlockDc(Dc);
+
+ if(!hDc)
+ {
+ NtGdiDeleteObjectApp(hdcDest);
+ }
+ return Bmp;
+}
+
+
+HBITMAP
+APIENTRY
+NtGdiCreateDIBSection(
+ IN HDC hDC,
+ IN OPTIONAL HANDLE hSection,
+ IN DWORD dwOffset,
+ IN LPBITMAPINFO bmi,
+ IN DWORD Usage,
+ IN UINT cjHeader,
+ IN FLONG fl,
+ IN ULONG_PTR dwColorSpace,
+ OUT PVOID *Bits)
+{
+ HBITMAP hbitmap = 0;
+ DC *dc;
+ BOOL bDesktopDC = FALSE;
+
+ if (!bmi) return hbitmap; // Make sure.
+
+ // If the reference hdc is null, take the desktop dc
+ if (hDC == 0)
+ {
+ hDC = NtGdiCreateCompatibleDC(0);
+ bDesktopDC = TRUE;
+ }
+
+ if ((dc = DC_LockDc(hDC)))
+ {
+ hbitmap = DIB_CreateDIBSection(dc,
+ (BITMAPINFO*)bmi,
+ Usage,
+ Bits,
+ hSection,
+ dwOffset,
+ 0);
+ DC_UnlockDc(dc);
+ }
+ else
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ }
+
+ if (bDesktopDC)
+ NtGdiDeleteObjectApp(hDC);
+
+ return hbitmap;
+}
+
+HBITMAP
+APIENTRY
+DIB_CreateDIBSection(
+ PDC dc,
+ BITMAPINFO *bmi,
+ UINT usage,
+ LPVOID *bits,
+ HANDLE section,
+ DWORD offset,
+ DWORD ovr_pitch)
+{
+ HBITMAP res = 0;
+ SURFACE *bmp = NULL;
+ void *mapBits = NULL;
- pdcattr = dc->pdcattr;
-
+ HPALETTE hpal ;
+
+ // Fill BITMAP32 structure with DIB data
+ BITMAPINFOHEADER *bi = &bmi->bmiHeader;
+ INT effHeight;
+ ULONG totalSize;
+ BITMAP bm;
+ SIZEL Size;
+ RGBQUAD *lpRGB;
+ HANDLE hSecure;
+ DWORD dsBitfields[3] = {0};
+ ULONG ColorCount;
+
+ DPRINT("format (%ld,%ld), planes %d, bpp %d, size %ld, colors %ld (%s)\n",
+ bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
+ bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
+
+ /* CreateDIBSection should fail for compressed formats */
+ if (bi->biCompression == BI_RLE4 || bi->biCompression == BI_RLE8)
+ {
+ return (HBITMAP)NULL;
+ }
+
- if (res) pdcattr->ulDirty_ |= DC_DIBSECTION;
-
+ effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight;
+ bm.bmType = 0;
+ bm.bmWidth = bi->biWidth;
+ bm.bmHeight = effHeight;
+ bm.bmWidthBytes = ovr_pitch ? ovr_pitch : (ULONG) DIB_GetDIBWidthBytes(bm.bmWidth, bi->biBitCount);
+
+ bm.bmPlanes = bi->biPlanes;
+ bm.bmBitsPixel = bi->biBitCount;
+ bm.bmBits = NULL;
+
+ // Get storage location for DIB bits. Only use biSizeImage if it's valid and
+ // we're dealing with a compressed bitmap. Otherwise, use width * height.
+ totalSize = bi->biSizeImage && bi->biCompression != BI_RGB
+ ? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight);
+
+ if (section)
+ {
+ SYSTEM_BASIC_INFORMATION Sbi;
+ NTSTATUS Status;
+ DWORD mapOffset;
+ LARGE_INTEGER SectionOffset;
+ SIZE_T mapSize;
+
+ Status = ZwQuerySystemInformation(SystemBasicInformation,
+ &Sbi,
+ sizeof Sbi,
+ 0);
+ if (!NT_SUCCESS(Status))
+ {
+ return NULL;
+ }
+
+ mapOffset = offset - (offset % Sbi.AllocationGranularity);
+ mapSize = bi->biSizeImage + (offset - mapOffset);
+
+ SectionOffset.LowPart = mapOffset;
+ SectionOffset.HighPart = 0;
+
+ Status = ZwMapViewOfSection(section,
+ NtCurrentProcess(),
+ &mapBits,
+ 0,
+ 0,
+ &SectionOffset,
+ &mapSize,
+ ViewShare,
+ 0,
+ PAGE_READWRITE);
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return NULL;
+ }
+
+ if (mapBits) bm.bmBits = (char *)mapBits + (offset - mapOffset);
+ }
+ else if (ovr_pitch && offset)
+ bm.bmBits = (LPVOID) offset;
+ else
+ {
+ offset = 0;
+ bm.bmBits = EngAllocUserMem(totalSize, 0);
+ }
+
+// hSecure = MmSecureVirtualMemory(bm.bmBits, totalSize, PAGE_READWRITE);
+ hSecure = (HANDLE)0x1; // HACK OF UNIMPLEMENTED KERNEL STUFF !!!!
+
+ if (usage == DIB_PAL_COLORS)
+ {
+ lpRGB = DIB_MapPaletteColors(dc, bmi);
+ ColorCount = bi->biClrUsed;
+ if (ColorCount == 0)
+ {
+ ColorCount = 1 << bi->biBitCount;
+ }
+ }
+ else
+ {
+ lpRGB = bmi->bmiColors;
+ ColorCount = 1 << bi->biBitCount;
+ }
+
+ /* Set dsBitfields values */
+ if (usage == DIB_PAL_COLORS || bi->biBitCount <= 8)
+ {
+ dsBitfields[0] = dsBitfields[1] = dsBitfields[2] = 0;
+ }
+ else if (bi->biCompression == BI_RGB)
+ {
+ switch (bi->biBitCount)
+ {
+ case 15:
+ dsBitfields[0] = 0x7c00;
+ dsBitfields[1] = 0x03e0;
+ dsBitfields[2] = 0x001f;
+ break;
+
+ case 16:
+ dsBitfields[0] = 0xF800;
+ dsBitfields[1] = 0x07e0;
+ dsBitfields[2] = 0x001f;
+ break;
+
+ case 24:
+ case 32:
+ dsBitfields[0] = 0xff0000;
+ dsBitfields[1] = 0x00ff00;
+ dsBitfields[2] = 0x0000ff;
+ break;
+ }
+ }
+ else
+ {
+ dsBitfields[0] = ((DWORD*)bmi->bmiColors)[0];
+ dsBitfields[1] = ((DWORD*)bmi->bmiColors)[1];
+ dsBitfields[2] = ((DWORD*)bmi->bmiColors)[2];
+ }
+
+ // Create Device Dependent Bitmap and add DIB pointer
+ Size.cx = bm.bmWidth;
+ Size.cy = abs(bm.bmHeight);
+ res = GreCreateBitmapEx(bm.bmWidth,
+ abs(bm.bmHeight),
+ bm.bmWidthBytes,
+ BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression),
+ BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT |
+ (bi->biHeight < 0 ? BMF_TOPDOWN : 0),
+ bi->biSizeImage,
+ bm.bmBits);
+ if (!res)
+ {
+ if (lpRGB != bmi->bmiColors)
+ {
+ ExFreePoolWithTag(lpRGB, TAG_COLORMAP);
+ }
+ SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
+ return NULL;
+ }
+ bmp = SURFACE_LockSurface(res);
+ if (NULL == bmp)
+ {
+ if (lpRGB != bmi->bmiColors)
+ {
+ ExFreePoolWithTag(lpRGB, TAG_COLORMAP);
+ }
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ GreDeleteObject(res);
+ return NULL;
+ }
+
+ /* WINE NOTE: WINE makes use of a colormap, which is a color translation
+ table between the DIB and the X physical device. Obviously,
+ this is left out of the ReactOS implementation. Instead,
+ we call NtGdiSetDIBColorTable. */
+ if (bi->biBitCount <= 8)
+ {
+ bi->biClrUsed = 1 << bi->biBitCount;
+ }
+ else
+ {
+ bi->biClrUsed = 0;
+ }
+
+ bmp->hDIBSection = section;
+ bmp->hSecure = hSecure;
+ bmp->dwOffset = offset;
+ bmp->flags = API_BITMAP;
+ bmp->dsBitfields[0] = dsBitfields[0];
+ bmp->dsBitfields[1] = dsBitfields[1];
+ bmp->dsBitfields[2] = dsBitfields[2];
+ bmp->biClrUsed = bi->biClrUsed;
+ bmp->biClrImportant = bi->biClrImportant;
+
+ if (bi->biClrUsed != 0)
+ {
+ hpal = PALETTE_AllocPaletteIndexedRGB(ColorCount, lpRGB);
+ }
+ else
+ {
+ hpal = PALETTE_AllocPalette(PAL_BITFIELDS, 0, NULL,
+ dsBitfields[0],
+ dsBitfields[1],
+ dsBitfields[2]);
+ }
+
+ bmp->ppal = PALETTE_ShareLockPalette(hpal);
+ /* Lazy delete hpal, it will be freed at surface release */
+ GreDeleteObject(hpal);
+
+ // Clean up in case of errors
+ if (!res || !bmp || !bm.bmBits)
+ {
+ DPRINT("got an error res=%08x, bmp=%p, bm.bmBits=%p\n", res, bmp, bm.bmBits);
+ if (bm.bmBits)
+ {
+ // MmUnsecureVirtualMemory(hSecure); // FIXME: Implement this!
+ if (section)
+ {
+ ZwUnmapViewOfSection(NtCurrentProcess(), mapBits);
+ bm.bmBits = NULL;
+ }
+ else
+ if (!offset)
+ EngFreeUserMem(bm.bmBits), bm.bmBits = NULL;
+ }
+
+ if (bmp)
+ bmp = NULL;
+
+ if (res)
+ {
+ SURFACE_FreeSurfaceByHandle(res);
+ res = 0;
+ }
+ }
+
+ if (lpRGB != bmi->bmiColors)
+ {
+ ExFreePoolWithTag(lpRGB, TAG_COLORMAP);
+ }
+
+ if (bmp)
+ {
+ SURFACE_UnlockSurface(bmp);
+ }
+
+ // Return BITMAP handle and storage location
+ if (NULL != bm.bmBits && NULL != bits)
+ {
+ *bits = bm.bmBits;
+ }
+
+ return res;
+}
+
+/***********************************************************************
+ * DIB_GetDIBWidthBytes
+ *
+ * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
+ * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/struc/src/str01.htm
+ * 11/16/1999 (RJJ) lifted from wine
+ */
+INT FASTCALL DIB_GetDIBWidthBytes(INT width, INT depth)
+{
+ return ((width * depth + 31) & ~31) >> 3;
+}
+
+/***********************************************************************
+ * DIB_GetDIBImageBytes
+ *
+ * Return the number of bytes used to hold the image in a DIB bitmap.
+ * 11/16/1999 (RJJ) lifted from wine
+ */
+
+INT APIENTRY DIB_GetDIBImageBytes(INT width, INT height, INT depth)
+{
+ return DIB_GetDIBWidthBytes(width, depth) * (height < 0 ? -height : height);
+}
+
+/***********************************************************************
+ * DIB_BitmapInfoSize
+ *
+ * Return the size of the bitmap info structure including color table.
+ * 11/16/1999 (RJJ) lifted from wine
+ */
+
+INT FASTCALL DIB_BitmapInfoSize(const BITMAPINFO * info, WORD coloruse)
+{
+ int colors;
+
+ if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
+ {
+ BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)info;
+ colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
+ return sizeof(BITMAPCOREHEADER) + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
+ }
+ else /* assume BITMAPINFOHEADER */
+ {
+ colors = info->bmiHeader.biClrUsed;
+ if (!colors && (info->bmiHeader.biBitCount <= 8)) colors = 1 << info->bmiHeader.biBitCount;
+ return info->bmiHeader.biSize + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
+ }
+}
+
+RGBQUAD *
+FASTCALL
+DIB_MapPaletteColors(PDC dc, CONST BITMAPINFO* lpbmi)
+{
+ RGBQUAD *lpRGB;
+ ULONG nNumColors,i;
+ USHORT *lpIndex;
+ PPALETTE palGDI;
+
+ palGDI = PALETTE_LockPalette(dc->dclevel.hpal);
+
+ if (NULL == palGDI)
+ {
+ return NULL;
+ }
+
+ if (palGDI->Mode != PAL_INDEXED)
+ {
+ PALETTE_UnlockPalette(palGDI);
+ return NULL;
+ }
+
+ nNumColors = 1 << lpbmi->bmiHeader.biBitCount;
+ if (lpbmi->bmiHeader.biClrUsed)
+ {
+ nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed);
+ }
+
+ lpRGB = (RGBQUAD *)ExAllocatePoolWithTag(PagedPool, sizeof(RGBQUAD) * nNumColors, TAG_COLORMAP);
+ if (lpRGB == NULL)
+ {
+ PALETTE_UnlockPalette(palGDI);
+ return NULL;
+ }
+
+ lpIndex = (USHORT *)&lpbmi->bmiColors[0];
+
+ for (i = 0; i < nNumColors; i++)
+ {
+ if (*lpIndex < palGDI->NumColors)
+ {
+ lpRGB[i].rgbRed = palGDI->IndexedColors[*lpIndex].peRed;
+ lpRGB[i].rgbGreen = palGDI->IndexedColors[*lpIndex].peGreen;
+ lpRGB[i].rgbBlue = palGDI->IndexedColors[*lpIndex].peBlue;
+ }
+ else
+ {
+ lpRGB[i].rgbRed = 0;
+ lpRGB[i].rgbGreen = 0;
+ lpRGB[i].rgbBlue = 0;
+ }
+ lpRGB[i].rgbReserved = 0;
+ lpIndex++;
+ }
+ PALETTE_UnlockPalette(palGDI);
+
+ return lpRGB;
+}
+
+HPALETTE
+FASTCALL
+BuildDIBPalette(CONST BITMAPINFO *bmi, PINT paletteType)
+{
+ BYTE bits;
+ ULONG ColorCount;
+ HPALETTE hPal;
+ ULONG RedMask, GreenMask, BlueMask;
+ PDWORD pdwColors = (PDWORD)((PBYTE)bmi + bmi->bmiHeader.biSize);
+
+ // Determine Bits Per Pixel
+ bits = bmi->bmiHeader.biBitCount;
+
+ // Determine paletteType from Bits Per Pixel
+ if (bits <= 8)
+ {
+ *paletteType = PAL_INDEXED;
+ RedMask = GreenMask = BlueMask = 0;
+ }
+ else if (bmi->bmiHeader.biCompression == BI_BITFIELDS)
+ {
+ *paletteType = PAL_BITFIELDS;
+ RedMask = pdwColors[0];
+ GreenMask = pdwColors[1];
+ BlueMask = pdwColors[2];
+ }
+ else if (bits == 15)
+ {
+ *paletteType = PAL_BITFIELDS;
+ RedMask = 0x7c00;
+ GreenMask = 0x03e0;
+ BlueMask = 0x001f;
+ }
+ else if (bits == 16)
+ {
+ *paletteType = PAL_BITFIELDS;
+ RedMask = 0xF800;
+ GreenMask = 0x07e0;
+ BlueMask = 0x001f;
+ }
+ else
+ {
+ *paletteType = PAL_BGR;
+ RedMask = 0xff0000;
+ GreenMask = 0x00ff00;
+ BlueMask = 0x0000ff;
+ }
+
+ if (bmi->bmiHeader.biClrUsed == 0)
+ {
+ ColorCount = 1 << bmi->bmiHeader.biBitCount;
+ }
+ else
+ {
+ ColorCount = bmi->bmiHeader.biClrUsed;
+ }
+
+ if (PAL_INDEXED == *paletteType)
+ {
+ hPal = PALETTE_AllocPaletteIndexedRGB(ColorCount, (RGBQUAD*)pdwColors);
+ }
+ else
+ {
+ hPal = PALETTE_AllocPalette(*paletteType, ColorCount,
+ NULL,
+ RedMask, GreenMask, BlueMask);
+ }
+
+ return hPal;
+}
+
+FORCEINLINE
+DWORD
+GetBMIColor(CONST BITMAPINFO* pbmi, INT i)
+{
+ DWORD dwRet = 0;
+ INT size;
+ if(pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
+ {
+ /* BITMAPCOREINFO holds RGBTRIPLE values */
+ size = sizeof(RGBTRIPLE);
+ }
+ else
+ {
+ size = sizeof(RGBQUAD);
+ }
+ memcpy(&dwRet, (PBYTE)pbmi + pbmi->bmiHeader.biSize + i*size, size);
+ return dwRet;
+}
+
+FORCEINLINE
+VOID
+SetBMIColor(CONST BITMAPINFO* pbmi, DWORD* color, INT i)
+{
+ PVOID pvColors = ((PBYTE)pbmi + pbmi->bmiHeader.biSize);
+ if(pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
+ {
+ RGBTRIPLE *pColor = pvColors;
+ pColor[i] = *(RGBTRIPLE*)color;
+ }
+ else
+ {
+ RGBQUAD *pColor = pvColors;
+ pColor[i] = *(RGBQUAD*)color;
+ }
+}
+
+NTSTATUS
+FASTCALL
+ProbeAndConvertToBitmapV5Info(
+ OUT PBITMAPV5INFO pbmiDst,
+ IN CONST BITMAPINFO* pbmiUnsafe,
+ IN DWORD dwColorUse,
+ IN UINT MaxSize)
+{
+ DWORD dwSize;
+ ULONG ulWidthBytes;
+ PBITMAPV5HEADER pbmhDst = &pbmiDst->bmiHeader;
+
+ /* Get the size and probe */
+ ProbeForRead(&pbmiUnsafe->bmiHeader.biSize, sizeof(DWORD), 1);
+ dwSize = pbmiUnsafe->bmiHeader.biSize;
+ /* At least dwSize bytes must be valids */
+ ProbeForRead(pbmiUnsafe, max(dwSize, MaxSize), 1);
+
+ /* Check the size */
+ // FIXME: are intermediate sizes allowed? As what are they interpreted?
+ // make sure we don't use a too big dwSize later
+ if (dwSize != sizeof(BITMAPCOREHEADER) &&
+ dwSize != sizeof(BITMAPINFOHEADER) &&
+ dwSize != sizeof(BITMAPV4HEADER) &&
+ dwSize != sizeof(BITMAPV5HEADER))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (dwSize == sizeof(BITMAPCOREHEADER))
+ {
+ PBITMAPCOREHEADER pbch = (PBITMAPCOREHEADER)pbmiUnsafe;
+
+ /* Manually copy the fields that are present */
+ pbmhDst->bV5Width = pbch->bcWidth;
+ pbmhDst->bV5Height = pbch->bcHeight;
+ pbmhDst->bV5Planes = pbch->bcPlanes;
+ pbmhDst->bV5BitCount = pbch->bcBitCount;
+
+ /* Set some default values */
+ pbmhDst->bV5Compression = BI_RGB;
+ pbmhDst->bV5SizeImage = DIB_GetDIBImageBytes(pbch->bcWidth,
+ pbch->bcHeight,
+ pbch->bcPlanes*pbch->bcBitCount) ;
+ pbmhDst->bV5XPelsPerMeter = 72;
+ pbmhDst->bV5YPelsPerMeter = 72;
+ pbmhDst->bV5ClrUsed = 0;
+ pbmhDst->bV5ClrImportant = 0;
+ }
+ else
+ {
+ /* Copy valid fields */
+ memcpy(pbmiDst, pbmiUnsafe, dwSize);
+ if(!pbmhDst->bV5SizeImage)
+ pbmhDst->bV5SizeImage = DIB_GetDIBImageBytes(pbmhDst->bV5Width,
+ pbmhDst->bV5Height,
+ pbmhDst->bV5Planes*pbmhDst->bV5BitCount) ;
+
+ if(dwSize < sizeof(BITMAPV5HEADER))
+ {
+ /* Zero out the rest of the V5 header */
+ memset((char*)pbmiDst + dwSize, 0, sizeof(BITMAPV5HEADER) - dwSize);
+ }
+ }
+ pbmhDst->bV5Size = sizeof(BITMAPV5HEADER);
+
+
+ if (dwSize < sizeof(BITMAPV4HEADER))
+ {
+ if (pbmhDst->bV5Compression == BI_BITFIELDS)
+ {
+ pbmhDst->bV5RedMask = GetBMIColor(pbmiUnsafe, 0);
+ pbmhDst->bV5GreenMask = GetBMIColor(pbmiUnsafe, 1);
+ pbmhDst->bV5BlueMask = GetBMIColor(pbmiUnsafe, 2);
+ pbmhDst->bV5AlphaMask = 0;
+ pbmhDst->bV5ClrUsed = 0;
+ }
+
+// pbmhDst->bV5CSType;
+// pbmhDst->bV5Endpoints;
+// pbmhDst->bV5GammaRed;
+// pbmhDst->bV5GammaGreen;
+// pbmhDst->bV5GammaBlue;
+ }
+
+ if (dwSize < sizeof(BITMAPV5HEADER))
+ {
+// pbmhDst->bV5Intent;
+// pbmhDst->bV5ProfileData;
+// pbmhDst->bV5ProfileSize;
+// pbmhDst->bV5Reserved;
+ }
+
+ ulWidthBytes = ((pbmhDst->bV5Width * pbmhDst->bV5Planes *
+ pbmhDst->bV5BitCount + 31) & ~31) / 8;
+
+ if (pbmhDst->bV5SizeImage == 0)
+ pbmhDst->bV5SizeImage = abs(ulWidthBytes * pbmhDst->bV5Height);
+
+ if (pbmhDst->bV5ClrUsed == 0)
+ {
+ switch(pbmhDst->bV5BitCount)
+ {
+ case 1:
+ pbmhDst->bV5ClrUsed = 2;
+ break;
+ case 4:
+ pbmhDst->bV5ClrUsed = 16;
+ break;
+ case 8:
+ pbmhDst->bV5ClrUsed = 256;
+ break;
+ default:
+ pbmhDst->bV5ClrUsed = 0;
+ break;
+ }
+ }
+
+ if (pbmhDst->bV5Planes != 1)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (pbmhDst->bV5BitCount != 0 && pbmhDst->bV5BitCount != 1 &&
+ pbmhDst->bV5BitCount != 4 && pbmhDst->bV5BitCount != 8 &&
+ pbmhDst->bV5BitCount != 16 && pbmhDst->bV5BitCount != 24 &&
+ pbmhDst->bV5BitCount != 32)
+ {
+ DPRINT("Invalid bit count: %d\n", pbmhDst->bV5BitCount);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if ((pbmhDst->bV5BitCount == 0 &&
+ pbmhDst->bV5Compression != BI_JPEG && pbmhDst->bV5Compression != BI_PNG))
+ {
+ DPRINT("Bit count 0 is invalid for compression %d.\n", pbmhDst->bV5Compression);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (pbmhDst->bV5Compression == BI_BITFIELDS &&
+ pbmhDst->bV5BitCount != 16 && pbmhDst->bV5BitCount != 32)
+ {
+ DPRINT("Bit count %d is invalid for compression BI_BITFIELDS.\n", pbmhDst->bV5BitCount);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Copy Colors */
+ if(pbmhDst->bV5ClrUsed)
+ {
+ INT i;
+ if(dwColorUse == DIB_PAL_COLORS)
+ {
+ RtlCopyMemory(pbmiDst->bmiColors,
+ pbmiUnsafe->bmiColors,
+ pbmhDst->bV5ClrUsed * sizeof(WORD));
+ }
+ else
+ {
+ for(i = 0; i < pbmhDst->bV5ClrUsed; i++)
+ {
+ ((DWORD*)pbmiDst->bmiColors)[i] = GetBMIColor(pbmiUnsafe, i);
+ }
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+FASTCALL
+GetBMIFromBitmapV5Info(IN PBITMAPV5INFO pbmiSrc,
+ OUT PBITMAPINFO pbmiDst,
+ IN DWORD dwColorUse)
+{
+ if(pbmiDst->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
+ {
+ /* Manually set value */
+ BITMAPCOREHEADER* pbmhCore = (BITMAPCOREHEADER*)&pbmiDst->bmiHeader;
+ pbmhCore->bcWidth = pbmiSrc->bmiHeader.bV5Width;
+ pbmhCore->bcHeight = pbmiSrc->bmiHeader.bV5Height;
+ pbmhCore->bcPlanes = pbmiSrc->bmiHeader.bV5Planes;
+ pbmhCore->bcBitCount = pbmiSrc->bmiHeader.bV5BitCount;
+ }
+ else
+ {
+ /* Copy valid Fields, keep bmiHeader.biSize safe */
+ RtlCopyMemory(&pbmiDst->bmiHeader.biWidth,
+ &pbmiSrc->bmiHeader.bV5Width,
+ pbmiDst->bmiHeader.biSize - sizeof(DWORD));
+ }
+ if((pbmiDst->bmiHeader.biSize < sizeof(BITMAPV4HEADER)) &&
+ (pbmiSrc->bmiHeader.bV5Compression == BI_BITFIELDS))
+ {
+ /* Masks are already set in V4 and V5 headers */
+ SetBMIColor(pbmiDst, &pbmiSrc->bmiHeader.bV5RedMask, 0);
+ SetBMIColor(pbmiDst, &pbmiSrc->bmiHeader.bV5GreenMask, 1);
+ SetBMIColor(pbmiDst, &pbmiSrc->bmiHeader.bV5BlueMask, 2);
+ }
+ else
+ {
+ INT i;
+ ULONG cColorsUsed;
+
+ cColorsUsed = pbmiSrc->bmiHeader.bV5ClrUsed;
+ if (cColorsUsed == 0 && pbmiSrc->bmiHeader.bV5BitCount <= 8)
+ cColorsUsed = (1 << pbmiSrc->bmiHeader.bV5BitCount);
+
+ if(dwColorUse == DIB_PAL_COLORS)
+ {
+ RtlCopyMemory(pbmiDst->bmiColors,
+ pbmiSrc->bmiColors,
+ cColorsUsed * sizeof(WORD));
+ }
+ else
+ {
+ for(i = 0; i < cColorsUsed; i++)
+ {
+ SetBMIColor(pbmiDst, (DWORD*)pbmiSrc->bmiColors + i, i);
+ }
+ }
+ }
+}
+
+/* EOF */
--- /dev/null
- DirInfoBuffer = ExAllocatePool(PagedPool, 0x4000);
+/*
+ * FreeType font engine interface
+ *
+ * Copyright 2001 Huw D M Davies for CodeWeavers.
+ * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
+ *
+ * This file contains the WineEng* functions.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+/*
+ *
+ * Addaped for the use in ReactOS.
+ *
+ */
+/*
+ * PROJECT: ReactOS win32 kernel mode subsystem
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: subsystems/win32/win32k/objects/freetype.c
+ * PURPOSE: Freetype library support
+ * PROGRAMMER:
+ */
+
+/** Includes ******************************************************************/
+
+#include <win32k.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_TYPE1_TABLES_H
+#include <freetype/tttables.h>
+#include <freetype/fttrigon.h>
+#include <freetype/ftglyph.h>
+#include <freetype/ftbitmap.h>
+#include <freetype/ftoutln.h>
+#include <freetype/ftwinfnt.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#ifndef FT_MAKE_TAG
+#define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
+ ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
+ ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
+#endif
+
+FT_Library library;
+
+typedef struct _FONT_ENTRY
+{
+ LIST_ENTRY ListEntry;
+ FONTGDI *Font;
+ UNICODE_STRING FaceName;
+ BYTE NotEnum;
+} FONT_ENTRY, *PFONT_ENTRY;
+
+/* The FreeType library is not thread safe, so we have
+ to serialize access to it */
+static FAST_MUTEX FreeTypeLock;
+
+static LIST_ENTRY FontListHead;
+static FAST_MUTEX FontListLock;
+static BOOL RenderingEnabled = TRUE;
+
+#define MAX_FONT_CACHE 256
+
+typedef struct _FONT_CACHE_ENTRY
+{
+ LIST_ENTRY ListEntry;
+ int GlyphIndex;
+ FT_Face Face;
+ FT_BitmapGlyph BitmapGlyph;
+ int Height;
+} FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY;
+static LIST_ENTRY FontCacheListHead;
+static UINT FontCacheNumEntries;
+
+static PWCHAR ElfScripts[32] = /* these are in the order of the fsCsb[0] bits */
+{
+ L"Western", /*00*/
+ L"Central_European",
+ L"Cyrillic",
+ L"Greek",
+ L"Turkish",
+ L"Hebrew",
+ L"Arabic",
+ L"Baltic",
+ L"Vietnamese", /*08*/
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
+ L"Thai",
+ L"Japanese",
+ L"CHINESE_GB2312",
+ L"Hangul",
+ L"CHINESE_BIG5",
+ L"Hangul(Johab)",
+ NULL, NULL, /*23*/
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ L"Symbol" /*31*/
+};
+
+/*
+ * For TranslateCharsetInfo
+ */
+#define CP_SYMBOL 42
+#define MAXTCIINDEX 32
+static const CHARSETINFO FontTci[MAXTCIINDEX] =
+{
+ /* ANSI */
+ { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
+ { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
+ { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
+ { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
+ { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
+ { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
+ { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
+ { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
+ { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
+ /* reserved by ANSI */
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ /* ANSI and OEM */
+ { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
+ { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
+ { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
+ { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
+ { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
+ { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
+ /* reserved for alternate ANSI and OEM */
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ /* reserved for system */
+ { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
+ { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
+};
+
+BOOL FASTCALL
+InitFontSupport(VOID)
+{
+ ULONG ulError;
+
+ InitializeListHead(&FontListHead);
+ InitializeListHead(&FontCacheListHead);
+ FontCacheNumEntries = 0;
+ ExInitializeFastMutex(&FontListLock);
+ ExInitializeFastMutex(&FreeTypeLock);
+
+ ulError = FT_Init_FreeType(&library);
+ if (ulError)
+ {
+ DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
+ return FALSE;
+ }
+
+ IntLoadSystemFonts();
+
+ return TRUE;
+}
+
+/*
+ * IntLoadSystemFonts
+ *
+ * Search the system font directory and adds each font found.
+ */
+
+VOID FASTCALL
+IntLoadSystemFonts(VOID)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING Directory, SearchPattern, FileName, TempString;
+ IO_STATUS_BLOCK Iosb;
+ HANDLE hDirectory;
+ BYTE *DirInfoBuffer;
+ PFILE_DIRECTORY_INFORMATION DirInfo;
+ BOOLEAN bRestartScan = TRUE;
+ NTSTATUS Status;
+
+ RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
+ /* FIXME: Add support for other font types */
+ RtlInitUnicodeString(&SearchPattern, L"*.ttf");
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &Directory,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = ZwOpenFile(
+ &hDirectory,
+ SYNCHRONIZE | FILE_LIST_DIRECTORY,
+ &ObjectAttributes,
+ &Iosb,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
+
+ if (NT_SUCCESS(Status))
+ {
- FileName.Buffer = ExAllocatePool(PagedPool, MAX_PATH * sizeof(WCHAR));
++ DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
+ if (DirInfoBuffer == NULL)
+ {
+ ZwClose(hDirectory);
+ return;
+ }
+
- ExFreePool(DirInfoBuffer);
++ FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT);
+ if (FileName.Buffer == NULL)
+ {
- ExFreePool(FileName.Buffer);
- ExFreePool(DirInfoBuffer);
++ ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
+ ZwClose(hDirectory);
+ return;
+ }
+ FileName.Length = 0;
+ FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
+
+ while (1)
+ {
+ Status = ZwQueryDirectoryFile(
+ hDirectory,
+ NULL,
+ NULL,
+ NULL,
+ &Iosb,
+ DirInfoBuffer,
+ 0x4000,
+ FileDirectoryInformation,
+ FALSE,
+ &SearchPattern,
+ bRestartScan);
+
+ if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
+ {
+ break;
+ }
+
+ DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
+ while (1)
+ {
+ TempString.Buffer = DirInfo->FileName;
+ TempString.Length =
+ TempString.MaximumLength = DirInfo->FileNameLength;
+ RtlCopyUnicodeString(&FileName, &Directory);
+ RtlAppendUnicodeStringToString(&FileName, &TempString);
+ IntGdiAddFontResource(&FileName, 0);
+ if (DirInfo->NextEntryOffset == 0)
+ break;
+ DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
+ }
+
+ bRestartScan = FALSE;
+ }
+
++ ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
++ ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
+ ZwClose(hDirectory);
+ }
+}
+
+
+/*
+ * IntGdiAddFontResource
+ *
+ * Adds the font resource from the specified file to the system.
+ */
+
+INT FASTCALL
+IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
+{
+ FONTGDI *FontGDI;
+ NTSTATUS Status;
+ HANDLE FileHandle, KeyHandle;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PVOID Buffer = NULL;
+ IO_STATUS_BLOCK Iosb;
+ INT Error;
+ FT_Face Face;
+ ANSI_STRING AnsiFaceName;
+ PFONT_ENTRY Entry;
+ PSECTION_OBJECT SectionObject;
+ ULONG ViewSize = 0;
+ LARGE_INTEGER SectionSize;
+ FT_Fixed XScale, YScale;
+ UNICODE_STRING FontRegPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
+
+ /* Open the font file */
+
+ InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
+ Status = ZwOpenFile(
+ &FileHandle,
+ FILE_GENERIC_READ | SYNCHRONIZE,
+ &ObjectAttributes,
+ &Iosb,
+ FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_NONALERT);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Could not load font file: %wZ\n", FileName);
+ return 0;
+ }
+
+ SectionSize.QuadPart = 0LL;
+ Status = MmCreateSection((PVOID)&SectionObject, SECTION_ALL_ACCESS,
+ NULL, &SectionSize, PAGE_READONLY,
+ SEC_COMMIT, FileHandle, NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Could not map file: %wZ\n", FileName);
+ ZwClose(FileHandle);
+ return 0;
+ }
+
+ ZwClose(FileHandle);
+
+ Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Could not map file: %wZ\n", FileName);
+ return Status;
+ }
+
+ IntLockFreeType;
+ Error = FT_New_Memory_Face(
+ library,
+ Buffer,
+ ViewSize,
+ 0,
+ &Face);
+ IntUnLockFreeType;
+
+ if (Error)
+ {
+ if (Error == FT_Err_Unknown_File_Format)
+ DPRINT("Unknown font file format\n");
+ else
+ DPRINT("Error reading font file (error code: %u)\n", Error);
+ ObDereferenceObject(SectionObject);
+ return 0;
+ }
+
+ Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
+ if (!Entry)
+ {
+ FT_Done_Face(Face);
+ ObDereferenceObject(SectionObject);
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return 0;
+ }
+
+ FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), TAG_FONTOBJ);
+ if (FontGDI == NULL)
+ {
+ FT_Done_Face(Face);
+ ObDereferenceObject(SectionObject);
+ ExFreePoolWithTag(Entry, TAG_FONT);
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return 0;
+ }
+
+ FontGDI->Filename = ExAllocatePoolWithTag(PagedPool, FileName->Length + sizeof(WCHAR), TAG_PFF);
+ if (FontGDI->Filename == NULL)
+ {
+ EngFreeMem(FontGDI);
+ FT_Done_Face(Face);
+ ObDereferenceObject(SectionObject);
+ ExFreePoolWithTag(Entry, TAG_FONT);
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return 0;
+ }
+ RtlCopyMemory(FontGDI->Filename, FileName->Buffer, FileName->Length);
+ FontGDI->Filename[FileName->Length / sizeof(WCHAR)] = L'\0';
+ FontGDI->face = Face;
+
+ /* FIXME: Complete text metrics */
+ XScale = Face->size->metrics.x_scale;
+ YScale = Face->size->metrics.y_scale;
+#if 0 /* This (Wine) code doesn't seem to work correctly for us */
+ FontGDI->TextMetric.tmAscent = (FT_MulFix(Face->ascender, YScale) + 32) >> 6;
+ FontGDI->TextMetric.tmDescent = (FT_MulFix(Face->descender, YScale) + 32) >> 6;
+ FontGDI->TextMetric.tmHeight = (FT_MulFix(Face->ascender, YScale) -
+ FT_MulFix(Face->descender, YScale)) >> 6;
+#else
+ FontGDI->TextMetric.tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* units above baseline */
+ FontGDI->TextMetric.tmDescent = (32 - Face->size->metrics.descender) >> 6; /* units below baseline */
+ FontGDI->TextMetric.tmHeight = (Face->size->metrics.ascender - Face->size->metrics.descender) >> 6;
+#endif
+
+
+
+ DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
+ DPRINT("Num glyphs: %u\n", Face->num_glyphs);
+
+ /* Add this font resource to the font table */
+
+ Entry->Font = FontGDI;
+ Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
+ RtlInitAnsiString(&AnsiFaceName, (LPSTR)Face->family_name);
+ RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
+
+ if (Characteristics & FR_PRIVATE)
+ {
+ PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
+ IntLockProcessPrivateFonts(Win32Process);
+ InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
+ IntUnLockProcessPrivateFonts(Win32Process);
+ }
+ else
+ {
+ IntLockGlobalFonts;
+ InsertTailList(&FontListHead, &Entry->ListEntry);
+ InitializeObjectAttributes(&ObjectAttributes, &FontRegPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
+ Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
+ if (NT_SUCCESS(Status))
+ {
+ LPWSTR pName = wcsrchr(FileName->Buffer, L'\\');
+ if (pName)
+ {
+ pName++;
+ ZwSetValueKey(KeyHandle, &Entry->FaceName, 0, REG_SZ, pName, (wcslen(pName) + 1) * sizeof(WCHAR));
+ }
+ ZwClose(KeyHandle);
+ }
+ IntUnLockGlobalFonts;
+ }
+ return 1;
+}
+
+BOOL FASTCALL
+IntIsFontRenderingEnabled(VOID)
+{
+ BOOL Ret = RenderingEnabled;
+ HDC hDC;
+
+ hDC = IntGetScreenDC();
+ if (hDC)
+ Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
+
+ return Ret;
+}
+
+VOID FASTCALL
+IntEnableFontRendering(BOOL Enable)
+{
+ RenderingEnabled = Enable;
+}
+
+FT_Render_Mode FASTCALL
+IntGetFontRenderMode(LOGFONTW *logfont)
+{
+ switch (logfont->lfQuality)
+ {
+ case NONANTIALIASED_QUALITY:
+ return FT_RENDER_MODE_MONO;
+ case DRAFT_QUALITY:
+ return FT_RENDER_MODE_LIGHT;
+ /* case CLEARTYPE_QUALITY:
+ return FT_RENDER_MODE_LCD; */
+ }
+ return FT_RENDER_MODE_NORMAL;
+}
+
+
+NTSTATUS FASTCALL
+TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
+{
+ PTEXTOBJ TextObj;
+
+ TextObj = TEXTOBJ_AllocTextWithHandle();
+ if (!TextObj)
+ {
+ return STATUS_NO_MEMORY;
+ }
+
+ *NewFont = TextObj->BaseObject.hHmgr;
+ RtlCopyMemory(&TextObj->logfont.elfEnumLogfontEx.elfLogFont, lf, sizeof(LOGFONTW));
+ if (lf->lfEscapement != lf->lfOrientation)
+ {
+ /* this should really depend on whether GM_ADVANCED is set */
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation =
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfEscapement;
+ }
+ TEXTOBJ_UnlockText(TextObj);
+
+ return STATUS_SUCCESS;
+}
+
+/*************************************************************************
+ * TranslateCharsetInfo
+ *
+ * Fills a CHARSETINFO structure for a character set, code page, or
+ * font. This allows making the correspondance between different labelings
+ * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
+ * of the same encoding.
+ *
+ * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
+ * only one codepage should be set in *Src.
+ *
+ * RETURNS
+ * TRUE on success, FALSE on failure.
+ *
+ */
+static BOOLEAN APIENTRY
+IntTranslateCharsetInfo(PDWORD Src, /* [in]
+ if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
+ if flags == TCI_SRCCHARSET: a character set value
+ if flags == TCI_SRCCODEPAGE: a code page value */
+ LPCHARSETINFO Cs, /* [out] structure to receive charset information */
+ DWORD Flags /* [in] determines interpretation of lpSrc */)
+{
+ int Index = 0;
+
+ switch (Flags)
+ {
+ case TCI_SRCFONTSIG:
+ while (0 == (*Src >> Index & 0x0001) && Index < MAXTCIINDEX)
+ {
+ Index++;
+ }
+ break;
+ case TCI_SRCCODEPAGE:
+ while ( *Src != FontTci[Index].ciACP && Index < MAXTCIINDEX)
+ {
+ Index++;
+ }
+ break;
+ case TCI_SRCCHARSET:
+ while ( *Src != FontTci[Index].ciCharset && Index < MAXTCIINDEX)
+ {
+ Index++;
+ }
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == FontTci[Index].ciCharset)
+ {
+ return FALSE;
+ }
+
+ RtlCopyMemory(Cs, &FontTci[Index], sizeof(CHARSETINFO));
+
+ return TRUE;
+}
+
+
+static BOOL face_has_symbol_charmap(FT_Face ft_face)
+{
+ int i;
+
+ for(i = 0; i < ft_face->num_charmaps; i++)
+ {
+ if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void FASTCALL
+FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI, TT_OS2 *pOS2, TT_HoriHeader *pHori, FT_WinFNT_HeaderRec *pWin)
+{
+ FT_Fixed XScale, YScale;
+ int Ascent, Descent;
+ FT_Face Face = FontGDI->face;
+
+ XScale = Face->size->metrics.x_scale;
+ YScale = Face->size->metrics.y_scale;
+
+ if (pWin)
+ {
+ TM->tmHeight = pWin->pixel_height;
+ TM->tmAscent = pWin->ascent;
+ TM->tmDescent = TM->tmHeight - TM->tmAscent;
+ TM->tmInternalLeading = pWin->internal_leading;
+ TM->tmExternalLeading = pWin->external_leading;
+ TM->tmAveCharWidth = pWin->avg_width;
+ TM->tmMaxCharWidth = pWin->max_width;
+ TM->tmWeight = pWin->weight;
+ TM->tmOverhang = 0;
+ TM->tmDigitizedAspectX = pWin->horizontal_resolution;
+ TM->tmDigitizedAspectY = pWin->vertical_resolution;
+ TM->tmFirstChar = pWin->first_char;
+ TM->tmLastChar = pWin->last_char;
+ TM->tmDefaultChar = pWin->default_char + pWin->first_char;
+ TM->tmBreakChar = pWin->break_char + pWin->first_char;
+ TM->tmItalic = pWin->italic;
+ TM->tmUnderlined = FontGDI->Underline;
+ TM->tmStruckOut = FontGDI->StrikeOut;
+ TM->tmPitchAndFamily = pWin->pitch_and_family;
+ TM->tmCharSet = pWin->charset;
+ return;
+ }
+
+ if (pOS2->usWinAscent + pOS2->usWinDescent == 0)
+ {
+ Ascent = pHori->Ascender;
+ Descent = -pHori->Descender;
+ }
+ else
+ {
+ Ascent = pOS2->usWinAscent;
+ Descent = pOS2->usWinDescent;
+ }
+
+#if 0 /* This (Wine) code doesn't seem to work correctly for us, cmd issue */
+ TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6;
+ TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6;
+#else /* This (ros) code was previously affected by a FreeType bug, but it works now */
+ TM->tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* units above baseline */
+ TM->tmDescent = (32 - Face->size->metrics.descender) >> 6; /* units below baseline */
+#endif
+ TM->tmInternalLeading = (FT_MulFix(Ascent + Descent - Face->units_per_EM, YScale) + 32) >> 6;
+
+ TM->tmHeight = TM->tmAscent + TM->tmDescent;
+
+ /* MSDN says:
+ * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
+ */
+ TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
+ - ((Ascent + Descent)
+ - (pHori->Ascender - pHori->Descender)),
+ YScale) + 32) >> 6);
+
+ TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
+ if (TM->tmAveCharWidth == 0)
+ {
+ TM->tmAveCharWidth = 1;
+ }
+
+ /* Correct forumla to get the maxcharwidth from unicode and ansi font */
+ TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
+
+ TM->tmWeight = pOS2->usWeightClass;
+ TM->tmOverhang = 0;
+ TM->tmDigitizedAspectX = 96;
+ TM->tmDigitizedAspectY = 96;
+ if (face_has_symbol_charmap(Face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
+ {
+ USHORT cpOEM, cpAnsi;
+
+ EngGetCurrentCodePage(&cpOEM, &cpAnsi);
+ TM->tmFirstChar = 0;
+ switch(cpAnsi)
+ {
+ case 1257: /* Baltic */
+ TM->tmLastChar = 0xf8fd;
+ break;
+ default:
+ TM->tmLastChar = 0xf0ff;
+ }
+ TM->tmBreakChar = 0x20;
+ TM->tmDefaultChar = 0x1f;
+ }
+ else
+ {
+ TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
+ TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
+
+ if(pOS2->usFirstCharIndex <= 1)
+ TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
+ else if (pOS2->usFirstCharIndex > 0xff)
+ TM->tmBreakChar = 0x20;
+ else
+ TM->tmBreakChar = pOS2->usFirstCharIndex;
+ TM->tmDefaultChar = TM->tmBreakChar - 1;
+ }
+ TM->tmItalic = (Face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0;
+ TM->tmUnderlined = FontGDI->Underline;
+ TM->tmStruckOut = FontGDI->StrikeOut;
+
+ /* Yes TPMF_FIXED_PITCH is correct; braindead api */
+ if (! FT_IS_FIXED_WIDTH(Face))
+ {
+ TM->tmPitchAndFamily = TMPF_FIXED_PITCH;
+ }
+ else
+ {
+ TM->tmPitchAndFamily = 0;
+ }
+
+ switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
+ {
+ case PAN_FAMILY_SCRIPT:
+ TM->tmPitchAndFamily |= FF_SCRIPT;
+ break;
+ case PAN_FAMILY_DECORATIVE:
+ TM->tmPitchAndFamily |= FF_DECORATIVE;
+ break;
+
+ case PAN_ANY:
+ case PAN_NO_FIT:
+ case PAN_FAMILY_TEXT_DISPLAY:
+ case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
+ /* which is clearly not what the panose spec says. */
+ if (TM->tmPitchAndFamily == 0) /* fixed */
+ {
+ TM->tmPitchAndFamily = FF_MODERN;
+ }
+ else
+ {
+ switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
+ {
+ case PAN_ANY:
+ case PAN_NO_FIT:
+ default:
+ TM->tmPitchAndFamily |= FF_DONTCARE;
+ break;
+
+ case PAN_SERIF_COVE:
+ case PAN_SERIF_OBTUSE_COVE:
+ case PAN_SERIF_SQUARE_COVE:
+ case PAN_SERIF_OBTUSE_SQUARE_COVE:
+ case PAN_SERIF_SQUARE:
+ case PAN_SERIF_THIN:
+ case PAN_SERIF_BONE:
+ case PAN_SERIF_EXAGGERATED:
+ case PAN_SERIF_TRIANGLE:
+ TM->tmPitchAndFamily |= FF_ROMAN;
+ break;
+
+ case PAN_SERIF_NORMAL_SANS:
+ case PAN_SERIF_OBTUSE_SANS:
+ case PAN_SERIF_PERP_SANS:
+ case PAN_SERIF_FLARED:
+ case PAN_SERIF_ROUNDED:
+ TM->tmPitchAndFamily |= FF_SWISS;
+ break;
+ }
+ }
+ break;
+ default:
+ TM->tmPitchAndFamily |= FF_DONTCARE;
+ }
+
+ if (FT_IS_SCALABLE(Face))
+ {
+ TM->tmPitchAndFamily |= TMPF_VECTOR;
+ }
+ if (FT_IS_SFNT(Face))
+ {
+ TM->tmPitchAndFamily |= TMPF_TRUETYPE;
+ }
+
+ TM->tmCharSet = DEFAULT_CHARSET;
+}
+
+/*************************************************************
+ * IntGetOutlineTextMetrics
+ *
+ */
+INT FASTCALL
+IntGetOutlineTextMetrics(PFONTGDI FontGDI,
+ UINT Size,
+ OUTLINETEXTMETRICW *Otm)
+{
+ unsigned Needed;
+ TT_OS2 *pOS2;
+ TT_HoriHeader *pHori;
+ TT_Postscript *pPost;
+ FT_Fixed XScale, YScale;
+ ANSI_STRING FamilyNameA, StyleNameA;
+ UNICODE_STRING FamilyNameW, StyleNameW, Regular;
+ FT_WinFNT_HeaderRec Win;
+ FT_Error Error;
+ char *Cp;
+
+ Needed = sizeof(OUTLINETEXTMETRICW);
+
+ RtlInitAnsiString(&FamilyNameA, FontGDI->face->family_name);
+ RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
+
+ RtlInitAnsiString(&StyleNameA, FontGDI->face->style_name);
+ RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
+
+ /* These names should be read from the TT name table */
+
+ /* length of otmpFamilyName */
+ Needed += FamilyNameW.Length + sizeof(WCHAR);
+
+ RtlInitUnicodeString(&Regular, L"regular");
+ /* length of otmpFaceName */
+ if (0 == RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
+ {
+ Needed += FamilyNameW.Length + sizeof(WCHAR); /* just the family name */
+ }
+ else
+ {
+ Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
+ }
+
+ /* length of otmpStyleName */
+ Needed += StyleNameW.Length + sizeof(WCHAR);
+
+ /* length of otmpFullName */
+ Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
+
+ if (Size < Needed)
+ {
+ RtlFreeUnicodeString(&FamilyNameW);
+ RtlFreeUnicodeString(&StyleNameW);
+ return Needed;
+ }
+
+ XScale = FontGDI->face->size->metrics.x_scale;
+ YScale = FontGDI->face->size->metrics.y_scale;
+
+ IntLockFreeType;
+ pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
+ if (NULL == pOS2)
+ {
+ IntUnLockFreeType;
+ DPRINT1("Can't find OS/2 table - not TT font?\n");
+ RtlFreeUnicodeString(&StyleNameW);
+ RtlFreeUnicodeString(&FamilyNameW);
+ return 0;
+ }
+
+ pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
+ if (NULL == pHori)
+ {
+ IntUnLockFreeType;
+ DPRINT1("Can't find HHEA table - not TT font?\n");
+ RtlFreeUnicodeString(&StyleNameW);
+ RtlFreeUnicodeString(&FamilyNameW);
+ return 0;
+ }
+
+ pPost = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_post); /* we can live with this failing */
+
+ Error = FT_Get_WinFNT_Header(FontGDI->face , &Win);
+
+ Otm->otmSize = Needed;
+
+// FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
+ if (!(FontGDI->flRealizedType & FDM_TYPE_TEXT_METRIC))
+ {
+ FillTM(&FontGDI->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
+ FontGDI->flRealizedType |= FDM_TYPE_TEXT_METRIC;
+ }
+
+ RtlCopyMemory(&Otm->otmTextMetrics, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
+
+ Otm->otmFiller = 0;
+ RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
+ Otm->otmfsSelection = pOS2->fsSelection;
+ Otm->otmfsType = pOS2->fsType;
+ Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
+ Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
+ Otm->otmItalicAngle = 0; /* POST table */
+ Otm->otmEMSquare = FontGDI->face->units_per_EM;
+ Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6;
+ Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6;
+ Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6;
+ Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6;
+ Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6;
+ Otm->otmrcFontBox.left = (FT_MulFix(FontGDI->face->bbox.xMin, XScale) + 32) >> 6;
+ Otm->otmrcFontBox.right = (FT_MulFix(FontGDI->face->bbox.xMax, XScale) + 32) >> 6;
+ Otm->otmrcFontBox.top = (FT_MulFix(FontGDI->face->bbox.yMax, YScale) + 32) >> 6;
+ Otm->otmrcFontBox.bottom = (FT_MulFix(FontGDI->face->bbox.yMin, YScale) + 32) >> 6;
+ Otm->otmMacAscent = FontGDI->TextMetric.tmAscent;
+ Otm->otmMacDescent = -FontGDI->TextMetric.tmDescent;
+ Otm->otmMacLineGap = Otm->otmLineGap;
+ Otm->otmusMinimumPPEM = 0; /* TT Header */
+ Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6;
+ Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6;
+ Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6;
+ Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6;
+ Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6;
+ Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6;
+ Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6;
+ Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6;
+ Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6;
+ Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6;
+ if (!pPost)
+ {
+ Otm->otmsUnderscoreSize = 0;
+ Otm->otmsUnderscorePosition = 0;
+ }
+ else
+ {
+ Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6;
+ Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
+ }
+
+ IntUnLockFreeType;
+
+ /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
+ Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
+ Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
+ wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
+ Cp += FamilyNameW.Length + sizeof(WCHAR);
+ Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm);
+ wcscpy((WCHAR*) Cp, StyleNameW.Buffer);
+ Cp += StyleNameW.Length + sizeof(WCHAR);
+ Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
+ wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
+ if (0 != RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
+ {
+ wcscat((WCHAR*) Cp, L" ");
+ wcscat((WCHAR*) Cp, StyleNameW.Buffer);
+ Cp += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
+ }
+ else
+ {
+ Cp += FamilyNameW.Length + sizeof(WCHAR);
+ }
+ Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
+ wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
+ wcscat((WCHAR*) Cp, L" ");
+ wcscat((WCHAR*) Cp, StyleNameW.Buffer);
+
+ RtlFreeUnicodeString(&StyleNameW);
+ RtlFreeUnicodeString(&FamilyNameW);
+
+ return Needed;
+}
+
+static PFONTGDI FASTCALL
+FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
+{
+ PLIST_ENTRY Entry;
+ PFONT_ENTRY CurrentEntry;
+ ANSI_STRING EntryFaceNameA;
+ UNICODE_STRING EntryFaceNameW;
+ FONTGDI *FontGDI;
+
+ Entry = Head->Flink;
+ while (Entry != Head)
+ {
+ CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
+
+ FontGDI = CurrentEntry->Font;
+ ASSERT(FontGDI);
+
+ RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
+ RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
+ if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
+ {
+ EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
+ EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
+ }
+
+ if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
+ {
+ RtlFreeUnicodeString(&EntryFaceNameW);
+ return FontGDI;
+ }
+
+ RtlFreeUnicodeString(&EntryFaceNameW);
+ Entry = Entry->Flink;
+ }
+
+ return NULL;
+}
+
+static PFONTGDI FASTCALL
+FindFaceNameInLists(PUNICODE_STRING FaceName)
+{
+ PPROCESSINFO Win32Process;
+ PFONTGDI Font;
+
+ /* Search the process local list */
+ Win32Process = PsGetCurrentProcessWin32Process();
+ IntLockProcessPrivateFonts(Win32Process);
+ Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
+ IntUnLockProcessPrivateFonts(Win32Process);
+ if (NULL != Font)
+ {
+ return Font;
+ }
+
+ /* Search the global list */
+ IntLockGlobalFonts;
+ Font = FindFaceNameInList(FaceName, &FontListHead);
+ IntUnLockGlobalFonts;
+
+ return Font;
+}
+
+static void FASTCALL
+FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
+{
+ ANSI_STRING StyleA;
+ UNICODE_STRING StyleW;
+ TT_OS2 *pOS2;
+ FONTSIGNATURE fs;
+ CHARSETINFO CharSetInfo;
+ unsigned i, Size;
+ OUTLINETEXTMETRICW *Otm;
+ LOGFONTW *Lf;
+ TEXTMETRICW *TM;
+ NEWTEXTMETRICW *Ntm;
+ DWORD fs0;
+
+ RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
+ Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
+ Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
+ if (!Otm)
+ {
+ return;
+ }
+ IntGetOutlineTextMetrics(FontGDI, Size, Otm);
+
+ Lf = &Info->EnumLogFontEx.elfLogFont;
+ TM = &Otm->otmTextMetrics;
+
+ Lf->lfHeight = TM->tmHeight;
+ Lf->lfWidth = TM->tmAveCharWidth;
+ Lf->lfWeight = TM->tmWeight;
+ Lf->lfItalic = TM->tmItalic;
+ Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
+ Lf->lfCharSet = TM->tmCharSet;
+ Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
+ Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ Lf->lfQuality = PROOF_QUALITY;
+
+ Ntm = &Info->NewTextMetricEx.ntmTm;
+ Ntm->tmHeight = TM->tmHeight;
+ Ntm->tmAscent = TM->tmAscent;
+ Ntm->tmDescent = TM->tmDescent;
+ Ntm->tmInternalLeading = TM->tmInternalLeading;
+ Ntm->tmExternalLeading = TM->tmExternalLeading;
+ Ntm->tmAveCharWidth = TM->tmAveCharWidth;
+ Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
+ Ntm->tmWeight = TM->tmWeight;
+ Ntm->tmOverhang = TM->tmOverhang;
+ Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
+ Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
+ Ntm->tmFirstChar = TM->tmFirstChar;
+ Ntm->tmLastChar = TM->tmLastChar;
+ Ntm->tmDefaultChar = TM->tmDefaultChar;
+ Ntm->tmBreakChar = TM->tmBreakChar;
+ Ntm->tmItalic = TM->tmItalic;
+ Ntm->tmUnderlined = TM->tmUnderlined;
+ Ntm->tmStruckOut = TM->tmStruckOut;
+ Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
+ Ntm->tmCharSet = TM->tmCharSet;
+ Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
+
+ if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
+
+ if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
+
+ Ntm->ntmSizeEM = Otm->otmEMSquare;
+ Ntm->ntmCellHeight = 0;
+ Ntm->ntmAvgWidth = 0;
+
+ Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
+ ? TRUETYPE_FONTTYPE : 0);
+
+ if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
+ Info->FontType |= RASTER_FONTTYPE;
+
+ ExFreePoolWithTag(Otm, TAG_GDITEXT);
+
+ wcsncpy(Info->EnumLogFontEx.elfLogFont.lfFaceName, FaceName, LF_FACESIZE);
+ wcsncpy(Info->EnumLogFontEx.elfFullName, FaceName, LF_FULLFACESIZE);
+ RtlInitAnsiString(&StyleA, FontGDI->face->style_name);
+ RtlAnsiStringToUnicodeString(&StyleW, &StyleA, TRUE);
+ wcsncpy(Info->EnumLogFontEx.elfStyle, StyleW.Buffer, LF_FACESIZE);
+ RtlFreeUnicodeString(&StyleW);
+
+ Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
+ Info->EnumLogFontEx.elfScript[0] = L'\0';
+ IntLockFreeType;
+ pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
+ IntUnLockFreeType;
+ if (NULL != pOS2)
+ {
+ fs.fsCsb[0] = pOS2->ulCodePageRange1;
+ fs.fsCsb[1] = pOS2->ulCodePageRange2;
+ fs.fsUsb[0] = pOS2->ulUnicodeRange1;
+ fs.fsUsb[1] = pOS2->ulUnicodeRange2;
+ fs.fsUsb[2] = pOS2->ulUnicodeRange3;
+ fs.fsUsb[3] = pOS2->ulUnicodeRange4;
+
+ if (0 == pOS2->version)
+ {
+ FT_UInt Dummy;
+
+ if (FT_Get_First_Char(FontGDI->face, &Dummy) < 0x100)
+ fs.fsCsb[0] |= FS_LATIN1;
+ else
+ fs.fsCsb[0] |= FS_SYMBOL;
+ }
+ if (fs.fsCsb[0] == 0)
+ { /* let's see if we can find any interesting cmaps */
+ for (i = 0; i < FontGDI->face->num_charmaps; i++)
+ {
+ switch (FontGDI->face->charmaps[i]->encoding)
+ {
+ case FT_ENCODING_UNICODE:
+ case FT_ENCODING_APPLE_ROMAN:
+ fs.fsCsb[0] |= FS_LATIN1;
+ break;
+ case FT_ENCODING_MS_SYMBOL:
+ fs.fsCsb[0] |= FS_SYMBOL;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ for (i = 0; i < MAXTCIINDEX; i++)
+ {
+ fs0 = 1L << i;
+ if (fs.fsCsb[0] & fs0)
+ {
+ if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
+ {
+ CharSetInfo.ciCharset = DEFAULT_CHARSET;
+ }
+ if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
+ {
+ Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
+ if (NULL != ElfScripts[i])
+ wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
+ else
+ {
+ DPRINT1("Unknown elfscript for bit %d\n", i);
+ }
+ }
+ }
+ }
+ Info->NewTextMetricEx.ntmFontSig = fs;
+ }
+}
+
+static int FASTCALL
+FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
+{
+ DWORD i;
+ UNICODE_STRING InfoFaceName;
+
+ for (i = 0; i < InfoEntries; i++)
+ {
+ RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
+ if (0 == RtlCompareUnicodeString(&InfoFaceName, FaceName, TRUE))
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static BOOLEAN FASTCALL
+FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
+ PFONTFAMILYINFO Info, DWORD InfoEntries)
+{
+ UNICODE_STRING LogFontFaceName;
+
+ RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
+ if (0 != LogFontFaceName.Length
+ && 0 != RtlCompareUnicodeString(&LogFontFaceName, FaceName, TRUE))
+ {
+ return FALSE;
+ }
+
+ return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
+}
+
+static BOOLEAN FASTCALL
+GetFontFamilyInfoForList(LPLOGFONTW LogFont,
+ PFONTFAMILYINFO Info,
+ DWORD *Count,
+ DWORD Size,
+ PLIST_ENTRY Head)
+{
+ PLIST_ENTRY Entry;
+ PFONT_ENTRY CurrentEntry;
+ ANSI_STRING EntryFaceNameA;
+ UNICODE_STRING EntryFaceNameW;
+ FONTGDI *FontGDI;
+
+ Entry = Head->Flink;
+ while (Entry != Head)
+ {
+ CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
+
+ FontGDI = CurrentEntry->Font;
+ ASSERT(FontGDI);
+
+ RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
+ RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
+ if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
+ {
+ EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
+ EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
+ }
+
+ if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
+ {
+ if (*Count < Size)
+ {
+ FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
+ }
+ (*Count)++;
+ }
+ RtlFreeUnicodeString(&EntryFaceNameW);
+ Entry = Entry->Flink;
+ }
+
+ return TRUE;
+}
+
+typedef struct FontFamilyInfoCallbackContext
+{
+ LPLOGFONTW LogFont;
+ PFONTFAMILYINFO Info;
+ DWORD Count;
+ DWORD Size;
+} FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
+
+static NTSTATUS APIENTRY
+FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
+ IN PVOID ValueData, IN ULONG ValueLength,
+ IN PVOID Context, IN PVOID EntryContext)
+{
+ PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
+ UNICODE_STRING RegistryName, RegistryValue;
+ int Existing;
+ PFONTGDI FontGDI;
+
+ if (REG_SZ != ValueType)
+ {
+ return STATUS_SUCCESS;
+ }
+ InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
+ RtlInitUnicodeString(&RegistryName, ValueName);
+
+ /* Do we need to include this font family? */
+ if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
+ min(InfoContext->Count, InfoContext->Size)))
+ {
+ RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
+ Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
+ min(InfoContext->Count, InfoContext->Size));
+ if (0 <= Existing)
+ {
+ /* We already have the information about the "real" font. Just copy it */
+ if (InfoContext->Count < InfoContext->Size)
+ {
+ InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
+ wcsncpy(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
+ RegistryName.Buffer, LF_FACESIZE);
+ }
+ InfoContext->Count++;
+ return STATUS_SUCCESS;
+ }
+
+ /* Try to find information about the "real" font */
+ FontGDI = FindFaceNameInLists(&RegistryValue);
+ if (NULL == FontGDI)
+ {
+ /* "Real" font not found, discard this registry entry */
+ return STATUS_SUCCESS;
+ }
+
+ /* Return info about the "real" font but with the name of the alias */
+ if (InfoContext->Count < InfoContext->Size)
+ {
+ FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
+ RegistryName.Buffer, FontGDI);
+ }
+ InfoContext->Count++;
+ return STATUS_SUCCESS;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static BOOLEAN FASTCALL
+GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
+ PFONTFAMILYINFO Info,
+ DWORD *Count,
+ DWORD Size)
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
+ FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
+ NTSTATUS Status;
+
+ /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\SysFontSubstitutes
+ The real work is done in the registry callback function */
+ Context.LogFont = LogFont;
+ Context.Info = Info;
+ Context.Count = *Count;
+ Context.Size = Size;
+
+ QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
+ QueryTable[0].Flags = 0;
+ QueryTable[0].Name = NULL;
+ QueryTable[0].EntryContext = NULL;
+ QueryTable[0].DefaultType = REG_NONE;
+ QueryTable[0].DefaultData = NULL;
+ QueryTable[0].DefaultLength = 0;
+
+ QueryTable[1].QueryRoutine = NULL;
+ QueryTable[1].Name = NULL;
+
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
+ L"SysFontSubstitutes",
+ QueryTable,
+ &Context,
+ NULL);
+ if (NT_SUCCESS(Status))
+ {
+ *Count = Context.Count;
+ }
+
+ return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
+}
+
+BOOL
+FASTCALL
+ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
+{
+ if ( lprs )
+ {
+ lprs->nSize = sizeof(RASTERIZER_STATUS);
+ lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
+ lprs->nLanguageID = gusLanguageID;
+ return TRUE;
+ }
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+}
+
+
+FT_BitmapGlyph APIENTRY
+ftGdiGlyphCacheGet(
+ FT_Face Face,
+ INT GlyphIndex,
+ INT Height)
+{
+ PLIST_ENTRY CurrentEntry;
+ PFONT_CACHE_ENTRY FontEntry;
+
+ CurrentEntry = FontCacheListHead.Flink;
+ while (CurrentEntry != &FontCacheListHead)
+ {
+ FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry;
+ if (FontEntry->Face == Face &&
+ FontEntry->GlyphIndex == GlyphIndex &&
+ FontEntry->Height == Height)
+ break;
+ CurrentEntry = CurrentEntry->Flink;
+ }
+
+ if (CurrentEntry == &FontCacheListHead)
+ {
+ return NULL;
+ }
+
+ RemoveEntryList(CurrentEntry);
+ InsertHeadList(&FontCacheListHead, CurrentEntry);
+ return FontEntry->BitmapGlyph;
+}
+
+FT_BitmapGlyph APIENTRY
+ftGdiGlyphCacheSet(
+ FT_Face Face,
+ INT GlyphIndex,
+ INT Height,
+ FT_GlyphSlot GlyphSlot,
+ FT_Render_Mode RenderMode)
+{
+ FT_Glyph GlyphCopy;
+ INT error;
+ PFONT_CACHE_ENTRY NewEntry;
+ FT_Bitmap AlignedBitmap;
+ FT_BitmapGlyph BitmapGlyph;
+
+ error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
+ if (error)
+ {
+ DPRINT1("Failure caching glyph.\n");
+ return NULL;
+ };
+
+ error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
+ if (error)
+ {
+ DPRINT1("Failure rendering glyph.\n");
+ return NULL;
+ };
+
+ NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
+ if (!NewEntry)
+ {
+ DPRINT1("Alloc failure caching glyph.\n");
+ FT_Done_Glyph(GlyphCopy);
+ return NULL;
+ }
+
+ BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
+ FT_Bitmap_New(&AlignedBitmap);
+ if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
+ {
+ DPRINT1("Conversion failed\n");
+ FT_Done_Glyph((FT_Glyph)BitmapGlyph);
+ return NULL;
+ }
+
+ FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
+ BitmapGlyph->bitmap = AlignedBitmap;
+
+ NewEntry->GlyphIndex = GlyphIndex;
+ NewEntry->Face = Face;
+ NewEntry->BitmapGlyph = BitmapGlyph;
+ NewEntry->Height = Height;
+
+ InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
+ if (FontCacheNumEntries++ > MAX_FONT_CACHE)
+ {
+ NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
+ FT_Done_Glyph((FT_Glyph)NewEntry->BitmapGlyph);
+ RemoveTailList(&FontCacheListHead);
+ ExFreePool(NewEntry);
+ FontCacheNumEntries--;
+ }
+
+ return BitmapGlyph;
+}
+
+
+static
+void
+FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
+{
+ pt->x.value = vec->x >> 6;
+ pt->x.fract = (vec->x & 0x3f) << 10;
+ pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
+ pt->y.value = vec->y >> 6;
+ pt->y.fract = (vec->y & 0x3f) << 10;
+ pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
+ return;
+}
+
+/*
+ This function builds an FT_Fixed from a float. It puts the integer part
+ in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
+ It fails if the integer part of the float number is greater than SHORT_MAX.
+*/
+static __inline FT_Fixed FT_FixedFromFloat(float f)
+{
+ short value = f;
+ unsigned short fract = (f - value) * 0xFFFF;
+ return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
+}
+
+/*
+ This function builds an FT_Fixed from a FIXED. It simply put f.value
+ in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
+*/
+static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
+{
+ return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
+}
+
+/*
+ * Based on WineEngGetGlyphOutline
+ *
+ */
+ULONG
+FASTCALL
+ftGdiGetGlyphOutline(
+ PDC dc,
+ WCHAR wch,
+ UINT iFormat,
+ LPGLYPHMETRICS pgm,
+ ULONG cjBuf,
+ PVOID pvBuf,
+ LPMAT2 pmat2,
+ BOOL bIgnoreRotation)
+{
+ static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
+ PDC_ATTR pdcattr;
+ PTEXTOBJ TextObj;
+ PFONTGDI FontGDI;
+ HFONT hFont = 0;
+ GLYPHMETRICS gm;
+ ULONG Size;
+ FT_Face ft_face;
+ FT_UInt glyph_index;
+ DWORD width, height, pitch, needed = 0;
+ FT_Bitmap ft_bitmap;
+ FT_Error error;
+ INT left, right, top = 0, bottom = 0;
+ FT_Angle angle = 0;
+ FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
+ FLOAT eM11, widthRatio = 1.0;
+ FT_Matrix transMat = identityMat;
+ BOOL needsTransform = FALSE;
+ INT orientation;
+ LONG aveWidth;
+ INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
+ OUTLINETEXTMETRICW *potm;
+ int n = 0;
+ FT_CharMap found = 0, charmap;
+ XFORM xForm;
+
+ DPRINT("%d, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
+ cjBuf, pvBuf, pmat2);
+
+ pdcattr = dc->pdcattr;
+
+ MatrixS2XForm(&xForm, &dc->dclevel.mxWorldToDevice);
+ eM11 = xForm.eM11;
+
+ hFont = pdcattr->hlfntNew;
+ TextObj = RealizeFontInit(hFont);
+
+ if (!TextObj)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return GDI_ERROR;
+ }
+ FontGDI = ObjToGDI(TextObj->Font, FONT);
+ ft_face = FontGDI->face;
+
+ aveWidth = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth: 0;
+ orientation = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation: 0;
+
+ Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
+ potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
+ if (!potm)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ TEXTOBJ_UnlockText(TextObj);
+ return GDI_ERROR;
+ }
+ IntGetOutlineTextMetrics(FontGDI, Size, potm);
+
+ IntLockFreeType;
+
+ /* During testing, I never saw this used. In here just incase.*/
+ if (ft_face->charmap == NULL)
+ {
+ DPRINT("WARNING: No charmap selected!\n");
+ DPRINT("This font face has %d charmaps\n", ft_face->num_charmaps);
+
+ for (n = 0; n < ft_face->num_charmaps; n++)
+ {
+ charmap = ft_face->charmaps[n];
+ DPRINT("found charmap encoding: %u\n", charmap->encoding);
+ if (charmap->encoding != 0)
+ {
+ found = charmap;
+ break;
+ }
+ }
+ if (!found)
+ {
+ DPRINT1("WARNING: Could not find desired charmap!\n");
+ }
+ error = FT_Set_Charmap(ft_face, found);
+ if (error)
+ {
+ DPRINT1("WARNING: Could not set the charmap!\n");
+ }
+ }
+
+// FT_Set_Pixel_Sizes(ft_face,
+// TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
+ /* FIXME should set character height if neg */
+// (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
+// TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
+
+ TEXTOBJ_UnlockText(TextObj);
+
+ if (iFormat & GGO_GLYPH_INDEX)
+ {
+ glyph_index = wch;
+ iFormat &= ~GGO_GLYPH_INDEX;
+ }
+ else glyph_index = FT_Get_Char_Index(ft_face, wch);
+
+ if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
+ load_flags |= FT_LOAD_NO_BITMAP;
+
+ if (iFormat & GGO_UNHINTED)
+ {
+ load_flags |= FT_LOAD_NO_HINTING;
+ iFormat &= ~GGO_UNHINTED;
+ }
+
+ error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
+ if (error)
+ {
+ DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
+ IntUnLockFreeType;
+ if (potm) ExFreePoolWithTag(potm, TAG_GDITEXT);
+ return GDI_ERROR;
+ }
+ IntUnLockFreeType;
+
+ if (aveWidth && potm)
+ {
+ widthRatio = (FLOAT)aveWidth * eM11 /
+ (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
+ }
+
+ left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
+ right = (INT)((ft_face->glyph->metrics.horiBearingX +
+ ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
+
+ adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
+ lsb = left >> 6;
+ bbx = (right - left) >> 6;
+
+ DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
+
+ IntLockFreeType;
+
+ /* Scaling transform */
+ if (aveWidth)
+ {
+ FT_Matrix scaleMat;
+ DPRINT("Scaling Trans!\n");
+ scaleMat.xx = FT_FixedFromFloat(widthRatio);
+ scaleMat.xy = 0;
+ scaleMat.yx = 0;
+ scaleMat.yy = (1 << 16);
+ FT_Matrix_Multiply(&scaleMat, &transMat);
+ needsTransform = TRUE;
+ }
+
+ /* Slant transform */
+ if (potm->otmTextMetrics.tmItalic)
+ {
+ FT_Matrix slantMat;
+ DPRINT("Slant Trans!\n");
+ slantMat.xx = (1 << 16);
+ slantMat.xy = ((1 << 16) >> 2);
+ slantMat.yx = 0;
+ slantMat.yy = (1 << 16);
+ FT_Matrix_Multiply(&slantMat, &transMat);
+ needsTransform = TRUE;
+ }
+
+ /* Rotation transform */
+ if (orientation)
+ {
+ FT_Matrix rotationMat;
+ FT_Vector vecAngle;
+ DPRINT("Rotation Trans!\n");
+ angle = FT_FixedFromFloat((float)orientation / 10.0);
+ FT_Vector_Unit(&vecAngle, angle);
+ rotationMat.xx = vecAngle.x;
+ rotationMat.xy = -vecAngle.y;
+ rotationMat.yx = -rotationMat.xy;
+ rotationMat.yy = rotationMat.xx;
+ FT_Matrix_Multiply(&rotationMat, &transMat);
+ needsTransform = TRUE;
+ }
+
+ /* Extra transformation specified by caller */
+ if (pmat2)
+ {
+ FT_Matrix extraMat;
+ DPRINT("MAT2 Matrix Trans!\n");
+ extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
+ extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
+ extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
+ extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
+ FT_Matrix_Multiply(&extraMat, &transMat);
+ needsTransform = TRUE;
+ }
+
+ if (potm) ExFreePoolWithTag(potm, TAG_GDITEXT); /* It looks like we are finished with potm ATM.*/
+
+ if (!needsTransform)
+ {
+ DPRINT("No Need to be Transformed!\n");
+ top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
+ bottom = (ft_face->glyph->metrics.horiBearingY -
+ ft_face->glyph->metrics.height) & -64;
+ gm.gmCellIncX = adv;
+ gm.gmCellIncY = 0;
+ }
+ else
+ {
+ INT xc, yc;
+ FT_Vector vec;
+ for (xc = 0; xc < 2; xc++)
+ {
+ for (yc = 0; yc < 2; yc++)
+ {
+ vec.x = (ft_face->glyph->metrics.horiBearingX +
+ xc * ft_face->glyph->metrics.width);
+ vec.y = ft_face->glyph->metrics.horiBearingY -
+ yc * ft_face->glyph->metrics.height;
+ DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
+ FT_Vector_Transform(&vec, &transMat);
+ if (xc == 0 && yc == 0)
+ {
+ left = right = vec.x;
+ top = bottom = vec.y;
+ }
+ else
+ {
+ if (vec.x < left) left = vec.x;
+ else if (vec.x > right) right = vec.x;
+ if (vec.y < bottom) bottom = vec.y;
+ else if (vec.y > top) top = vec.y;
+ }
+ }
+ }
+ left = left & -64;
+ right = (right + 63) & -64;
+ bottom = bottom & -64;
+ top = (top + 63) & -64;
+
+ DPRINT("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
+ vec.x = ft_face->glyph->metrics.horiAdvance;
+ vec.y = 0;
+ FT_Vector_Transform(&vec, &transMat);
+ gm.gmCellIncX = (vec.x+63) >> 6;
+ gm.gmCellIncY = -((vec.y+63) >> 6);
+ }
+ gm.gmBlackBoxX = (right - left) >> 6;
+ gm.gmBlackBoxY = (top - bottom) >> 6;
+ gm.gmptGlyphOrigin.x = left >> 6;
+ gm.gmptGlyphOrigin.y = top >> 6;
+
+ DPRINT("CX %d CY %d BBX %d BBY %d GOX %d GOY %d\n",
+ gm.gmCellIncX, gm.gmCellIncY,
+ gm.gmBlackBoxX, gm.gmBlackBoxY,
+ gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
+
+ IntUnLockFreeType;
+
+ if (pgm) RtlCopyMemory(pgm, &gm, sizeof(GLYPHMETRICS));
+
+ if (iFormat == GGO_METRICS)
+ {
+ DPRINT("GGO_METRICS Exit!\n");
+ return 1; /* FIXME */
+ }
+
+ if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
+ {
+ DPRINT1("loaded a bitmap\n");
+ return GDI_ERROR;
+ }
+
+ switch (iFormat)
+ {
+ case GGO_BITMAP:
+ width = gm.gmBlackBoxX;
+ height = gm.gmBlackBoxY;
+ pitch = ((width + 31) >> 5) << 2;
+ needed = pitch * height;
+
+ if (!pvBuf || !cjBuf) break;
+
+ switch (ft_face->glyph->format)
+ {
+ case ft_glyph_format_bitmap:
+ {
+ BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
+ INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
+ INT h = ft_face->glyph->bitmap.rows;
+ while (h--)
+ {
+ RtlCopyMemory(dst, src, w);
+ src += ft_face->glyph->bitmap.pitch;
+ dst += pitch;
+ }
+ break;
+ }
+
+ case ft_glyph_format_outline:
+ ft_bitmap.width = width;
+ ft_bitmap.rows = height;
+ ft_bitmap.pitch = pitch;
+ ft_bitmap.pixel_mode = ft_pixel_mode_mono;
+ ft_bitmap.buffer = pvBuf;
+
+ IntLockFreeType;
+ if (needsTransform)
+ {
+ FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
+ }
+ FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
+ /* Note: FreeType will only set 'black' bits for us. */
+ RtlZeroMemory(pvBuf, needed);
+ FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
+ IntUnLockFreeType;
+ break;
+
+ default:
+ DPRINT1("loaded glyph format %x\n", ft_face->glyph->format);
+ return GDI_ERROR;
+ }
+ break;
+
+ case GGO_GRAY2_BITMAP:
+ case GGO_GRAY4_BITMAP:
+ case GGO_GRAY8_BITMAP:
+ {
+ unsigned int mult, row, col;
+ BYTE *start, *ptr;
+
+ width = gm.gmBlackBoxX;
+ height = gm.gmBlackBoxY;
+ pitch = (width + 3) / 4 * 4;
+ needed = pitch * height;
+
+ if (!pvBuf || !cjBuf) break;
+
+ switch (ft_face->glyph->format)
+ {
+ case ft_glyph_format_bitmap:
+ {
+ BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
+ INT h = ft_face->glyph->bitmap.rows;
+ INT x;
+ while (h--)
+ {
+ for (x = 0; x < pitch; x++)
+ {
+ if (x < ft_face->glyph->bitmap.width)
+ dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
+ else
+ dst[x] = 0;
+ }
+ src += ft_face->glyph->bitmap.pitch;
+ dst += pitch;
+ }
+ return needed;
+ }
+ case ft_glyph_format_outline:
+ {
+ ft_bitmap.width = width;
+ ft_bitmap.rows = height;
+ ft_bitmap.pitch = pitch;
+ ft_bitmap.pixel_mode = ft_pixel_mode_grays;
+ ft_bitmap.buffer = pvBuf;
+
+ IntLockFreeType;
+ if (needsTransform)
+ {
+ FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
+ }
+ FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
+ RtlZeroMemory(ft_bitmap.buffer, cjBuf);
+ FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
+ IntUnLockFreeType;
+
+ if (iFormat == GGO_GRAY2_BITMAP)
+ mult = 4;
+ else if (iFormat == GGO_GRAY4_BITMAP)
+ mult = 16;
+ else if (iFormat == GGO_GRAY8_BITMAP)
+ mult = 64;
+ else
+ {
+ return GDI_ERROR;
+ }
+ }
+ default:
+ DPRINT1("loaded glyph format %x\n", ft_face->glyph->format);
+ return GDI_ERROR;
+ }
+ start = pvBuf;
+ for (row = 0; row < height; row++)
+ {
+ ptr = start;
+ for (col = 0; col < width; col++, ptr++)
+ {
+ *ptr = (((int)*ptr) * mult + 128) / 256;
+ }
+ start += pitch;
+ }
+ break;
+ }
+
+ case GGO_NATIVE:
+ {
+ int contour, point = 0, first_pt;
+ FT_Outline *outline = &ft_face->glyph->outline;
+ TTPOLYGONHEADER *pph;
+ TTPOLYCURVE *ppc;
+ DWORD pph_start, cpfx, type;
+
+ if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
+
+ IntLockFreeType;
+ if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
+
+ for (contour = 0; contour < outline->n_contours; contour++)
+ {
+ pph_start = needed;
+ pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
+ first_pt = point;
+ if (pvBuf)
+ {
+ pph->dwType = TT_POLYGON_TYPE;
+ FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
+ }
+ needed += sizeof(*pph);
+ point++;
+ while (point <= outline->contours[contour])
+ {
+ ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
+ type = (outline->tags[point] & FT_Curve_Tag_On) ?
+ TT_PRIM_LINE : TT_PRIM_QSPLINE;
+ cpfx = 0;
+ do
+ {
+ if (pvBuf)
+ FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
+ cpfx++;
+ point++;
+ }
+ while (point <= outline->contours[contour] &&
+ (outline->tags[point] & FT_Curve_Tag_On) ==
+ (outline->tags[point-1] & FT_Curve_Tag_On));
+
+ /* At the end of a contour Windows adds the start point, but
+ only for Beziers */
+ if (point > outline->contours[contour] &&
+ !(outline->tags[point-1] & FT_Curve_Tag_On))
+ {
+ if (pvBuf)
+ FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
+ cpfx++;
+ }
+ else if (point <= outline->contours[contour] &&
+ outline->tags[point] & FT_Curve_Tag_On)
+ {
+ /* add closing pt for bezier */
+ if (pvBuf)
+ FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
+ cpfx++;
+ point++;
+ }
+ if (pvBuf)
+ {
+ ppc->wType = type;
+ ppc->cpfx = cpfx;
+ }
+ needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
+ }
+ if (pvBuf) pph->cb = needed - pph_start;
+ }
+ IntUnLockFreeType;
+ break;
+ }
+ case GGO_BEZIER:
+ {
+ /* Convert the quadratic Beziers to cubic Beziers.
+ The parametric eqn for a cubic Bezier is, from PLRM:
+ r(t) = at^3 + bt^2 + ct + r0
+ with the control points:
+ r1 = r0 + c/3
+ r2 = r1 + (c + b)/3
+ r3 = r0 + c + b + a
+
+ A quadratic Beizer has the form:
+ p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
+
+ So equating powers of t leads to:
+ r1 = 2/3 p1 + 1/3 p0
+ r2 = 2/3 p1 + 1/3 p2
+ and of course r0 = p0, r3 = p2
+ */
+
+ int contour, point = 0, first_pt;
+ FT_Outline *outline = &ft_face->glyph->outline;
+ TTPOLYGONHEADER *pph;
+ TTPOLYCURVE *ppc;
+ DWORD pph_start, cpfx, type;
+ FT_Vector cubic_control[4];
+ if (cjBuf == 0) pvBuf = NULL;
+
+ if (needsTransform && pvBuf)
+ {
+ IntLockFreeType;
+ FT_Outline_Transform(outline, &transMat);
+ IntUnLockFreeType;
+ }
+
+ for (contour = 0; contour < outline->n_contours; contour++)
+ {
+ pph_start = needed;
+ pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
+ first_pt = point;
+ if (pvBuf)
+ {
+ pph->dwType = TT_POLYGON_TYPE;
+ FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
+ }
+ needed += sizeof(*pph);
+ point++;
+ while (point <= outline->contours[contour])
+ {
+ ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
+ type = (outline->tags[point] & FT_Curve_Tag_On) ?
+ TT_PRIM_LINE : TT_PRIM_CSPLINE;
+ cpfx = 0;
+ do
+ {
+ if (type == TT_PRIM_LINE)
+ {
+ if (pvBuf)
+ FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
+ cpfx++;
+ point++;
+ }
+ else
+ {
+ /* Unlike QSPLINEs, CSPLINEs always have their endpoint
+ so cpfx = 3n */
+
+ /* FIXME: Possible optimization in endpoint calculation
+ if there are two consecutive curves */
+ cubic_control[0] = outline->points[point-1];
+ if (!(outline->tags[point-1] & FT_Curve_Tag_On))
+ {
+ cubic_control[0].x += outline->points[point].x + 1;
+ cubic_control[0].y += outline->points[point].y + 1;
+ cubic_control[0].x >>= 1;
+ cubic_control[0].y >>= 1;
+ }
+ if (point+1 > outline->contours[contour])
+ cubic_control[3] = outline->points[first_pt];
+ else
+ {
+ cubic_control[3] = outline->points[point+1];
+ if (!(outline->tags[point+1] & FT_Curve_Tag_On))
+ {
+ cubic_control[3].x += outline->points[point].x + 1;
+ cubic_control[3].y += outline->points[point].y + 1;
+ cubic_control[3].x >>= 1;
+ cubic_control[3].y >>= 1;
+ }
+ }
+ /* r1 = 1/3 p0 + 2/3 p1
+ r2 = 1/3 p2 + 2/3 p1 */
+ cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
+ cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
+ cubic_control[2] = cubic_control[1];
+ cubic_control[1].x += (cubic_control[0].x + 1) / 3;
+ cubic_control[1].y += (cubic_control[0].y + 1) / 3;
+ cubic_control[2].x += (cubic_control[3].x + 1) / 3;
+ cubic_control[2].y += (cubic_control[3].y + 1) / 3;
+ if (pvBuf)
+ {
+ FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
+ FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
+ FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
+ }
+ cpfx += 3;
+ point++;
+ }
+ }
+ while (point <= outline->contours[contour] &&
+ (outline->tags[point] & FT_Curve_Tag_On) ==
+ (outline->tags[point-1] & FT_Curve_Tag_On));
+ /* At the end of a contour Windows adds the start point,
+ but only for Beziers and we've already done that.
+ */
+ if (point <= outline->contours[contour] &&
+ outline->tags[point] & FT_Curve_Tag_On)
+ {
+ /* This is the closing pt of a bezier, but we've already
+ added it, so just inc point and carry on */
+ point++;
+ }
+ if (pvBuf)
+ {
+ ppc->wType = type;
+ ppc->cpfx = cpfx;
+ }
+ needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
+ }
+ if (pvBuf) pph->cb = needed - pph_start;
+ }
+ break;
+ }
+
+ default:
+ DPRINT1("Unsupported format %d\n", iFormat);
+ return GDI_ERROR;
+ }
+
+ DPRINT("ftGdiGetGlyphOutline END and needed %d\n", needed);
+ return needed;
+}
+
+BOOL
+FASTCALL
+TextIntGetTextExtentPoint(PDC dc,
+ PTEXTOBJ TextObj,
+ LPCWSTR String,
+ int Count,
+ int MaxExtent,
+ LPINT Fit,
+ LPINT Dx,
+ LPSIZE Size)
+{
+ PFONTGDI FontGDI;
+ FT_Face face;
+ FT_GlyphSlot glyph;
+ FT_BitmapGlyph realglyph;
+ INT error, n, glyph_index, i, previous;
+ ULONGLONG TotalWidth = 0;
+ FT_CharMap charmap, found = NULL;
+ BOOL use_kerning;
+ FT_Render_Mode RenderMode;
+ BOOLEAN Render;
+
+ FontGDI = ObjToGDI(TextObj->Font, FONT);
+
+ face = FontGDI->face;
+ if (NULL != Fit)
+ {
+ *Fit = 0;
+ }
+
+ IntLockFreeType;
+ if (face->charmap == NULL)
+ {
+ DPRINT("WARNING: No charmap selected!\n");
+ DPRINT("This font face has %d charmaps\n", face->num_charmaps);
+
+ for (n = 0; n < face->num_charmaps; n++)
+ {
+ charmap = face->charmaps[n];
+ DPRINT("found charmap encoding: %u\n", charmap->encoding);
+ if (charmap->encoding != 0)
+ {
+ found = charmap;
+ break;
+ }
+ }
+
+ if (! found)
+ {
+ DPRINT1("WARNING: Could not find desired charmap!\n");
+ }
+
+ error = FT_Set_Charmap(face, found);
+ if (error)
+ {
+ DPRINT1("WARNING: Could not set the charmap!\n");
+ }
+ }
+
+ Render = IntIsFontRenderingEnabled();
+ if (Render)
+ RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
+ else
+ RenderMode = FT_RENDER_MODE_MONO;
+
+ error = FT_Set_Pixel_Sizes(face,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
+ /* FIXME should set character height if neg */
+ (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
+ - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
+ if (error)
+ {
+ DPRINT1("Error in setting pixel sizes: %u\n", error);
+ }
+
+ use_kerning = FT_HAS_KERNING(face);
+ previous = 0;
+
+ for (i = 0; i < Count; i++)
+ {
+ glyph_index = FT_Get_Char_Index(face, *String);
+ if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
+ {
+ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+ if (error)
+ {
+ DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
+ break;
+ }
+
+ glyph = face->glyph;
+ realglyph = ftGdiGlyphCacheSet(face, glyph_index,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);
+ if (!realglyph)
+ {
+ DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
+ break;
+ }
+ }
+
+ /* retrieve kerning distance */
+ if (use_kerning && previous && glyph_index)
+ {
+ FT_Vector delta;
+ FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
+ TotalWidth += delta.x;
+ }
+
+ TotalWidth += realglyph->root.advance.x >> 10;
+
+ if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
+ {
+ *Fit = i + 1;
+ }
+ if (NULL != Dx)
+ {
+ Dx[i] = (TotalWidth + 32) >> 6;
+ }
+
+ previous = glyph_index;
+ String++;
+ }
+ IntUnLockFreeType;
+
+ Size->cx = (TotalWidth + 32) >> 6;
+ Size->cy = (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight);
+ Size->cy = EngMulDiv(Size->cy, dc->ppdev->gdiinfo.ulLogPixelsY, 72);
+
+ return TRUE;
+}
+
+
+INT
+FASTCALL
+ftGdiGetTextCharsetInfo(
+ PDC Dc,
+ LPFONTSIGNATURE lpSig,
+ DWORD dwFlags)
+{
+ PDC_ATTR pdcattr;
+ UINT Ret = DEFAULT_CHARSET, i;
+ HFONT hFont;
+ PTEXTOBJ TextObj;
+ PFONTGDI FontGdi;
+ FONTSIGNATURE fs;
+ TT_OS2 *pOS2;
+ FT_Face Face;
+ CHARSETINFO csi;
+ DWORD cp, fs0;
+ USHORT usACP, usOEM;
+
+ pdcattr = Dc->pdcattr;
+ hFont = pdcattr->hlfntNew;
+ TextObj = RealizeFontInit(hFont);
+
+ if (!TextObj)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return Ret;
+ }
+ FontGdi = ObjToGDI(TextObj->Font, FONT);
+ Face = FontGdi->face;
+ TEXTOBJ_UnlockText(TextObj);
+
+ IntLockFreeType;
+ pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
+ IntUnLockFreeType;
+ memset(&fs, 0, sizeof(FONTSIGNATURE));
+ if (NULL != pOS2)
+ {
+ fs.fsCsb[0] = pOS2->ulCodePageRange1;
+ fs.fsCsb[1] = pOS2->ulCodePageRange2;
+ fs.fsUsb[0] = pOS2->ulUnicodeRange1;
+ fs.fsUsb[1] = pOS2->ulUnicodeRange2;
+ fs.fsUsb[2] = pOS2->ulUnicodeRange3;
+ fs.fsUsb[3] = pOS2->ulUnicodeRange4;
+ if (pOS2->version == 0)
+ {
+ FT_UInt dummy;
+
+ if (FT_Get_First_Char( Face, &dummy ) < 0x100)
+ fs.fsCsb[0] |= FS_LATIN1;
+ else
+ fs.fsCsb[0] |= FS_SYMBOL;
+ }
+ }
+ DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
+ if (fs.fsCsb[0] == 0)
+ { /* let's see if we can find any interesting cmaps */
+ for (i = 0; i < Face->num_charmaps; i++)
+ {
+ switch (Face->charmaps[i]->encoding)
+ {
+ case FT_ENCODING_UNICODE:
+ case FT_ENCODING_APPLE_ROMAN:
+ fs.fsCsb[0] |= FS_LATIN1;
+ break;
+ case FT_ENCODING_MS_SYMBOL:
+ fs.fsCsb[0] |= FS_SYMBOL;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ if (lpSig)
+ {
+ RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
+ }
+
+ RtlGetDefaultCodePage(&usACP, &usOEM);
+ cp = usACP;
+
+ if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
+ if (csi.fs.fsCsb[0] & fs.fsCsb[0])
+ {
+ DPRINT("Hit 1\n");
+ Ret = csi.ciCharset;
+ goto Exit;
+ }
+
+ for (i = 0; i < MAXTCIINDEX; i++)
+ {
+ fs0 = 1L << i;
+ if (fs.fsCsb[0] & fs0)
+ {
+ if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
+ {
+ //*cp = csi.ciACP;
+ DPRINT("Hit 2\n");
+ Ret = csi.ciCharset;
+ goto Exit;
+ }
+ else
+ DPRINT1("TCI failing on %x\n", fs0);
+ }
+ }
+Exit:
+ DPRINT("CharSet %d CodePage %d\n",csi.ciCharset, csi.ciACP);
+ return (MAKELONG(csi.ciACP, csi.ciCharset));
+}
+
+
+DWORD
+FASTCALL
+ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
+{
+ DWORD size = 0;
+ DWORD num_ranges = 0;
+ FT_Face face = Font->face;
+
+ if (face->charmap->encoding == FT_ENCODING_UNICODE)
+ {
+ FT_UInt glyph_code = 0;
+ FT_ULong char_code, char_code_prev;
+
+ char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
+
+ DPRINT("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
+ face->num_glyphs, glyph_code, char_code);
+
+ if (!glyph_code) return 0;
+
+ if (glyphset)
+ {
+ glyphset->ranges[0].wcLow = (USHORT)char_code;
+ glyphset->ranges[0].cGlyphs = 0;
+ glyphset->cGlyphsSupported = 0;
+ }
+
+ num_ranges = 1;
+ while (glyph_code)
+ {
+ if (char_code < char_code_prev)
+ {
+ DPRINT1("expected increasing char code from FT_Get_Next_Char\n");
+ return 0;
+ }
+ if (char_code - char_code_prev > 1)
+ {
+ num_ranges++;
+ if (glyphset)
+ {
+ glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
+ glyphset->ranges[num_ranges - 1].cGlyphs = 1;
+ glyphset->cGlyphsSupported++;
+ }
+ }
+ else if (glyphset)
+ {
+ glyphset->ranges[num_ranges - 1].cGlyphs++;
+ glyphset->cGlyphsSupported++;
+ }
+ char_code_prev = char_code;
+ char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
+ }
+ }
+ else
+ DPRINT1("encoding %u not supported\n", face->charmap->encoding);
+
+ size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
+ if (glyphset)
+ {
+ glyphset->cbThis = size;
+ glyphset->cRanges = num_ranges;
+ }
+ return size;
+}
+
+
+BOOL
+FASTCALL
+ftGdiGetTextMetricsW(
+ HDC hDC,
+ PTMW_INTERNAL ptmwi)
+{
+ PDC dc;
+ PDC_ATTR pdcattr;
+ PTEXTOBJ TextObj;
+ PFONTGDI FontGDI;
+ FT_Face Face;
+ TT_OS2 *pOS2;
+ TT_HoriHeader *pHori;
+ FT_WinFNT_HeaderRec Win;
+ ULONG Error;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (!ptmwi)
+ {
+ SetLastWin32Error(STATUS_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ if (!(dc = DC_LockDc(hDC)))
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ pdcattr = dc->pdcattr;
+ TextObj = RealizeFontInit(pdcattr->hlfntNew);
+ if (NULL != TextObj)
+ {
+ FontGDI = ObjToGDI(TextObj->Font, FONT);
+
+ Face = FontGDI->face;
+ IntLockFreeType;
+ Error = FT_Set_Pixel_Sizes(Face,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
+ /* FIXME should set character height if neg */
+ (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
+ - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
+ IntUnLockFreeType;
+ if (0 != Error)
+ {
+ DPRINT1("Error in setting pixel sizes: %u\n", Error);
+ Status = STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ Status = STATUS_SUCCESS;
+
+ IntLockFreeType;
+ pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
+ if (NULL == pOS2)
+ {
+ DPRINT1("Can't find OS/2 table - not TT font?\n");
+ Status = STATUS_INTERNAL_ERROR;
+ }
+
+ pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
+ if (NULL == pHori)
+ {
+ DPRINT1("Can't find HHEA table - not TT font?\n");
+ Status = STATUS_INTERNAL_ERROR;
+ }
+
+ Error = FT_Get_WinFNT_Header(FontGDI->face , &Win);
+
+ IntUnLockFreeType;
+
+ if (NT_SUCCESS(Status))
+ {
+ if (!(FontGDI->flRealizedType & FDM_TYPE_TEXT_METRIC))
+ {
+ FillTM(&FontGDI->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
+ FontGDI->flRealizedType |= FDM_TYPE_TEXT_METRIC;
+ }
+
+ RtlCopyMemory(&ptmwi->TextMetric, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
+ /* FIXME: Fill Diff member */
+ RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
+ }
+ }
+ TEXTOBJ_UnlockText(TextObj);
+ }
+ else
+ {
+ Status = STATUS_INVALID_HANDLE;
+ }
+ DC_UnlockDc(dc);
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+DWORD
+FASTCALL
+ftGdiGetFontData(
+ PFONTGDI FontGdi,
+ DWORD Table,
+ DWORD Offset,
+ PVOID Buffer,
+ DWORD Size)
+{
+ DWORD Result = GDI_ERROR;
+
+ IntLockFreeType;
+
+ if (FT_IS_SFNT(FontGdi->face))
+ {
+ if (Table)
+ Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
+ (Table << 8 & 0xFF0000);
+
+ if (!Buffer) Size = 0;
+
+ if (Buffer && Size)
+ {
+ FT_Error Error;
+ FT_ULong Needed = 0;
+
+ Error = FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, NULL, &Needed);
+
+ if ( !Error && Needed < Size) Size = Needed;
+ }
+ if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
+ Result = Size;
+ }
+
+ IntUnLockFreeType;
+
+ return Result;
+}
+
+static UINT FASTCALL
+GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
+{
+ ANSI_STRING EntryFaceNameA;
+ UNICODE_STRING EntryFaceNameW;
+ unsigned Size;
+ OUTLINETEXTMETRICW *Otm;
+ LONG WeightDiff;
+ NTSTATUS Status;
+ UINT Score = 1;
+
+ RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
+ Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
+ if (NT_SUCCESS(Status))
+ {
+ if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
+ {
+ EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
+ EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
+ }
+ if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
+ {
+ Score += 49;
+ }
+ RtlFreeUnicodeString(&EntryFaceNameW);
+ }
+
+ Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
+ Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
+ if (NULL == Otm)
+ {
+ return Score;
+ }
+ IntGetOutlineTextMetrics(FontGDI, Size, Otm);
+
+ if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
+ (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
+ {
+ Score += 25;
+ }
+ if (LogFont->lfWeight != FW_DONTCARE)
+ {
+ if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
+ {
+ WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
+ }
+ else
+ {
+ WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
+ }
+ Score += (1000 - WeightDiff) / (1000 / 25);
+ }
+ else
+ {
+ Score += 25;
+ }
+
+ ExFreePool(Otm);
+
+ return Score;
+}
+
+static __inline VOID
+FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
+ PUNICODE_STRING FaceName, PLIST_ENTRY Head)
+{
+ PLIST_ENTRY Entry;
+ PFONT_ENTRY CurrentEntry;
+ FONTGDI *FontGDI;
+ UINT Score;
+
+ Entry = Head->Flink;
+ while (Entry != Head)
+ {
+ CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
+
+ FontGDI = CurrentEntry->Font;
+ ASSERT(FontGDI);
+
+ Score = GetFontScore(LogFont, FaceName, FontGDI);
+ if (*MatchScore == 0 || *MatchScore < Score)
+ {
+ *FontObj = GDIToObj(FontGDI, FONT);
+ *MatchScore = Score;
+ }
+ Entry = Entry->Flink;
+ }
+}
+
+static __inline BOOLEAN
+SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
+ LPCWSTR Key)
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
+ NTSTATUS Status;
+ UNICODE_STRING Value;
+
+ RtlInitUnicodeString(&Value, NULL);
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
+ RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = FaceName->Buffer;
+ QueryTable[0].EntryContext = &Value;
+ QueryTable[0].DefaultType = REG_NONE;
+ QueryTable[0].DefaultData = NULL;
+ QueryTable[0].DefaultLength = 0;
+
+ QueryTable[1].QueryRoutine = NULL;
+ QueryTable[1].Name = NULL;
+
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
+ Key,
+ QueryTable,
+ NULL,
+ NULL);
+ if (NT_SUCCESS(Status))
+ {
+ RtlFreeUnicodeString(FaceName);
+ *FaceName = Value;
+ }
+
+ return NT_SUCCESS(Status);
+}
+
+static __inline void
+SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
+{
+ if (10 < Level) /* Enough is enough */
+ {
+ return;
+ }
+
+ if (SubstituteFontFamilyKey(FaceName, L"SysFontSubstitutes") ||
+ SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
+ {
+ SubstituteFontFamily(FaceName, Level + 1);
+ }
+}
+
+static
+VOID
+FASTCALL
+IntFontType(PFONTGDI Font)
+{
+ PS_FontInfoRec psfInfo;
+ FT_ULong tmp_size = 0;
+
+ if (FT_HAS_MULTIPLE_MASTERS(Font->face))
+ Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
+ if (FT_HAS_VERTICAL( Font->face ))
+ Font->FontObj.flFontType |= FO_VERT_FACE;
+ if (FT_IS_SCALABLE( Font->face ))
+ Font->FontObj.flFontType |= FO_TYPE_RASTER;
+ if (FT_IS_SFNT(Font->face))
+ {
+ Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
+ if (FT_Get_Sfnt_Table(Font->face, ft_sfnt_post))
+ Font->FontObj.flFontType |= FO_POSTSCRIPT;
+ }
+ if (!FT_Get_PS_Font_Info(Font->face, &psfInfo ))
+ {
+ Font->FontObj.flFontType |= FO_POSTSCRIPT;
+ }
+ /* check for the presence of the 'CFF ' table to check if the font is Type1 */
+ if (!FT_Load_Sfnt_Table(Font->face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
+ {
+ Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
+ }
+}
+
+NTSTATUS
+FASTCALL
+TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PTEXTOBJ TextObj;
+ UNICODE_STRING FaceName;
+ PPROCESSINFO Win32Process;
+ UINT MatchScore;
+
+ if (!pTextObj)
+ {
+ TextObj = TEXTOBJ_LockText(FontHandle);
+ if (NULL == TextObj)
+ {
+ return STATUS_INVALID_HANDLE;
+ }
+
+ if (TextObj->fl & TEXTOBJECT_INIT)
+ {
+ TEXTOBJ_UnlockText(TextObj);
+ return STATUS_SUCCESS;
+ }
+ }
+ else
+ TextObj = pTextObj;
+
+ if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName))
+ {
+ if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
+ return STATUS_NO_MEMORY;
+ }
+ SubstituteFontFamily(&FaceName, 0);
+ MatchScore = 0;
+ TextObj->Font = NULL;
+
+ /* First search private fonts */
+ Win32Process = PsGetCurrentProcessWin32Process();
+ IntLockProcessPrivateFonts(Win32Process);
+ FindBestFontFromList(&TextObj->Font, &MatchScore,
+ &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
+ &Win32Process->PrivateFontListHead);
+ IntUnLockProcessPrivateFonts(Win32Process);
+
+ /* Search system fonts */
+ IntLockGlobalFonts;
+ FindBestFontFromList(&TextObj->Font, &MatchScore,
+ &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
+ &FontListHead);
+ IntUnLockGlobalFonts;
+ if (NULL == TextObj->Font)
+ {
+ DPRINT1("Requested font %S not found, no fonts loaded at all\n",
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName);
+ Status = STATUS_NOT_FOUND;
+ }
+ else
+ {
+ PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
+ // Need hdev, when freetype is loaded need to create DEVOBJ for
+ // Consumer and Producer.
+ TextObj->Font->iUniq = 1; // Now it can be cached.
+ IntFontType(FontGdi);
+ FontGdi->flType = TextObj->Font->flFontType;
+ FontGdi->flRealizedType = 0;
+ FontGdi->Underline = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfUnderline ? 0xff : 0;
+ FontGdi->StrikeOut = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfStrikeOut ? 0xff : 0;
+ TextObj->fl |= TEXTOBJECT_INIT;
+ Status = STATUS_SUCCESS;
+ }
+
+ RtlFreeUnicodeString(&FaceName);
+ if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
+
+ ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
+
+ return Status;
+}
+
+
+static
+BOOL
+FASTCALL
+IntGetFullFileName(
+ POBJECT_NAME_INFORMATION NameInfo,
+ ULONG Size,
+ PUNICODE_STRING FileName)
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE hFile;
+ IO_STATUS_BLOCK IoStatusBlock;
+ ULONG Desired;
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ FileName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = ZwOpenFile(
+ &hFile,
+ 0, //FILE_READ_ATTRIBUTES,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ 0);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
+ return FALSE;
+ }
+
+ Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
+ ZwClose(hFile);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL
+FASTCALL
+IntGdiGetFontResourceInfo(
+ PUNICODE_STRING FileName,
+ PVOID pBuffer,
+ DWORD *pdwBytes,
+ DWORD dwType)
+{
+ UNICODE_STRING EntryFileName;
+ POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
+ PLIST_ENTRY ListEntry;
+ PFONT_ENTRY FontEntry;
+ FONTFAMILYINFO Info;
+ ULONG Size;
+ BOOL bFound = FALSE;
+
+ /* Create buffer for full path name */
+ Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
+ NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
+ if (!NameInfo1)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ /* Get the full path name */
+ if (!IntGetFullFileName(NameInfo1, Size, FileName))
+ {
+ ExFreePool(NameInfo1);
+ return FALSE;
+ }
+
+ /* Create a buffer for the entries' names */
+ NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
+ if (!NameInfo2)
+ {
+ ExFreePool(NameInfo1);
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ /* Try to find the pathname in the global font list */
+ IntLockGlobalFonts;
+ for (ListEntry = FontListHead.Flink;
+ ListEntry != &FontListHead;
+ ListEntry = ListEntry->Flink)
+ {
+ FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
+ if (FontEntry->Font->Filename != NULL)
+ {
+ RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
+ if (IntGetFullFileName(NameInfo2, Size, &EntryFileName))
+ {
+ if (RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
+ {
+ /* found */
+ FontFamilyFillInfo(&Info, FontEntry->FaceName.Buffer, FontEntry->Font);
+ bFound = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ IntUnLockGlobalFonts;
+
+ /* Free the buffers */
+ ExFreePool(NameInfo1);
+ ExFreePool(NameInfo2);
+
+ if (!bFound && dwType != 5)
+ {
+ /* Font could not be found in system table
+ dwType == 5 will still handle this */
+ return FALSE;
+ }
+
+ switch (dwType)
+ {
+ case 0: /* FIXME: returns 1 or 2, don't know what this is atm */
+ *(DWORD*)pBuffer = 1;
+ *pdwBytes = sizeof(DWORD);
+ break;
+
+ case 1: /* Copy the full font name */
+ Size = wcslen(Info.EnumLogFontEx.elfFullName) + 1;
+ Size = min(Size , LF_FULLFACESIZE) * sizeof(WCHAR);
+ RtlCopyMemory(pBuffer, Info.EnumLogFontEx.elfFullName, Size);
+ // FIXME: Do we have to zeroterminate?
+ *pdwBytes = Size;
+ break;
+
+ case 2: /* Copy a LOGFONTW structure */
+ Info.EnumLogFontEx.elfLogFont.lfWidth = 0;
+ RtlCopyMemory(pBuffer, &Info.EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
+ *pdwBytes = sizeof(LOGFONTW);
+ break;
+
+ case 3: /* FIXME: What exactly is copied here? */
+ *(DWORD*)pBuffer = 1;
+ *pdwBytes = sizeof(DWORD*);
+ break;
+
+ case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
+ *(BOOL*)pBuffer = !bFound;
+ *pdwBytes = sizeof(BOOL);
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOL
+FASTCALL
+ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
+{
+ if (FT_HAS_FIXED_SIZES(Font->face))
+ Info->iTechnology = RI_TECH_BITMAP;
+ else
+ {
+ if (FT_IS_SCALABLE(Font->face))
+ Info->iTechnology = RI_TECH_SCALABLE;
+ else
+ Info->iTechnology = RI_TECH_FIXED;
+ }
+ Info->iUniq = Font->FontObj.iUniq;
+ Info->dwUnknown = -1;
+ return TRUE;
+}
+
+
+DWORD
+FASTCALL
+ftGdiGetKerningPairs( PFONTGDI Font,
+ DWORD cPairs,
+ LPKERNINGPAIR pKerningPair)
+{
+ DWORD Count = 0;
+ INT i = 0;
+ FT_Face face = Font->face;
+
+ if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
+ {
+ FT_UInt previous_index = 0, glyph_index = 0;
+ FT_ULong char_code, char_previous;
+ FT_Vector delta;
+
+ char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
+
+ IntLockFreeType;
+
+ while (glyph_index)
+ {
+ if (previous_index && glyph_index)
+ {
+ FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
+
+ if (pKerningPair && cPairs)
+ {
+ pKerningPair[i].wFirst = char_previous;
+ pKerningPair[i].wSecond = char_code;
+ pKerningPair[i].iKernAmount = delta.x;
+ i++;
+ if (i == cPairs) break;
+ }
+ Count++;
+ }
+ previous_index = glyph_index;
+ char_previous = char_code;
+ char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
+ }
+ IntUnLockFreeType;
+ }
+ return Count;
+}
+
+
+//////////////////
+//
+// Functions needing sorting.
+//
+///////////////
+int APIENTRY
+NtGdiGetFontFamilyInfo(HDC Dc,
+ LPLOGFONTW UnsafeLogFont,
+ PFONTFAMILYINFO UnsafeInfo,
+ DWORD Size)
+{
+ NTSTATUS Status;
+ LOGFONTW LogFont;
+ PFONTFAMILYINFO Info;
+ DWORD Count;
+ PPROCESSINFO Win32Process;
+
+ /* Make a safe copy */
+ Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
+ if (! NT_SUCCESS(Status))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return -1;
+ }
+
+ /* Allocate space for a safe copy */
+ Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), TAG_GDITEXT);
+ if (NULL == Info)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return -1;
+ }
+
+ /* Enumerate font families in the global list */
+ IntLockGlobalFonts;
+ Count = 0;
+ if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
+ {
+ IntUnLockGlobalFonts;
+ ExFreePool(Info);
+ return -1;
+ }
+ IntUnLockGlobalFonts;
+
+ /* Enumerate font families in the process local list */
+ Win32Process = PsGetCurrentProcessWin32Process();
+ IntLockProcessPrivateFonts(Win32Process);
+ if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
+ &Win32Process->PrivateFontListHead))
+ {
+ IntUnLockProcessPrivateFonts(Win32Process);
+ ExFreePool(Info);
+ return -1;
+ }
+ IntUnLockProcessPrivateFonts(Win32Process);
+
+ /* Enumerate font families in the registry */
+ if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
+ {
+ ExFreePool(Info);
+ return -1;
+ }
+
+ /* Return data to caller */
+ if (0 != Count)
+ {
+ Status = MmCopyToCaller(UnsafeInfo, Info,
+ (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
+ if (! NT_SUCCESS(Status))
+ {
+ ExFreePool(Info);
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return -1;
+ }
+ }
+
+ ExFreePool(Info);
+
+ return Count;
+}
+
+BOOL
+APIENTRY
+GreExtTextOutW(
+ IN HDC hDC,
+ IN INT XStart,
+ IN INT YStart,
+ IN UINT fuOptions,
+ IN OPTIONAL PRECTL lprc,
+ IN LPWSTR String,
+ IN INT Count,
+ IN OPTIONAL LPINT Dx,
+ IN DWORD dwCodePage)
+{
+ /*
+ * FIXME:
+ * Call EngTextOut, which does the real work (calling DrvTextOut where
+ * appropriate)
+ */
+
+ DC *dc;
+ PDC_ATTR pdcattr;
+ SURFOBJ *SurfObj;
+ SURFACE *psurf = NULL;
+ int error, glyph_index, n, i;
+ FT_Face face;
+ FT_GlyphSlot glyph;
+ FT_BitmapGlyph realglyph;
+ LONGLONG TextLeft, RealXStart;
+ ULONG TextTop, previous, BackgroundLeft;
+ FT_Bool use_kerning;
+ RECTL DestRect, MaskRect, DummyRect = {0, 0, 0, 0};
+ POINTL SourcePoint, BrushOrigin;
+ HBITMAP HSourceGlyph;
+ SURFOBJ *SourceGlyphSurf;
+ SIZEL bitSize;
+ FT_CharMap found = 0, charmap;
+ INT yoff;
+ FONTOBJ *FontObj;
+ PFONTGDI FontGDI;
+ PTEXTOBJ TextObj = NULL;
+ EXLATEOBJ exloRGB2Dst, exloDst2RGB;
+ FT_Render_Mode RenderMode;
+ BOOLEAN Render;
+ POINT Start;
+ BOOL DoBreak = FALSE;
+ PPALETTE ppalDst;
+ USHORT DxShift;
+
+ // TODO: Write test-cases to exactly match real Windows in different
+ // bad parameters (e.g. does Windows check the DC or the RECT first?).
+ dc = DC_LockDc(hDC);
+ if (!dc)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ if (dc->dctype == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(dc);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ pdcattr = dc->pdcattr;
+
+ if ((fuOptions & ETO_OPAQUE) || pdcattr->jBkMode == OPAQUE)
+ {
+ if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
+ DC_vUpdateBackgroundBrush(dc);
+ }
+
+ /* Check if String is valid */
+ if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ goto fail;
+ }
+
+ DxShift = fuOptions & ETO_PDY ? 1 : 0;
+
+ if (PATH_IsPathOpen(dc->dclevel))
+ {
+ if (!PATH_ExtTextOut( dc,
+ XStart,
+ YStart,
+ fuOptions,
+ (const RECTL *)lprc,
+ String,
+ Count,
+ (const INT *)Dx)) goto fail;
+ goto good;
+ }
+
+ if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
+ {
+ IntLPtoDP(dc, (POINT *)lprc, 2);
+ }
+
+ Start.x = XStart;
+ Start.y = YStart;
+ IntLPtoDP(dc, &Start, 1);
+
+ RealXStart = (Start.x + dc->ptlDCOrig.x) << 6;
+ YStart = Start.y + dc->ptlDCOrig.y;
+
+ SourcePoint.x = 0;
+ SourcePoint.y = 0;
+ MaskRect.left = 0;
+ MaskRect.top = 0;
+ BrushOrigin.x = 0;
+ BrushOrigin.y = 0;
+
+ if ((fuOptions & ETO_OPAQUE) && lprc)
+ {
+ DestRect.left = lprc->left;
+ DestRect.top = lprc->top;
+ DestRect.right = lprc->right;
+ DestRect.bottom = lprc->bottom;
+
+ IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
+
+ DestRect.left += dc->ptlDCOrig.x;
+ DestRect.top += dc->ptlDCOrig.y;
+ DestRect.right += dc->ptlDCOrig.x;
+ DestRect.bottom += dc->ptlDCOrig.y;
+
+ DC_vPrepareDCsForBlit(dc, DestRect, NULL, DestRect);
+
+ if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
+ DC_vUpdateBackgroundBrush(dc);
+
+ IntEngBitBlt(
+ &dc->dclevel.pSurface->SurfObj,
+ NULL,
+ NULL,
+ dc->rosdc.CombinedClip,
+ NULL,
+ &DestRect,
+ &SourcePoint,
+ &SourcePoint,
+ &dc->eboBackground.BrushObject,
+ &BrushOrigin,
+ ROP3_TO_ROP4(PATCOPY));
+ fuOptions &= ~ETO_OPAQUE;
+ DC_vFinishBlit(dc, NULL);
+ }
+ else
+ {
+ if (pdcattr->jBkMode == OPAQUE)
+ {
+ fuOptions |= ETO_OPAQUE;
+ }
+ }
+
+ TextObj = RealizeFontInit(pdcattr->hlfntNew);
+ if (TextObj == NULL)
+ {
+ goto fail;
+ }
+
+ FontObj = TextObj->Font;
+ ASSERT(FontObj);
+ FontGDI = ObjToGDI(FontObj, FONT);
+ ASSERT(FontGDI);
+
+ IntLockFreeType;
+ face = FontGDI->face;
+ if (face->charmap == NULL)
+ {
+ DPRINT("WARNING: No charmap selected!\n");
+ DPRINT("This font face has %d charmaps\n", face->num_charmaps);
+
+ for (n = 0; n < face->num_charmaps; n++)
+ {
+ charmap = face->charmaps[n];
+ DPRINT("found charmap encoding: %u\n", charmap->encoding);
+ if (charmap->encoding != 0)
+ {
+ found = charmap;
+ break;
+ }
+ }
+ if (!found)
+ {
+ DPRINT1("WARNING: Could not find desired charmap!\n");
+ }
+ error = FT_Set_Charmap(face, found);
+ if (error)
+ {
+ DPRINT1("WARNING: Could not set the charmap!\n");
+ }
+ }
+
+ Render = IntIsFontRenderingEnabled();
+ if (Render)
+ RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
+ else
+ RenderMode = FT_RENDER_MODE_MONO;
+
+ error = FT_Set_Pixel_Sizes(
+ face,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
+ /* FIXME should set character height if neg */
+ (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
+ - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
+ if (error)
+ {
+ DPRINT1("Error in setting pixel sizes: %u\n", error);
+ IntUnLockFreeType;
+ goto fail;
+ }
+
+ /*
+ * Process the vertical alignment and determine the yoff.
+ */
+
+ if (pdcattr->lTextAlign & TA_BASELINE)
+ yoff = 0;
+ else if (pdcattr->lTextAlign & TA_BOTTOM)
+ yoff = -face->size->metrics.descender >> 6;
+ else /* TA_TOP */
+ yoff = face->size->metrics.ascender >> 6;
+
+ use_kerning = FT_HAS_KERNING(face);
+ previous = 0;
+
+ /*
+ * Process the horizontal alignment and modify XStart accordingly.
+ */
+
+ if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
+ {
+ ULONGLONG TextWidth = 0;
+ LPCWSTR TempText = String;
+ int Start;
+
+ /*
+ * Calculate width of the text.
+ */
+
+ if (NULL != Dx)
+ {
+ Start = Count < 2 ? 0 : Count - 2;
+ TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
+ }
+ else
+ {
+ Start = 0;
+ }
+ TempText = String + Start;
+
+ for (i = Start; i < Count; i++)
+ {
+ if (fuOptions & ETO_GLYPH_INDEX)
+ glyph_index = *TempText;
+ else
+ glyph_index = FT_Get_Char_Index(face, *TempText);
+
+ if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
+ {
+ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+ if (error)
+ {
+ DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
+ }
+
+ glyph = face->glyph;
+ realglyph = ftGdiGlyphCacheSet(face, glyph_index,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);
+ if (!realglyph)
+ {
+ DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
+ IntUnLockFreeType;
+ goto fail;
+ }
+
+ }
+ /* retrieve kerning distance */
+ if (use_kerning && previous && glyph_index)
+ {
+ FT_Vector delta;
+ FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
+ TextWidth += delta.x;
+ }
+
+ TextWidth += realglyph->root.advance.x >> 10;
+
+ previous = glyph_index;
+ TempText++;
+ }
+
+ previous = 0;
+
+ if (pdcattr->lTextAlign & TA_RIGHT)
+ {
+ RealXStart -= TextWidth;
+ }
+ else
+ {
+ RealXStart -= TextWidth / 2;
+ }
+ }
+
+ TextLeft = RealXStart;
+ TextTop = YStart;
+ BackgroundLeft = (RealXStart + 32) >> 6;
+
+ /* Lock blit with a dummy rect */
+ DC_vPrepareDCsForBlit(dc, DummyRect, NULL, DummyRect);
+
+ psurf = dc->dclevel.pSurface ;
+ SurfObj = &psurf->SurfObj ;
+
+ /* Create the xlateobj */
+ if (psurf->ppal)
+ {
+ ppalDst = psurf->ppal;
+ GDIOBJ_IncrementShareCount(&ppalDst->BaseObject);
+ }
+ else
+ // Destination palette obtained from the hDC
+ ppalDst = PALETTE_ShareLockPalette(dc->ppdev->devinfo.hpalDefault);
+ ASSERT(ppalDst);
+ EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, ppalDst, 0, 0, 0);
+ EXLATEOBJ_vInitialize(&exloDst2RGB, ppalDst, &gpalRGB, 0, 0, 0);
+ PALETTE_ShareUnlockPalette(ppalDst);
+
+ if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
+ DC_vUpdateBackgroundBrush(dc) ;
+
+ if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
+ DC_vUpdateTextBrush(dc) ;
+
+ /*
+ * The main rendering loop.
+ */
+ for (i = 0; i < Count; i++)
+ {
+ if (fuOptions & ETO_GLYPH_INDEX)
+ glyph_index = *String;
+ else
+ glyph_index = FT_Get_Char_Index(face, *String);
+
+ if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
+ {
+ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+ if (error)
+ {
+ DPRINT1("Failed to load and render glyph! [index: %u]\n", glyph_index);
+ IntUnLockFreeType;
+ goto fail2;
+ }
+ glyph = face->glyph;
+ realglyph = ftGdiGlyphCacheSet(face,
+ glyph_index,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
+ glyph,
+ RenderMode);
+ if (!realglyph)
+ {
+ DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
+ IntUnLockFreeType;
+ goto fail2;
+ }
+ }
+
+ /* retrieve kerning distance and move pen position */
+ if (use_kerning && previous && glyph_index && NULL == Dx)
+ {
+ FT_Vector delta;
+ FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
+ TextLeft += delta.x;
+ }
+ DPRINT("TextLeft: %d\n", TextLeft);
+ DPRINT("TextTop: %d\n", TextTop);
+ DPRINT("Advance: %d\n", realglyph->root.advance.x);
+
+ if (fuOptions & ETO_OPAQUE)
+ {
+ DestRect.left = BackgroundLeft;
+ DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
+ DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6);
+ DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6);
+ MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
+ IntEngBitBlt(
+ &psurf->SurfObj,
+ NULL,
+ NULL,
+ dc->rosdc.CombinedClip,
+ NULL,
+ &DestRect,
+ &SourcePoint,
+ &SourcePoint,
+ &dc->eboBackground.BrushObject,
+ &BrushOrigin,
+ ROP3_TO_ROP4(PATCOPY));
+ MouseSafetyOnDrawEnd(dc->ppdev);
+ BackgroundLeft = DestRect.right;
+
+ }
+
+ DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
+ DestRect.right = DestRect.left + realglyph->bitmap.width;
+ DestRect.top = TextTop + yoff - realglyph->top;
+ DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
+
+ bitSize.cx = realglyph->bitmap.width;
+ bitSize.cy = realglyph->bitmap.rows;
+ MaskRect.right = realglyph->bitmap.width;
+ MaskRect.bottom = realglyph->bitmap.rows;
+
+ /*
+ * We should create the bitmap out of the loop at the biggest possible
+ * glyph size. Then use memset with 0 to clear it and sourcerect to
+ * limit the work of the transbitblt.
+ */
+
+ HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
+ BMF_8BPP, BMF_TOPDOWN,
+ realglyph->bitmap.buffer);
+ if ( !HSourceGlyph )
+ {
+ DPRINT1("WARNING: EngLockSurface() failed!\n");
+ // FT_Done_Glyph(realglyph);
+ IntUnLockFreeType;
+ goto fail2;
+ }
+ SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
+ if ( !SourceGlyphSurf )
+ {
+ EngDeleteSurface((HSURF)HSourceGlyph);
+ DPRINT1("WARNING: EngLockSurface() failed!\n");
+ IntUnLockFreeType;
+ goto fail2;
+ }
+
+ /*
+ * Use the font data as a mask to paint onto the DCs surface using a
+ * brush.
+ */
+
+ if (lprc &&
+ (fuOptions & ETO_CLIPPED) &&
+ DestRect.right >= lprc->right + dc->ptlDCOrig.x)
+ {
+ // We do the check '>=' instead of '>' to possibly save an iteration
+ // through this loop, since it's breaking after the drawing is done,
+ // and x is always incremented.
+ DestRect.right = lprc->right + dc->ptlDCOrig.x;
+ DoBreak = TRUE;
+ }
+ MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
+ IntEngMaskBlt(
+ SurfObj,
+ SourceGlyphSurf,
+ dc->rosdc.CombinedClip,
+ &exloRGB2Dst.xlo,
+ &exloDst2RGB.xlo,
+ &DestRect,
+ (PPOINTL)&MaskRect,
+ &dc->eboText.BrushObject,
+ &BrushOrigin);
+ MouseSafetyOnDrawEnd(dc->ppdev) ;
+
+ EngUnlockSurface(SourceGlyphSurf);
+ EngDeleteSurface((HSURF)HSourceGlyph);
+
+ if (DoBreak)
+ {
+ break;
+ }
+
+ if (NULL == Dx)
+ {
+ TextLeft += realglyph->root.advance.x >> 10;
+ DPRINT("new TextLeft: %d\n", TextLeft);
+ }
+ else
+ {
+ TextLeft += Dx[i<<DxShift] << 6;
+ DPRINT("new TextLeft2: %d\n", TextLeft);
+ }
+
+ if (DxShift)
+ {
+ TextTop -= Dx[2 * i + 1] << 6;
+ }
+
+ previous = glyph_index;
+
+ String++;
+ }
+ IntUnLockFreeType;
+
+ DC_vFinishBlit(dc, NULL) ;
+ EXLATEOBJ_vCleanup(&exloRGB2Dst);
+ EXLATEOBJ_vCleanup(&exloDst2RGB);
+ if (TextObj != NULL)
+ TEXTOBJ_UnlockText(TextObj);
+good:
+ DC_UnlockDc( dc );
+
+ return TRUE;
+
+fail2:
+ EXLATEOBJ_vCleanup(&exloRGB2Dst);
+ EXLATEOBJ_vCleanup(&exloDst2RGB);
+fail:
+ if (TextObj != NULL)
+ TEXTOBJ_UnlockText(TextObj);
+
+ DC_UnlockDc(dc);
+
+ return FALSE;
+}
+
+#define STACK_TEXT_BUFFER_SIZE 100
+BOOL
+APIENTRY
+NtGdiExtTextOutW(
+ IN HDC hDC,
+ IN INT XStart,
+ IN INT YStart,
+ IN UINT fuOptions,
+ IN OPTIONAL LPRECT UnsafeRect,
+ IN LPWSTR UnsafeString,
+ IN INT Count,
+ IN OPTIONAL LPINT UnsafeDx,
+ IN DWORD dwCodePage)
+{
+ BOOL Result = FALSE;
+ NTSTATUS Status = STATUS_SUCCESS;
+ RECTL SafeRect;
+ BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
+ PVOID Buffer = LocalBuffer;
+ LPWSTR SafeString = NULL;
+ LPINT SafeDx = NULL;
+ ULONG BufSize, StringSize, DxSize = 0;
+
+ /* Check if String is valid */
+ if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ if (Count > 0)
+ {
+ /* Calculate buffer size for string and Dx values */
+ BufSize = StringSize = Count * sizeof(WCHAR);
+ if (UnsafeDx)
+ {
+ /* If ETO_PDY is specified, we have pairs of INTs */
+ DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
+ BufSize += DxSize;
+ }
+
+ /* Check if our local buffer is large enough */
+ if (BufSize > STACK_TEXT_BUFFER_SIZE)
+ {
+ /* It's not, allocate a temp buffer */
+ Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, TAG_GDITEXT);
+ if (!Buffer)
+ {
+ return FALSE;
+ }
+ }
+
+ /* Probe and copy user mode data to the buffer */
+ _SEH2_TRY
+ {
+ /* Put the Dx before the String to assure alignment of 4 */
+ SafeString = (LPWSTR)(((ULONG_PTR)Buffer) + DxSize);
+
+ /* Probe and copy the string */
+ ProbeForRead(UnsafeString, StringSize, 1);
+ memcpy((PVOID)SafeString, UnsafeString, StringSize);
+
+ /* If we have Dx values... */
+ if (UnsafeDx)
+ {
+ /* ... probe and copy them */
+ SafeDx = Buffer;
+ ProbeForRead(UnsafeDx, DxSize, 1);
+ memcpy(SafeDx, UnsafeDx, DxSize);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+ if (!NT_SUCCESS(Status))
+ {
+ goto cleanup;
+ }
+ }
+
+ /* If we have a rect, copy it */
+ if (UnsafeRect)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead(UnsafeRect, sizeof(RECT), 1);
+ SafeRect = *UnsafeRect;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+ if (!NT_SUCCESS(Status))
+ {
+ goto cleanup;
+ }
+ }
+
+ /* Finally call the internal routine */
+ Result = GreExtTextOutW(hDC,
+ XStart,
+ YStart,
+ fuOptions,
+ &SafeRect,
+ SafeString,
+ Count,
+ SafeDx,
+ dwCodePage);
+
+cleanup:
+ /* If we allocated a buffer, free it */
+ if (Buffer != LocalBuffer)
+ {
+ ExFreePoolWithTag(Buffer, TAG_GDITEXT);
+ }
+
+ return Result;
+}
+
+
+/*
+* @implemented
+*/
+BOOL
+APIENTRY
+NtGdiGetCharABCWidthsW(
+ IN HDC hDC,
+ IN UINT FirstChar,
+ IN ULONG Count,
+ IN OPTIONAL PWCHAR pwch,
+ IN FLONG fl,
+ OUT PVOID Buffer)
+{
+ LPABC SafeBuff;
+ LPABCFLOAT SafeBuffF = NULL;
+ PDC dc;
+ PDC_ATTR pdcattr;
+ PTEXTOBJ TextObj;
+ PFONTGDI FontGDI;
+ FT_Face face;
+ FT_CharMap charmap, found = NULL;
+ UINT i, glyph_index, BufferSize;
+ HFONT hFont = 0;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (pwch)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead(pwch,
+ sizeof(PWSTR),
+ 1);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastWin32Error(Status);
+ return FALSE;
+ }
+
+ if (!Buffer)
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ BufferSize = Count * sizeof(ABC); // Same size!
+ SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
+ if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
+ if (SafeBuff == NULL)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ dc = DC_LockDc(hDC);
+ if (dc == NULL)
+ {
+ ExFreePool(SafeBuff);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ pdcattr = dc->pdcattr;
+ hFont = pdcattr->hlfntNew;
+ TextObj = RealizeFontInit(hFont);
+ DC_UnlockDc(dc);
+
+ if (TextObj == NULL)
+ {
+ ExFreePool(SafeBuff);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ FontGDI = ObjToGDI(TextObj->Font, FONT);
+
+ face = FontGDI->face;
+ if (face->charmap == NULL)
+ {
+ for (i = 0; i < face->num_charmaps; i++)
+ {
+ charmap = face->charmaps[i];
+ if (charmap->encoding != 0)
+ {
+ found = charmap;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ DPRINT1("WARNING: Could not find desired charmap!\n");
+ ExFreePool(SafeBuff);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ IntLockFreeType;
+ FT_Set_Charmap(face, found);
+ IntUnLockFreeType;
+ }
+
+ IntLockFreeType;
+ FT_Set_Pixel_Sizes(face,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
+ /* FIXME should set character height if neg */
+ (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
+
+ for (i = FirstChar; i < FirstChar+Count; i++)
+ {
+ int adv, lsb, bbx, left, right;
+
+ if (pwch)
+ {
+ if (fl & GCABCW_INDICES)
+ glyph_index = pwch[i - FirstChar];
+ else
+ glyph_index = FT_Get_Char_Index(face, pwch[i - FirstChar]);
+ }
+ else
+ {
+ if (fl & GCABCW_INDICES)
+ glyph_index = i;
+ else
+ glyph_index = FT_Get_Char_Index(face, i);
+ }
+ FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+
+ left = (INT)face->glyph->metrics.horiBearingX & -64;
+ right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
+ adv = (face->glyph->advance.x + 32) >> 6;
+
+// int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
+// DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same!*/
+
+ lsb = left >> 6;
+ bbx = (right - left) >> 6;
+ /*
+ DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
+ */
+ if (!fl)
+ {
+ SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
+ SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
+ SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
+ }
+ else
+ {
+ SafeBuff[i - FirstChar].abcA = lsb;
+ SafeBuff[i - FirstChar].abcB = bbx;
+ SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
+ }
+ }
+ IntUnLockFreeType;
+ TEXTOBJ_UnlockText(TextObj);
+ Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
+ if (! NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ ExFreePool(SafeBuff);
+ return FALSE;
+ }
+ ExFreePool(SafeBuff);
+ DPRINT("NtGdiGetCharABCWidths Worked!\n");
+ return TRUE;
+}
+
+/*
+* @implemented
+*/
+BOOL
+APIENTRY
+NtGdiGetCharWidthW(
+ IN HDC hDC,
+ IN UINT FirstChar,
+ IN UINT Count,
+ IN OPTIONAL PWCHAR pwc,
+ IN FLONG fl,
+ OUT PVOID Buffer)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ LPINT SafeBuff;
+ PFLOAT SafeBuffF = NULL;
+ PDC dc;
+ PDC_ATTR pdcattr;
+ PTEXTOBJ TextObj;
+ PFONTGDI FontGDI;
+ FT_Face face;
+ FT_CharMap charmap, found = NULL;
+ UINT i, glyph_index, BufferSize;
+ HFONT hFont = 0;
+
+ if (pwc)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead(pwc,
+ sizeof(PWSTR),
+ 1);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastWin32Error(Status);
+ return FALSE;
+ }
+
+ BufferSize = Count * sizeof(INT); // Same size!
+ SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
+ if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
+ if (SafeBuff == NULL)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ dc = DC_LockDc(hDC);
+ if (dc == NULL)
+ {
+ ExFreePool(SafeBuff);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ pdcattr = dc->pdcattr;
+ hFont = pdcattr->hlfntNew;
+ TextObj = RealizeFontInit(hFont);
+ DC_UnlockDc(dc);
+
+ if (TextObj == NULL)
+ {
+ ExFreePool(SafeBuff);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ FontGDI = ObjToGDI(TextObj->Font, FONT);
+
+ face = FontGDI->face;
+ if (face->charmap == NULL)
+ {
+ for (i = 0; i < face->num_charmaps; i++)
+ {
+ charmap = face->charmaps[i];
+ if (charmap->encoding != 0)
+ {
+ found = charmap;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ DPRINT1("WARNING: Could not find desired charmap!\n");
+ ExFreePool(SafeBuff);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ IntLockFreeType;
+ FT_Set_Charmap(face, found);
+ IntUnLockFreeType;
+ }
+
+ IntLockFreeType;
+ FT_Set_Pixel_Sizes(face,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
+ /* FIXME should set character height if neg */
+ (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
+ - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
+
+ for (i = FirstChar; i < FirstChar+Count; i++)
+ {
+ if (pwc)
+ {
+ if (fl & GCW_INDICES)
+ glyph_index = pwc[i - FirstChar];
+ else
+ glyph_index = FT_Get_Char_Index(face, pwc[i - FirstChar]);
+ }
+ else
+ {
+ if (fl & GCW_INDICES)
+ glyph_index = i;
+ else
+ glyph_index = FT_Get_Char_Index(face, i);
+ }
+ FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+ if (!fl)
+ SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
+ else
+ SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
+ }
+ IntUnLockFreeType;
+ TEXTOBJ_UnlockText(TextObj);
+ MmCopyToCaller(Buffer, SafeBuff, BufferSize);
+ ExFreePool(SafeBuff);
+ return TRUE;
+}
+
+DWORD
+FASTCALL
+GreGetGlyphIndicesW(
+ HDC hdc,
+ LPWSTR pwc,
+ INT cwc,
+ LPWORD pgi,
+ DWORD iMode,
+ DWORD Unknown)
+{
+ PDC dc;
+ PDC_ATTR pdcattr;
+ PTEXTOBJ TextObj;
+ PFONTGDI FontGDI;
+ HFONT hFont = 0;
+ OUTLINETEXTMETRICW *potm;
+ INT i;
+ FT_Face face;
+ WCHAR DefChar = 0xffff;
+ PWSTR Buffer = NULL;
+ ULONG Size;
+
+ if ((!pwc) && (!pgi)) return cwc;
+
+ dc = DC_LockDc(hdc);
+ if (!dc)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return GDI_ERROR;
+ }
+ pdcattr = dc->pdcattr;
+ hFont = pdcattr->hlfntNew;
+ TextObj = RealizeFontInit(hFont);
+ DC_UnlockDc(dc);
+ if (!TextObj)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return GDI_ERROR;
+ }
+
+ FontGDI = ObjToGDI(TextObj->Font, FONT);
+ TEXTOBJ_UnlockText(TextObj);
+
+ Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), TAG_GDITEXT);
+ if (!Buffer)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return GDI_ERROR;
+ }
+
+ if (iMode & GGI_MARK_NONEXISTING_GLYPHS) DefChar = 0x001f; /* Indicate non existence */
+ else
+ {
+ Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
+ potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
+ if (!potm)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ cwc = GDI_ERROR;
+ goto ErrorRet;
+ }
+ IntGetOutlineTextMetrics(FontGDI, Size, potm);
+ DefChar = potm->otmTextMetrics.tmDefaultChar; // May need this.
+ ExFreePool(potm);
+ }
+
+ IntLockFreeType;
+ face = FontGDI->face;
+
+ for (i = 0; i < cwc; i++)
+ {
+ Buffer[i] = FT_Get_Char_Index(face, pwc[i]);
+ if (Buffer[i] == 0)
+ {
+ if (DefChar == 0xffff && FT_IS_SFNT(face))
+ {
+ TT_OS2 *pOS2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
+ DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(face, pOS2->usDefaultChar) : 0);
+ }
+ Buffer[i] = DefChar;
+ }
+ }
+
+ IntUnLockFreeType;
+
+ RtlCopyMemory( pgi, Buffer, cwc*sizeof(WORD));
+
+ErrorRet:
+ if (Buffer) ExFreePoolWithTag(Buffer, TAG_GDITEXT);
+ return cwc;
+}
+
+
+/*
+* @implemented
+*/
+DWORD
+APIENTRY
+NtGdiGetGlyphIndicesW(
+ IN HDC hdc,
+ IN OPTIONAL LPWSTR UnSafepwc,
+ IN INT cwc,
+ OUT OPTIONAL LPWORD UnSafepgi,
+ IN DWORD iMode)
+{
+ PDC dc;
+ PDC_ATTR pdcattr;
+ PTEXTOBJ TextObj;
+ PFONTGDI FontGDI;
+ HFONT hFont = 0;
+ NTSTATUS Status = STATUS_SUCCESS;
+ OUTLINETEXTMETRICW *potm;
+ INT i;
+ FT_Face face;
+ WCHAR DefChar = 0xffff;
+ PWSTR Buffer = NULL;
+ ULONG Size;
+
+ if ((!UnSafepwc) && (!UnSafepgi)) return cwc;
+
+ dc = DC_LockDc(hdc);
+ if (!dc)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return GDI_ERROR;
+ }
+ pdcattr = dc->pdcattr;
+ hFont = pdcattr->hlfntNew;
+ TextObj = RealizeFontInit(hFont);
+ DC_UnlockDc(dc);
+ if (!TextObj)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return GDI_ERROR;
+ }
+
+ FontGDI = ObjToGDI(TextObj->Font, FONT);
+ TEXTOBJ_UnlockText(TextObj);
+
+ Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), TAG_GDITEXT);
+ if (!Buffer)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return GDI_ERROR;
+ }
+
+ if (iMode & GGI_MARK_NONEXISTING_GLYPHS) DefChar = 0x001f; /* Indicate non existence */
+ else
+ {
+ Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
+ potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
+ if (!potm)
+ {
+ Status = ERROR_NOT_ENOUGH_MEMORY;
+ goto ErrorRet;
+ }
+ IntGetOutlineTextMetrics(FontGDI, Size, potm);
+ DefChar = potm->otmTextMetrics.tmDefaultChar; // May need this.
+ ExFreePool(potm);
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForRead(UnSafepwc,
+ sizeof(PWSTR),
+ 1);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ if (!NT_SUCCESS(Status)) goto ErrorRet;
+
+ IntLockFreeType;
+ face = FontGDI->face;
+
+ for (i = 0; i < cwc; i++)
+ {
+ Buffer[i] = FT_Get_Char_Index(face, UnSafepwc[i]);
+ if (Buffer[i] == 0)
+ {
+ if (DefChar == 0xffff && FT_IS_SFNT(face))
+ {
+ TT_OS2 *pOS2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
+ DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(face, pOS2->usDefaultChar) : 0);
+ }
+ Buffer[i] = DefChar;
+ }
+ }
+
+ IntUnLockFreeType;
+
+ _SEH2_TRY
+ {
+ ProbeForWrite(UnSafepgi,
+ sizeof(WORD),
+ 1);
+ RtlCopyMemory(UnSafepgi,
+ Buffer,
+ cwc*sizeof(WORD));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ErrorRet:
+ ExFreePoolWithTag(Buffer, TAG_GDITEXT);
+ if (NT_SUCCESS(Status)) return cwc;
+ SetLastWin32Error(Status);
+ return GDI_ERROR;
+}
+
+
+/* EOF */
--- /dev/null
- ProcessId = PsGetProcessId(NewOwner);
-
+/*
+ * PROJECT: ReactOS win32 kernel mode subsystem
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: subsystems/win32/win32k/objects/gdiobj.c
+ * PURPOSE: General GDI object manipulation routines
+ * PROGRAMMERS: ...
+ */
+
+/** INCLUDES ******************************************************************/
+
+#define GDI_DEBUG
+
+#include <win32k.h>
+#define NDEBUG
+#include <debug.h>
+
+#define GDI_ENTRY_TO_INDEX(ht, e) \
+ (((ULONG_PTR)(e) - (ULONG_PTR)&((ht)->Entries[0])) / sizeof(GDI_TABLE_ENTRY))
+#define GDI_HANDLE_GET_ENTRY(HandleTable, h) \
+ (&(HandleTable)->Entries[GDI_HANDLE_GET_INDEX((h))])
+
+/* apparently the first 10 entries are never used in windows as they are empty */
+#define RESERVE_ENTRIES_COUNT 10
+
+#define BASE_OBJTYPE_COUNT 32
+
+#define DelayExecution() \
+ DPRINT("%s:%i: Delay\n", __FILE__, __LINE__); \
+ KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay)
+
+#include "gdidbg.c"
+
+static
+BOOL INTERNAL_CALL GDI_CleanupDummy(PVOID ObjectBody);
+
+/** GLOBALS *******************************************************************/
+
+typedef struct
+{
+ BOOL bUseLookaside;
+ ULONG_PTR ulBodySize;
+ ULONG Tag;
+ GDICLEANUPPROC CleanupProc;
+} OBJ_TYPE_INFO, *POBJ_TYPE_INFO;
+
+static const
+OBJ_TYPE_INFO ObjTypeInfo[BASE_OBJTYPE_COUNT] =
+{
+ {0, 0, 0, NULL}, /* 00 reserved entry */
+ {1, sizeof(DC), TAG_DC, DC_Cleanup}, /* 01 DC */
+ {1, 0, 0, NULL}, /* 02 UNUSED1 */
+ {1, 0, 0, NULL}, /* 03 UNUSED2 */
+ {1, sizeof(ROSRGNDATA), TAG_REGION, REGION_Cleanup}, /* 04 RGN */
+ {1, sizeof(SURFACE), TAG_SURFACE, SURFACE_Cleanup}, /* 05 SURFACE */
+ {1, sizeof(CLIENTOBJ), TAG_CLIENTOBJ, GDI_CleanupDummy}, /* 06 CLIENTOBJ: METADC,... */
+ {1, sizeof(PATH), TAG_PATH, GDI_CleanupDummy}, /* 07 PATH */
+ {1, sizeof(PALETTE), TAG_PALETTE, PALETTE_Cleanup}, /* 08 PAL */
+ {1, sizeof(COLORSPACE), TAG_ICMLCS, GDI_CleanupDummy}, /* 09 ICMLCS, */
+ {1, sizeof(TEXTOBJ), TAG_LFONT, GDI_CleanupDummy}, /* 0a LFONT */
+ {0, 0, TAG_RFONT, NULL}, /* 0b RFONT, unused */
+ {0, 0, TAG_PFE, NULL}, /* 0c PFE, unused */
+ {0, 0, TAG_PFT, NULL}, /* 0d PFT, unused */
+ {0, sizeof(GDICLRXFORM), TAG_ICMCXF, GDI_CleanupDummy}, /* 0e ICMCXF, */
+ {0, 0, TAG_SPRITE, NULL}, /* 0f SPRITE, unused */
+ {1, sizeof(BRUSH), TAG_BRUSH, BRUSH_Cleanup}, /* 10 BRUSH, PEN, EXTPEN */
+ {0, 0, TAG_UMPD, NULL}, /* 11 UMPD, unused */
+ {0, 0, 0, NULL}, /* 12 UNUSED4 */
+ {0, 0, TAG_SPACE, NULL}, /* 13 SPACE, unused */
+ {0, 0, 0, NULL}, /* 14 UNUSED5 */
+ {0, 0, TAG_META, NULL}, /* 15 META, unused */
+ {0, 0, TAG_EFSTATE, NULL}, /* 16 EFSTATE, unused */
+ {0, 0, TAG_BMFD, NULL}, /* 17 BMFD, unused */
+ {0, 0, TAG_VTFD, NULL}, /* 18 VTFD, unused */
+ {0, 0, TAG_TTFD, NULL}, /* 19 TTFD, unused */
+ {0, 0, TAG_RC, NULL}, /* 1a RC, unused */
+ {0, 0, TAG_TEMP, NULL}, /* 1b TEMP, unused */
+ {0, sizeof(EDRIVEROBJ), TAG_DRVOBJ, DRIVEROBJ_Cleanup},/* 1c DRVOBJ */
+ {0, 0, TAG_DCIOBJ, NULL}, /* 1d DCIOBJ, unused */
+ {0, 0, TAG_SPOOL, NULL}, /* 1e SPOOL, unused */
+ {0, 0, 0, NULL}, /* 1f reserved entry */
+};
+
+static LARGE_INTEGER ShortDelay;
+
+/** INTERNAL FUNCTIONS ********************************************************/
+
+// Audit Functions
+int tDC = 0;
+int tBRUSH = 0;
+int tBITMAP = 0;
+int tFONT = 0;
+int tRGN = 0;
+
+VOID
+AllocTypeDataDump(INT TypeInfo)
+{
+ switch( TypeInfo & GDI_HANDLE_TYPE_MASK )
+ {
+ case GDILoObjType_LO_BRUSH_TYPE:
+ tBRUSH++;
+ break;
+ case GDILoObjType_LO_DC_TYPE:
+ tDC++;
+ break;
+ case GDILoObjType_LO_BITMAP_TYPE:
+ tBITMAP++;
+ break;
+ case GDILoObjType_LO_FONT_TYPE:
+ tFONT++;
+ break;
+ case GDILoObjType_LO_REGION_TYPE:
+ tRGN++;
+ break;
+ }
+}
+
+VOID
+DeAllocTypeDataDump(INT TypeInfo)
+{
+ switch( TypeInfo & GDI_HANDLE_TYPE_MASK )
+ {
+ case GDILoObjType_LO_BRUSH_TYPE:
+ tBRUSH--;
+ break;
+ case GDILoObjType_LO_DC_TYPE:
+ tDC--;
+ break;
+ case GDILoObjType_LO_BITMAP_TYPE:
+ tBITMAP--;
+ break;
+ case GDILoObjType_LO_FONT_TYPE:
+ tFONT--;
+ break;
+ case GDILoObjType_LO_REGION_TYPE:
+ tRGN--;
+ break;
+ }
+}
+
+/*
+ * Dummy GDI Cleanup Callback
+ */
+static
+BOOL INTERNAL_CALL
+GDI_CleanupDummy(PVOID ObjectBody)
+{
+ return TRUE;
+}
+
+/*!
+ * Allocate GDI object table.
+ * \param Size - number of entries in the object table.
+*/
+PGDI_HANDLE_TABLE INTERNAL_CALL
+GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject)
+{
+ PGDI_HANDLE_TABLE HandleTable = NULL;
+ LARGE_INTEGER htSize;
+ UINT ObjType;
+ ULONG ViewSize = 0;
+ NTSTATUS Status;
+
+ ASSERT(SectionObject != NULL);
+
+ htSize.QuadPart = sizeof(GDI_HANDLE_TABLE);
+
+ Status = MmCreateSection((PVOID*)SectionObject,
+ SECTION_ALL_ACCESS,
+ NULL,
+ &htSize,
+ PAGE_READWRITE,
+ SEC_COMMIT,
+ NULL,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ return NULL;
+
+ /* FIXME - use MmMapViewInSessionSpace once available! */
+ Status = MmMapViewInSystemSpace(*SectionObject,
+ (PVOID*)&HandleTable,
+ &ViewSize);
+ if (!NT_SUCCESS(Status))
+ {
+ ObDereferenceObject(*SectionObject);
+ *SectionObject = NULL;
+ return NULL;
+ }
+
+ RtlZeroMemory(HandleTable, sizeof(GDI_HANDLE_TABLE));
+
+ HandleTable->LookasideLists = ExAllocatePoolWithTag(NonPagedPool,
+ BASE_OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST),
+ TAG_GDIHNDTBLE);
+ if (HandleTable->LookasideLists == NULL)
+ {
+ MmUnmapViewInSystemSpace(HandleTable);
+ ObDereferenceObject(*SectionObject);
+ *SectionObject = NULL;
+ return NULL;
+ }
+
+ for (ObjType = 0; ObjType < BASE_OBJTYPE_COUNT; ObjType++)
+ {
+ if (ObjTypeInfo[ObjType].bUseLookaside)
+ {
+ ExInitializePagedLookasideList(HandleTable->LookasideLists + ObjType,
+ NULL,
+ NULL,
+ 0,
+ ObjTypeInfo[ObjType].ulBodySize,
+ ObjTypeInfo[ObjType].Tag,
+ 0);
+ }
+ }
+
+ ShortDelay.QuadPart = -5000LL; /* FIXME - 0.5 ms? */
+
+ HandleTable->FirstFree = 0;
+ HandleTable->FirstUnused = RESERVE_ENTRIES_COUNT;
+
+ return HandleTable;
+}
+
+static void FASTCALL
+LockErrorDebugOutput(HGDIOBJ hObj, PGDI_TABLE_ENTRY Entry, LPSTR Function)
+{
+ if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) == 0)
+ {
+ DPRINT1("%s: Attempted to lock object 0x%x that is deleted!\n", Function, hObj);
+ GDIDBG_TRACEDELETER(hObj);
+ }
+ else if (GDI_HANDLE_GET_REUSECNT(hObj) != GDI_ENTRY_GET_REUSECNT(Entry->Type))
+ {
+ DPRINT1("%s: Attempted to lock object 0x%x, wrong reuse counter (Handle: 0x%x, Entry: 0x%x)\n",
+ Function, hObj, GDI_HANDLE_GET_REUSECNT(hObj), GDI_ENTRY_GET_REUSECNT(Entry->Type));
+ }
+ else if (GDI_HANDLE_GET_TYPE(hObj) != ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK))
+ {
+ DPRINT1("%s: Attempted to lock object 0x%x, type mismatch (Handle: 0x%x, Entry: 0x%x)\n",
+ Function, hObj, GDI_HANDLE_GET_TYPE(hObj), (Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK);
+ }
+ else
+ {
+ DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n",
+ Function, hObj, Entry->Type);
+ }
+ GDIDBG_TRACECALLER();
+}
+
+ULONG
+FASTCALL
+InterlockedPopFreeEntry(VOID)
+{
+ ULONG idxFirst, idxNext, idxPrev;
+ PGDI_TABLE_ENTRY pEntry;
+ DWORD PrevProcId;
+
+ DPRINT("Enter InterLockedPopFreeEntry\n");
+
+ while (TRUE)
+ {
+ idxFirst = GdiHandleTable->FirstFree;
+
+ if (!idxFirst)
+ {
+ /* Increment FirstUnused and get the new index */
+ idxFirst = InterlockedIncrement((LONG*)&GdiHandleTable->FirstUnused) - 1;
+
+ /* Check if we have entries left */
+ if (idxFirst >= GDI_HANDLE_COUNT)
+ {
+ DPRINT1("No more gdi handles left!\n");
+ return 0;
+ }
+
+ /* Return the old index */
+ return idxFirst;
+ }
+
+ /* Get a pointer to the first free entry */
+ pEntry = GdiHandleTable->Entries + idxFirst;
+
+ /* Try to lock the entry */
+ PrevProcId = InterlockedCompareExchange((LONG*)&pEntry->ProcessId, 1, 0);
+ if (PrevProcId != 0)
+ {
+ /* The entry was locked or not free, wait and start over */
+ DelayExecution();
+ continue;
+ }
+
+ /* Sanity check: is entry really free? */
+ ASSERT(((ULONG_PTR)pEntry->KernelData & ~GDI_HANDLE_INDEX_MASK) == 0);
+
+ /* Try to exchange the FirstFree value */
+ idxNext = (ULONG_PTR)pEntry->KernelData;
+ idxPrev = InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree,
+ idxNext,
+ idxFirst);
+
+ /* Unlock the free entry */
+ (void)InterlockedExchange((LONG*)&pEntry->ProcessId, 0);
+
+ /* If we succeeded, break out of the loop */
+ if (idxPrev == idxFirst)
+ {
+ break;
+ }
+ }
+
+ return idxFirst;
+}
+
+/* Pushes an entry of the handle table to the free list,
+ The entry must be unlocked and the base type field must be 0 */
+VOID
+FASTCALL
+InterlockedPushFreeEntry(ULONG idxToFree)
+{
+ ULONG idxFirstFree, idxPrev;
+ PGDI_TABLE_ENTRY pFreeEntry;
+
+ DPRINT("Enter InterlockedPushFreeEntry\n");
+
+ pFreeEntry = GdiHandleTable->Entries + idxToFree;
+ ASSERT((pFreeEntry->Type & GDI_ENTRY_BASETYPE_MASK) == 0);
+ ASSERT(pFreeEntry->ProcessId == 0);
+ pFreeEntry->UserData = NULL;
+
+ do
+ {
+ idxFirstFree = GdiHandleTable->FirstFree;
+ pFreeEntry->KernelData = (PVOID)(ULONG_PTR)idxFirstFree;
+
+ idxPrev = InterlockedCompareExchange((LONG*)&GdiHandleTable->FirstFree,
+ idxToFree,
+ idxFirstFree);
+ }
+ while (idxPrev != idxFirstFree);
+}
+
+
+BOOL
+INTERNAL_CALL
+GDIOBJ_ValidateHandle(HGDIOBJ hObj, ULONG ObjectType)
+{
+ PGDI_TABLE_ENTRY Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj);
+ if ((((ULONG_PTR)hObj & GDI_HANDLE_TYPE_MASK) == ObjectType) &&
+ (Entry->Type << GDI_ENTRY_UPPER_SHIFT) == GDI_HANDLE_GET_UPPER(hObj))
+ {
+ HANDLE pid = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1);
+ if (pid == NULL || pid == PsGetCurrentProcessId())
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+POBJ INTERNAL_CALL
+GDIOBJ_AllocObj(UCHAR BaseType)
+{
+ POBJ pObject;
+
+ ASSERT((BaseType & ~GDIObjTypeTotal) == 0);
+// BaseType &= GDI_HANDLE_BASETYPE_MASK;
+
+ if (ObjTypeInfo[BaseType].bUseLookaside)
+ {
+ PPAGED_LOOKASIDE_LIST LookasideList;
+
+ LookasideList = GdiHandleTable->LookasideLists + BaseType;
+ pObject = ExAllocateFromPagedLookasideList(LookasideList);
+ }
+ else
+ {
+ pObject = ExAllocatePoolWithTag(PagedPool,
+ ObjTypeInfo[BaseType].ulBodySize,
+ ObjTypeInfo[BaseType].Tag);
+ }
+
+ if (pObject)
+ {
+ RtlZeroMemory(pObject, ObjTypeInfo[BaseType].ulBodySize);
+ }
+
+ return pObject;
+}
+
+
+/*!
+ * Allocate memory for GDI object and return handle to it.
+ *
+ * \param ObjectType - type of object \ref GDI object types
+ *
+ * \return Pointer to the allocated object, which is locked.
+*/
+POBJ INTERNAL_CALL
+GDIOBJ_AllocObjWithHandle(ULONG ObjectType)
+{
+ PPROCESSINFO W32Process;
+ POBJ newObject = NULL;
+ HANDLE CurrentProcessId, LockedProcessId;
+ UCHAR TypeIndex;
+ UINT Index;
+ PGDI_TABLE_ENTRY Entry;
+ LONG TypeInfo;
+
+ GDIDBG_INITLOOPTRACE();
+
+ W32Process = PsGetCurrentProcessWin32Process();
+ /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
+ to take too many GDI objects, itself. */
+ if (W32Process && W32Process->GDIHandleCount >= 0x2710)
+ {
+ DPRINT1("Too many objects for process!!!\n");
+ DPRINT1("DC %d BRUSH %d BITMAP %d FONT %d RGN %d\n",tDC,tBRUSH,tBITMAP,tFONT,tRGN);
+ GDIDBG_DUMPHANDLETABLE();
+ return NULL;
+ }
+
+ ASSERT(ObjectType != GDI_OBJECT_TYPE_DONTCARE);
+
+ TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(ObjectType);
+
+ newObject = GDIOBJ_AllocObj(TypeIndex);
+ if (!newObject)
+ {
+ DPRINT1("Not enough memory to allocate gdi object!\n");
+ return NULL;
+ }
+
+ CurrentProcessId = PsGetCurrentProcessId();
+ LockedProcessId = (HANDLE)((ULONG_PTR)CurrentProcessId | 0x1);
+
+// RtlZeroMemory(newObject, ObjTypeInfo[TypeIndex].ulBodySize);
+
+ /* On Windows the higher 16 bit of the type field don't contain the
+ full type from the handle, but the base type.
+ (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
+ TypeInfo = (ObjectType & GDI_HANDLE_BASETYPE_MASK) | (ObjectType >> GDI_ENTRY_UPPER_SHIFT);
+
+ Index = InterlockedPopFreeEntry();
+ if (Index != 0)
+ {
+ HANDLE PrevProcId;
+
+ Entry = &GdiHandleTable->Entries[Index];
+
+LockHandle:
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, 0);
+ if (PrevProcId == NULL)
+ {
+ PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
+ HGDIOBJ Handle;
+
+ Entry->KernelData = newObject;
+
+ /* copy the reuse-counter */
+ TypeInfo |= Entry->Type & GDI_ENTRY_REUSE_MASK;
+
+ /* we found a free entry, no need to exchange this field atomically
+ since we're holding the lock */
+ Entry->Type = TypeInfo;
+
+ /* Create a handle */
+ Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo << GDI_ENTRY_UPPER_SHIFT));
+
+ /* Initialize BaseObject fields */
+ newObject->hHmgr = Handle;
+ newObject->ulShareCount = 0;
+ newObject->cExclusiveLock = 1;
+ newObject->Tid = Thread;
+
+ AllocTypeDataDump(TypeInfo);
+
+ /* unlock the entry */
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, CurrentProcessId);
+
+ GDIDBG_CAPTUREALLOCATOR(Index);
+
+ if (W32Process != NULL)
+ {
+ InterlockedIncrement(&W32Process->GDIHandleCount);
+ }
+
+ DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, newObject);
+ return newObject;
+ }
+ else
+ {
+ GDIDBG_TRACELOOP(Index, PrevProcId, CurrentProcessId);
+ /* damn, someone is trying to lock the object even though it doesn't
+ even exist anymore, wait a little and try again!
+ FIXME - we shouldn't loop forever! Give up after some time! */
+ DelayExecution();
+ /* try again */
+ goto LockHandle;
+ }
+ }
+
+ GDIOBJ_FreeObj(newObject, TypeIndex);
+
+ DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
+ GDIDBG_DUMPHANDLETABLE();
+
+ return NULL;
+}
+
+
+VOID INTERNAL_CALL
+GDIOBJ_FreeObj(POBJ pObject, UCHAR BaseType)
+{
+ /* Object must not have a handle! */
+ ASSERT(pObject->hHmgr == NULL);
+
+ if (ObjTypeInfo[BaseType].bUseLookaside)
+ {
+ PPAGED_LOOKASIDE_LIST LookasideList;
+
+ LookasideList = GdiHandleTable->LookasideLists + BaseType;
+ ExFreeToPagedLookasideList(LookasideList, pObject);
+ }
+ else
+ {
+ ExFreePool(pObject);
+ }
+}
+
+/*!
+ * Free memory allocated for the GDI object. For each object type this function calls the
+ * appropriate cleanup routine.
+ *
+ * \param hObj - handle of the object to be deleted.
+ *
+ * \return Returns TRUE if succesful.
+ * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
+ * to the calling process.
+ *
+ * \bug This function should return VOID and kill the object no matter what...
+*/
+BOOL INTERNAL_CALL
+GDIOBJ_FreeObjByHandle(HGDIOBJ hObj, DWORD ExpectedType)
+{
+ PGDI_TABLE_ENTRY Entry;
+ HANDLE ProcessId, LockedProcessId, PrevProcId;
+ ULONG HandleType, HandleUpper, TypeIndex;
+ BOOL Silent;
+
+ GDIDBG_INITLOOPTRACE();
+
+ DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj);
+
+ if (GDI_HANDLE_IS_STOCKOBJ(hObj))
+ {
+ DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj);
+ GDIDBG_TRACECALLER();
+ return FALSE;
+ }
+
+ ProcessId = PsGetCurrentProcessId();
+ LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
+
+ Silent = (ExpectedType & GDI_OBJECT_TYPE_SILENT);
+ ExpectedType &= ~GDI_OBJECT_TYPE_SILENT;
+
+ HandleType = GDI_HANDLE_GET_TYPE(hObj);
+ HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
+
+ /* Check if we have the requested type */
+ if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
+ HandleType != ExpectedType) ||
+ HandleType == 0 )
+ {
+ DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
+ hObj, HandleType, ExpectedType);
+ GDIDBG_TRACECALLER();
+ return FALSE;
+ }
+
+ Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj);
+
+LockHandle:
+ /* lock the object, we must not delete global objects, so don't exchange the locking
+ process ID to zero when attempting to lock a global object... */
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
+ if (PrevProcId == ProcessId)
+ {
+ if ( (Entry->KernelData != NULL) &&
+ ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) &&
+ ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) == (HandleUpper & GDI_ENTRY_BASETYPE_MASK)) )
+ {
+ POBJ Object;
+
+ Object = Entry->KernelData;
+
+ if ((Object->cExclusiveLock == 0 ||
+ Object->Tid == (PTHREADINFO)PsGetCurrentThreadWin32Thread()) &&
+ Object->ulShareCount == 0)
+ {
+ BOOL Ret;
+ PPROCESSINFO W32Process = PsGetCurrentProcessWin32Process();
+
+ /* Clear the basetype field so when unlocking the handle it gets finally deleted and increment reuse counter */
+ Entry->Type = (Entry->Type + GDI_ENTRY_REUSE_INC) & ~GDI_ENTRY_BASETYPE_MASK;
+
+ /* unlock the handle slot */
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, NULL);
+
+ /* push this entry to the free list */
+ InterlockedPushFreeEntry(GDI_ENTRY_TO_INDEX(GdiHandleTable, Entry));
+
+ Object->hHmgr = NULL;
+
+ if (W32Process != NULL)
+ {
+ InterlockedDecrement(&W32Process->GDIHandleCount);
+ }
+
+ /* call the cleanup routine. */
+ TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(HandleType);
+ Ret = ObjTypeInfo[TypeIndex].CleanupProc(Object);
+
+ DeAllocTypeDataDump(HandleType);
+
+ /* Now it's time to free the memory */
+ GDIOBJ_FreeObj(Object, TypeIndex);
+
+ GDIDBG_CAPTUREDELETER(hObj);
+ return Ret;
+ }
+ else if (Object->ulShareCount != 0)
+ {
+ NTSTATUS Status;
+ PEPROCESS OldProcess;
+ Object->BaseFlags |= BASEFLAG_READY_TO_DIE;
+ DPRINT("Object %p, ulShareCount = %d\n", Object->hHmgr, Object->ulShareCount);
+ /* Set NULL owner. Do the work here to avoid race conditions */
+ Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
+ if (NT_SUCCESS(Status))
+ {
+ PPROCESSINFO W32Process = (PPROCESSINFO)OldProcess->Win32Process;
+ if (W32Process != NULL)
+ {
+ InterlockedDecrement(&W32Process->GDIHandleCount);
+ }
+ ObDereferenceObject(OldProcess);
+ }
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, NULL);
+ /* Don't wait on shared locks */
+ return FALSE;
+ }
+ else
+ {
+ /*
+ * The object is currently locked by another thread, so freeing is forbidden!
+ */
+ DPRINT1("Object->cExclusiveLock = %d\n", Object->cExclusiveLock);
+ GDIDBG_TRACECALLER();
+ GDIDBG_TRACELOCKER(hObj);
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+ /* do not assert here for it will call again from dxg.sys it being call twice */
+
+ DelayExecution();
+ goto LockHandle;
+ }
+ }
+ else
+ {
+ LockErrorDebugOutput(hObj, Entry, "GDIOBJ_FreeObj");
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+ }
+ }
+ else if (PrevProcId == LockedProcessId)
+ {
+ GDIDBG_TRACELOOP(hObj, PrevProcId, ProcessId);
+
+ /* the object is currently locked, wait some time and try again.
+ FIXME - we shouldn't loop forever! Give up after some time! */
+ DelayExecution();
+ /* try again */
+ goto LockHandle;
+ }
+ else
+ {
+ if (!Silent)
+ {
+ if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) == 0)
+ {
+ DPRINT1("Attempted to free gdi handle 0x%x that is already deleted!\n", hObj);
+ }
+ else if (((ULONG_PTR)PrevProcId & ~0x1) == 0)
+ {
+ DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj);
+ }
+ else
+ {
+ DPRINT1("Attempted to free foreign handle: 0x%x Owner: 0x%x from Caller: 0x%x\n", hObj, (ULONG_PTR)PrevProcId & ~0x1, (ULONG_PTR)ProcessId & ~0x1);
+ }
+ DPRINT1("Type = 0x%lx, KernelData = 0x%p, ProcessId = 0x%p\n", Entry->Type, Entry->KernelData, Entry->ProcessId);
+ GDIDBG_TRACECALLER();
+ GDIDBG_TRACEALLOCATOR(hObj);
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL
+FASTCALL
+IsObjectDead(HGDIOBJ hObject)
+{
+ INT Index = GDI_HANDLE_GET_INDEX(hObject);
+ PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
+ // We check to see if the objects are knocking on deaths door.
+ if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
+ return FALSE;
+ else
+ {
+ DPRINT1("Object 0x%x currently being destroyed!!!\n",hObject);
+ return TRUE; // return true and move on.
+ }
+}
+
+
+BOOL
+FASTCALL
+bPEBCacheHandle(HGDIOBJ Handle, int oType, PVOID pAttr)
+{
+ PGDIHANDLECACHE GdiHandleCache;
+ HGDIOBJ *hPtr;
+ BOOL Ret = FALSE;
+ int Offset = 0, Number;
+ HANDLE Lock;
+
+ GdiHandleCache = (PGDIHANDLECACHE)NtCurrentTeb()->ProcessEnvironmentBlock->GdiHandleBuffer;
+
+ switch (oType)
+ {
+ case hctBrushHandle:
+ Offset = 0;
+ break;
+
+ case hctPenHandle:
+ Offset = CACHE_BRUSH_ENTRIES;
+ break;
+
+ case hctRegionHandle:
+ Offset = CACHE_BRUSH_ENTRIES+CACHE_PEN_ENTRIES;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ Lock = InterlockedCompareExchangePointer( (PVOID*)&GdiHandleCache->ulLock,
+ NtCurrentTeb(),
+ NULL );
+ if (Lock) return FALSE;
+
+ _SEH2_TRY
+ {
+ Number = GdiHandleCache->ulNumHandles[oType];
+
+ hPtr = GdiHandleCache->Handle + Offset;
+
+ if ( pAttr && oType == hctRegionHandle)
+ {
+ if ( Number < CACHE_REGION_ENTRIES )
+ {
+ ((PRGN_ATTR)pAttr)->AttrFlags |= ATTR_CACHED;
+ hPtr[Number] = Handle;
+ GdiHandleCache->ulNumHandles[oType]++;
+ DPRINT("Put Handle Count %d PEB 0x%x\n", GdiHandleCache->ulNumHandles[oType], NtCurrentTeb()->ProcessEnvironmentBlock);
+ Ret = TRUE;
+ }
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Ret = FALSE;
+ }
+ _SEH2_END;
+
+ (void)InterlockedExchangePointer((PVOID*)&GdiHandleCache->ulLock, Lock);
+ return Ret;
+}
+
+/*!
+ * Delete GDI object
+ * \param hObject object handle
+ * \return if the function fails the returned value is FALSE.
+*/
+BOOL
+FASTCALL
+GreDeleteObject(HGDIOBJ hObject)
+{
+ INT Index;
+ PGDI_TABLE_ENTRY Entry;
+ DWORD dwObjectType;
+ PVOID pAttr = NULL;
+
+ DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject);
+ if (!IsObjectDead(hObject))
+ {
+ dwObjectType = GDIOBJ_GetObjectType(hObject);
+
+ Index = GDI_HANDLE_GET_INDEX(hObject);
+ Entry = &GdiHandleTable->Entries[Index];
+ pAttr = Entry->UserData;
+
+ switch (dwObjectType)
+ {
+ case GDI_OBJECT_TYPE_BRUSH:
+ break;
+
+ case GDI_OBJECT_TYPE_REGION:
+ /* If pAttr NULL, the probability is high for System Region. */
+ if ( pAttr &&
+ bPEBCacheHandle(hObject, hctRegionHandle, pAttr))
+ {
+ /* User space handle only! */
+ return TRUE;
+ }
+ if (pAttr)
+ {
+ FreeObjectAttr(pAttr);
+ Entry->UserData = NULL;
+ }
+ break;
+
+ case GDI_OBJECT_TYPE_DC:
+// DC_FreeDcAttr(hObject);
+ break;
+ }
+
+ return NULL != hObject
+ ? GDIOBJ_FreeObjByHandle(hObject, dwObjectType) : FALSE;
+ }
+ else
+ {
+ DPRINT1("Attempt DeleteObject 0x%x currently being destroyed!!!\n",hObject);
+ return TRUE; // return true and move on.
+ }
+}
+
+VOID
+FASTCALL
+IntDeleteHandlesForProcess(struct _EPROCESS *Process, ULONG ObjectType)
+{
+ PGDI_TABLE_ENTRY Entry, End;
+ ULONG Index = RESERVE_ENTRIES_COUNT;
+ HANDLE ProcId;
+ PPROCESSINFO W32Process;
+
+ W32Process = (PPROCESSINFO)Process->Win32Process;
+ ASSERT(W32Process);
+
+ if (W32Process->GDIHandleCount > 0)
+ {
+ ProcId = Process->UniqueProcessId;
+
+ /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
+ we should delete it directly here! */
+
+ End = &GdiHandleTable->Entries[GDI_HANDLE_COUNT];
+ for (Entry = &GdiHandleTable->Entries[RESERVE_ENTRIES_COUNT];
+ Entry != End;
+ Entry++, Index++)
+ {
+ /* ignore the lock bit */
+ if ( (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcId)
+ {
+ if ( (Entry->Type & GDI_ENTRY_BASETYPE_MASK) == ObjectType ||
+ ObjectType == GDI_OBJECT_TYPE_DONTCARE)
+ {
+ HGDIOBJ ObjectHandle;
+
+ /* Create the object handle for the entry, the lower(!) 16 bit of the
+ Type field includes the type of the object including the stock
+ object flag - but since stock objects don't have a process id we can
+ simply ignore this fact here. */
+ ObjectHandle = (HGDIOBJ)(Index | (Entry->Type << GDI_ENTRY_UPPER_SHIFT));
+
+ if (!GDIOBJ_FreeObjByHandle(ObjectHandle, GDI_OBJECT_TYPE_DONTCARE))
+ {
+ DPRINT1("Failed to delete object %p!\n", ObjectHandle);
+ }
+
+ if (W32Process->GDIHandleCount == 0)
+ {
+ /* there are no more gdi handles for this process, bail */
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/*!
+ * Internal function. Called when the process is destroyed to free the remaining GDI handles.
+ * \param Process - PID of the process that will be destroyed.
+*/
+BOOL INTERNAL_CALL
+GDI_CleanupForProcess(struct _EPROCESS *Process)
+{
+ PEPROCESS CurrentProcess;
+ PPROCESSINFO W32Process;
+
+ DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process, Process->UniqueProcessId);
+ CurrentProcess = PsGetCurrentProcess();
+ if (CurrentProcess != Process)
+ {
+ KeAttachProcess(&Process->Pcb);
+ }
+
+ W32Process = (PPROCESSINFO)CurrentProcess->Win32Process;
+
+ /* Delete objects. Begin with types that are not referenced by other types */
+ IntDeleteHandlesForProcess(Process, GDILoObjType_LO_DC_TYPE);
+ IntDeleteHandlesForProcess(Process, GDILoObjType_LO_BRUSH_TYPE);
+ IntDeleteHandlesForProcess(Process, GDILoObjType_LO_BITMAP_TYPE);
+
+ /* Finally finish with what's left */
+ IntDeleteHandlesForProcess(Process, GDI_OBJECT_TYPE_DONTCARE);
+
+ if (CurrentProcess != Process)
+ {
+ KeDetachProcess();
+ }
+
+#ifdef GDI_DEBUG
+ GdiDbgHTIntegrityCheck();
+#endif
+
+ DPRINT("Completed cleanup for process %d\n", Process->UniqueProcessId);
+ if (W32Process->GDIHandleCount > 0)
+ {
+ DPRINT1("Leaking %d handles!\n", W32Process->GDIHandleCount);
+ }
+
+ return TRUE;
+}
+
+/*!
+ * Return pointer to the object by handle.
+ *
+ * \param hObj Object handle
+ * \return Pointer to the object.
+ *
+ * \note Process can only get pointer to the objects it created or global objects.
+ *
+ * \todo Get rid of the ExpectedType parameter!
+*/
+PGDIOBJ INTERNAL_CALL
+GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ExpectedType)
+{
+ ULONG HandleIndex;
+ PGDI_TABLE_ENTRY Entry;
+ HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
+ POBJ Object = NULL;
+ ULONG HandleType, HandleUpper;
+
+ /* Check for dummy call */
+ if(hObj == NULL)
+ return NULL ;
+
+ GDIDBG_INITLOOPTRACE();
+
+ HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
+ HandleType = GDI_HANDLE_GET_TYPE(hObj);
+ HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
+
+ /* Check that the handle index is valid. */
+ if (HandleIndex >= GDI_HANDLE_COUNT )
+ return NULL;
+
+ Entry = &GdiHandleTable->Entries[HandleIndex];
+
+ /* Check if we have the requested type */
+ if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
+ HandleType != ExpectedType) ||
+ HandleType == 0 )
+ {
+ DPRINT("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
+ hObj, HandleType, ExpectedType);
+ GDIDBG_TRACECALLER();
+ GDIDBG_TRACEALLOCATOR(hObj);
+ GDIDBG_TRACEDELETER(hObj);
+ return NULL;
+ }
+
+ ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
+ HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
+
+ /* Check for invalid owner. */
+ if (ProcessId != HandleProcessId && HandleProcessId != NULL)
+ {
+ DPRINT1("Tried to lock object (0x%p) of wrong owner! ProcessId = %p, HandleProcessId = %p\n", hObj, ProcessId, HandleProcessId);
+ GDIDBG_TRACECALLER();
+ GDIDBG_TRACEALLOCATOR(hObj);
+ return NULL;
+ }
+
+ /*
+ * Prevent the thread from being terminated during the locking process.
+ * It would result in undesired effects and inconsistency of the global
+ * handle table.
+ */
+
+ KeEnterCriticalRegion();
+
+ /*
+ * Loop until we either successfully lock the handle entry & object or
+ * fail some of the check.
+ */
+
+ for (;;)
+ {
+ /* Lock the handle table entry. */
+ LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
+ LockedProcessId,
+ HandleProcessId);
+
+ if (PrevProcId == HandleProcessId)
+ {
+ /*
+ * We're locking an object that belongs to our process or it's a
+ * global object if HandleProcessId is 0 here.
+ */
+
+ if ( (Entry->KernelData != NULL) &&
+ ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) )
+ {
+ PTHREADINFO Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
+ Object = Entry->KernelData;
+
+ if (Object->cExclusiveLock == 0)
+ {
+ Object->Tid = Thread;
+ Object->cExclusiveLock = 1;
+ GDIDBG_CAPTURELOCKER(GDI_HANDLE_GET_INDEX(hObj))
+ }
+ else
+ {
+ if (Object->Tid != Thread)
+ {
+ /* Unlock the handle table entry. */
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+
+ DelayExecution();
+ continue;
+ }
+ InterlockedIncrement((PLONG)&Object->cExclusiveLock);
+ }
+ }
+ else
+ {
+ /*
+ * Debugging code. Report attempts to lock deleted handles and
+ * locking type mismatches.
+ */
+ LockErrorDebugOutput(hObj, Entry, "GDIOBJ_LockObj");
+ }
+
+ /* Unlock the handle table entry. */
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+
+ break;
+ }
+ else
+ {
+ /*
+ * The handle is currently locked, wait some time and try again.
+ */
+ GDIDBG_TRACELOOP(hObj, PrevProcId, NULL);
+
+ DelayExecution();
+ continue;
+ }
+ }
+
+ KeLeaveCriticalRegion();
+
+ return Object;
+}
+
+
+/*!
+ * Return pointer to the object by handle (and allow sharing of the handle
+ * across threads).
+ *
+ * \param hObj Object handle
+ * \return Pointer to the object.
+ *
+ * \note Process can only get pointer to the objects it created or global objects.
+ *
+ * \todo Get rid of the ExpectedType parameter!
+*/
+PGDIOBJ INTERNAL_CALL
+GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType)
+{
+ ULONG HandleIndex;
+ PGDI_TABLE_ENTRY Entry;
+ HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId;
+ POBJ Object = NULL;
+ ULONG_PTR HandleType, HandleUpper;
+
++ /* Check for dummy call */
++ if(hObj == NULL)
++ return NULL ;
++
+ HandleIndex = GDI_HANDLE_GET_INDEX(hObj);
+ HandleType = GDI_HANDLE_GET_TYPE(hObj);
+ HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
+
+ /* Check that the handle index is valid. */
+ if (HandleIndex >= GDI_HANDLE_COUNT)
+ return NULL;
+
+ /* Check if we have the requested type */
+ if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE &&
+ HandleType != ExpectedType) ||
+ HandleType == 0 )
+ {
+ DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n",
+ hObj, HandleType, ExpectedType);
+ return NULL;
+ }
+
+ Entry = &GdiHandleTable->Entries[HandleIndex];
+
+ ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1);
+ HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
+
+ /* Check for invalid owner. */
+ if (ProcessId != HandleProcessId && HandleProcessId != NULL)
+ {
+ return NULL;
+ }
+
+ /*
+ * Prevent the thread from being terminated during the locking process.
+ * It would result in undesired effects and inconsistency of the global
+ * handle table.
+ */
+
+ KeEnterCriticalRegion();
+
+ /*
+ * Loop until we either successfully lock the handle entry & object or
+ * fail some of the check.
+ */
+
+ for (;;)
+ {
+ /* Lock the handle table entry. */
+ LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
+ LockedProcessId,
+ HandleProcessId);
+
+ if (PrevProcId == HandleProcessId)
+ {
+ /*
+ * We're locking an object that belongs to our process or it's a
+ * global object if HandleProcessId is 0 here.
+ */
+
+ if ( (Entry->KernelData != NULL) &&
+ (HandleUpper == (Entry->Type << GDI_ENTRY_UPPER_SHIFT)) )
+ {
+ Object = (POBJ)Entry->KernelData;
+
+GDIDBG_CAPTURESHARELOCKER(HandleIndex);
+#ifdef GDI_DEBUG3
+ if (InterlockedIncrement((PLONG)&Object->ulShareCount) == 1)
+ {
+ memset(GDIHandleLocker[HandleIndex], 0x00, GDI_STACK_LEVELS * sizeof(ULONG));
+ RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleShareLocker[HandleIndex], NULL);
+ }
+#else
+ InterlockedIncrement((PLONG)&Object->ulShareCount);
+#endif
+ }
+ else
+ {
+ /*
+ * Debugging code. Report attempts to lock deleted handles and
+ * locking type mismatches.
+ */
+ LockErrorDebugOutput(hObj, Entry, "GDIOBJ_ShareLockObj");
+ }
+
+ /* Unlock the handle table entry. */
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+
+ break;
+ }
+ else
+ {
+ /*
+ * The handle is currently locked, wait some time and try again.
+ */
+
+ DelayExecution();
+ continue;
+ }
+ }
+
+ KeLeaveCriticalRegion();
+
+ return Object;
+}
+
+BOOL INTERNAL_CALL
+GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle)
+{
+ PGDI_TABLE_ENTRY Entry;
+ HANDLE ProcessId;
+ BOOL Ret;
+
+ DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle);
+
+ if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
+ {
+ ProcessId = PsGetCurrentProcessId();
+
+ Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, ObjectHandle);
+ Ret = Entry->KernelData != NULL &&
+ (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0 &&
+ (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcessId;
+
+ return Ret;
+ }
+
+ return FALSE;
+}
+
+BOOL INTERNAL_CALL
+GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj)
+{
+ /*
+ * FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
+ * MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
+ */
+ PGDI_TABLE_ENTRY Entry;
+ HANDLE ProcessId, LockedProcessId, PrevProcId;
+ PTHREADINFO Thread;
+ HGDIOBJ hObj;
+
+ GDIDBG_INITLOOPTRACE();
+
+ ASSERT(phObj);
+ hObj = *phObj;
+
+ DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", hObj);
+
+ Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
+
+ if (!GDI_HANDLE_IS_STOCKOBJ(hObj))
+ {
+ ProcessId = PsGetCurrentProcessId();
+ LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
+
+ Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hObj);
+
+LockHandle:
+ /* lock the object, we must not convert stock objects, so don't check!!! */
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
+ if (PrevProcId == ProcessId)
+ {
+ LONG NewType, PrevType, OldType;
+
+ /* we're locking an object that belongs to our process. First calculate
+ the new object type including the stock object flag and then try to
+ exchange it.*/
+ /* On Windows the higher 16 bit of the type field don't contain the
+ full type from the handle, but the base type.
+ (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
+ OldType = ((ULONG)hObj & GDI_HANDLE_BASETYPE_MASK) | ((ULONG)hObj >> GDI_ENTRY_UPPER_SHIFT);
+ /* We are currently not using bits 24..31 (flags) of the type field, but for compatibility
+ we copy them as we can't get them from the handle */
+ OldType |= Entry->Type & GDI_ENTRY_FLAGS_MASK;
+
+ /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */
+ NewType = OldType | GDI_ENTRY_STOCK_MASK;
+
+ /* Try to exchange the type field - but only if the old (previous type) matches! */
+ PrevType = InterlockedCompareExchange(&Entry->Type, NewType, OldType);
+ if (PrevType == OldType && Entry->KernelData != NULL)
+ {
+ PTHREADINFO PrevThread;
+ POBJ Object;
+
+ /* We successfully set the stock object flag.
+ KernelData should never be NULL here!!! */
+ ASSERT(Entry->KernelData);
+
+ Object = Entry->KernelData;
+
+ PrevThread = Object->Tid;
+ if (Object->cExclusiveLock == 0 || PrevThread == Thread)
+ {
+ /* dereference the process' object counter */
+ if (PrevProcId != GDI_GLOBAL_PROCESS)
+ {
+ PEPROCESS OldProcess;
+ PPROCESSINFO W32Process;
+ NTSTATUS Status;
+
+ /* FIXME */
+ Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
+ if (NT_SUCCESS(Status))
+ {
+ W32Process = (PPROCESSINFO)OldProcess->Win32Process;
+ if (W32Process != NULL)
+ {
+ InterlockedDecrement(&W32Process->GDIHandleCount);
+ }
+ ObDereferenceObject(OldProcess);
+ }
+ }
+
+ hObj = (HGDIOBJ)((ULONG)(hObj) | GDI_HANDLE_STOCK_MASK);
+ *phObj = hObj;
+ Object->hHmgr = hObj;
+
+ /* remove the process id lock and make it global */
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, GDI_GLOBAL_PROCESS);
+
+ /* we're done, successfully converted the object */
+ return TRUE;
+ }
+ else
+ {
+ GDIDBG_TRACELOOP(hObj, PrevThread, Thread);
+
+ /* WTF?! The object is already locked by a different thread!
+ Release the lock, wait a bit and try again!
+ FIXME - we should give up after some time unless we want to wait forever! */
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+
+ DelayExecution();
+ goto LockHandle;
+ }
+ }
+ else
+ {
+ DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj);
+ DPRINT1("OldType = 0x%x, Entry->Type = 0x%x, NewType = 0x%x, Entry->KernelData = 0x%x\n", OldType, Entry->Type, NewType, Entry->KernelData);
+ }
+ }
+ else if (PrevProcId == LockedProcessId)
+ {
+ GDIDBG_TRACELOOP(hObj, PrevProcId, ProcessId);
+
+ /* the object is currently locked, wait some time and try again.
+ FIXME - we shouldn't loop forever! Give up after some time! */
+ DelayExecution();
+ /* try again */
+ goto LockHandle;
+ }
+ else
+ {
+ DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj);
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL INTERNAL_CALL
+GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle, PEPROCESS NewOwner)
+{
+ PGDI_TABLE_ENTRY Entry;
+ HANDLE ProcessId, LockedProcessId, PrevProcId;
+ PTHREADINFO Thread;
+ BOOL Ret = TRUE;
+
+ GDIDBG_INITLOOPTRACE();
+
+ DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle, (NewOwner ? PsGetProcessId(NewOwner) : 0));
+
+ Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
+
+ if (!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
+ {
+ ProcessId = PsGetCurrentProcessId();
+ LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
+
+ Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, ObjectHandle);
+
+LockHandle:
+ /* lock the object, we must not convert stock objects, so don't check!!! */
+ PrevProcId = InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, ProcessId, LockedProcessId);
+ if (PrevProcId == ProcessId)
+ {
+ PTHREADINFO PrevThread;
+
+ if ((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
+ {
+ POBJ Object = Entry->KernelData;
+
+ PrevThread = Object->Tid;
+ if (Object->cExclusiveLock == 0 || PrevThread == Thread)
+ {
+ PEPROCESS OldProcess;
+ PPROCESSINFO W32Process;
+ NTSTATUS Status;
+
++ if (NewOwner != NULL)
++ {
++ ProcessId = PsGetProcessId(NewOwner);
++ }
++ else
++ ProcessId = 0;
++
++ if((ULONG_PTR)ProcessId == ((ULONG_PTR)PrevProcId & ~0x1))
++ {
++ DPRINT("Setting same process than previous one, nothing to do\n");
++ goto done;
++ }
++
+ /* dereference the process' object counter */
+ /* FIXME */
+ if ((ULONG_PTR)PrevProcId & ~0x1)
+ {
+ Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
+ if (NT_SUCCESS(Status))
+ {
+ W32Process = (PPROCESSINFO)OldProcess->Win32Process;
+ if (W32Process != NULL)
+ {
+ InterlockedDecrement(&W32Process->GDIHandleCount);
+ }
+ ObDereferenceObject(OldProcess);
+ }
+ }
+
+ if (NewOwner != NULL)
+ {
- else
- ProcessId = 0;
+ /* Increase the new process' object counter */
+ W32Process = (PPROCESSINFO)NewOwner->Win32Process;
+ if (W32Process != NULL)
+ {
+ InterlockedIncrement(&W32Process->GDIHandleCount);
+ }
+ }
+
++ done:
+ /* remove the process id lock and change it to the new process id */
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, ProcessId);
+
+ /* we're done! */
+ return Ret;
+ }
+ else
+ {
+ GDIDBG_TRACELOOP(ObjectHandle, PrevThread, Thread);
+
+ /* WTF?! The object is already locked by a different thread!
+ Release the lock, wait a bit and try again! DO reset the pid lock
+ so we make sure we don't access invalid memory in case the object is
+ being deleted in the meantime (because we don't have aquired a reference
+ at this point).
+ FIXME - we should give up after some time unless we want to wait forever! */
+ (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
+
+ DelayExecution();
+ goto LockHandle;
+ }
+ }
+ else
+ {
+ DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle);
+ DPRINT1("Entry->Type = 0x%lx, Entry->KernelData = 0x%p\n", Entry->Type, Entry->KernelData);
+ Ret = FALSE;
+ }
+ }
+ else if (PrevProcId == LockedProcessId)
+ {
+ GDIDBG_TRACELOOP(ObjectHandle, PrevProcId, ProcessId);
+
+ /* the object is currently locked, wait some time and try again.
+ FIXME - we shouldn't loop forever! Give up after some time! */
+ DelayExecution();
+ /* try again */
+ goto LockHandle;
+ }
+ else if (((ULONG_PTR)PrevProcId & ~0x1) == 0)
+ {
+ /* allow changing ownership of global objects */
+ ProcessId = NULL;
+ LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
+ goto LockHandle;
+ }
+ else if ((HANDLE)((ULONG_PTR)PrevProcId & ~0x1) != PsGetCurrentProcessId())
+ {
+ DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle, (ULONG_PTR)PrevProcId & ~0x1, PsGetCurrentProcessId());
+ Ret = FALSE;
+ }
+ else
+ {
+ DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle);
+ Ret = FALSE;
+ }
+ }
+ return Ret;
+}
+
+BOOL INTERNAL_CALL
+GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom, HGDIOBJ CopyTo)
+{
+ PGDI_TABLE_ENTRY FromEntry;
+ PTHREADINFO Thread;
+ HANDLE FromProcessId, FromLockedProcessId, FromPrevProcId;
+ BOOL Ret = TRUE;
+
+ GDIDBG_INITLOOPTRACE();
+
+ DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom, CopyTo);
+
+ Thread = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
+
+ if (!GDI_HANDLE_IS_STOCKOBJ(CopyFrom) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo))
+ {
+ FromEntry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, CopyFrom);
+
+ FromProcessId = (HANDLE)((ULONG_PTR)FromEntry->ProcessId & ~0x1);
+ FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
+
+LockHandleFrom:
+ /* lock the object, we must not convert stock objects, so don't check!!! */
+ FromPrevProcId = InterlockedCompareExchangePointer((PVOID*)&FromEntry->ProcessId, FromProcessId, FromLockedProcessId);
+ if (FromPrevProcId == FromProcessId)
+ {
+ PTHREADINFO PrevThread;
+ POBJ Object;
+
+ if ((FromEntry->Type & GDI_ENTRY_BASETYPE_MASK) != 0)
+ {
+ Object = FromEntry->KernelData;
+
+ /* save the pointer to the calling thread so we know it was this thread
+ that locked the object */
+ PrevThread = Object->Tid;
+ if (Object->cExclusiveLock == 0 || PrevThread == Thread)
+ {
+ /* now let's change the ownership of the target object */
+
+ if (((ULONG_PTR)FromPrevProcId & ~0x1) != 0)
+ {
+ PEPROCESS ProcessTo;
+ /* FIXME */
+ if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1), &ProcessTo)))
+ {
+ GDIOBJ_SetOwnership(CopyTo, ProcessTo);
+ ObDereferenceObject(ProcessTo);
+ }
+ }
+ else
+ {
+ /* mark the object as global */
+ GDIOBJ_SetOwnership(CopyTo, NULL);
+ }
+
+ (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
+ }
+ else
+ {
+ GDIDBG_TRACELOOP(CopyFrom, PrevThread, Thread);
+
+ /* WTF?! The object is already locked by a different thread!
+ Release the lock, wait a bit and try again! DO reset the pid lock
+ so we make sure we don't access invalid memory in case the object is
+ being deleted in the meantime (because we don't have aquired a reference
+ at this point).
+ FIXME - we should give up after some time unless we want to wait forever! */
+ (void)InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
+
+ DelayExecution();
+ goto LockHandleFrom;
+ }
+ }
+ else
+ {
+ DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom);
+ Ret = FALSE;
+ }
+ }
+ else if (FromPrevProcId == FromLockedProcessId)
+ {
+ GDIDBG_TRACELOOP(CopyFrom, FromPrevProcId, FromProcessId);
+
+ /* the object is currently locked, wait some time and try again.
+ FIXME - we shouldn't loop forever! Give up after some time! */
+ DelayExecution();
+ /* try again */
+ goto LockHandleFrom;
+ }
+ else if ((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1) != PsGetCurrentProcessId())
+ {
+ /* FIXME - should we really allow copying ownership from objects that we don't even own? */
+ DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom, (ULONG_PTR)FromPrevProcId & ~0x1, PsGetCurrentProcessId());
+ FromProcessId = (HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1);
+ FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
+ goto LockHandleFrom;
+ }
+ else
+ {
+ DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom);
+ Ret = FALSE;
+ }
+ }
+ return Ret;
+}
+
+PVOID INTERNAL_CALL
+GDI_MapHandleTable(PSECTION_OBJECT SectionObject, PEPROCESS Process)
+{
+ PVOID MappedView = NULL;
+ NTSTATUS Status;
+ LARGE_INTEGER Offset;
+ ULONG ViewSize = sizeof(GDI_HANDLE_TABLE);
+
+ Offset.QuadPart = 0;
+
+ ASSERT(SectionObject != NULL);
+ ASSERT(Process != NULL);
+
+ Status = MmMapViewOfSection(SectionObject,
+ Process,
+ &MappedView,
+ 0,
+ 0,
+ &Offset,
+ &ViewSize,
+ ViewUnmap,
+ SEC_NO_CHANGE,
+ PAGE_READONLY);
+
+ if (!NT_SUCCESS(Status))
+ return NULL;
+
+ return MappedView;
+}
+
+/* Locks 2 or 3 objects at a time */
+VOID
+INTERNAL_CALL
+GDIOBJ_LockMultipleObjs(ULONG ulCount,
+ IN HGDIOBJ* ahObj,
+ OUT PGDIOBJ* apObj)
+{
+ UINT auiIndices[3] = {0,1,2};
+ UINT i, tmp ;
+ BOOL bUnsorted = TRUE;
+
+ /* First is greatest */
+ while(bUnsorted)
+ {
+ bUnsorted = FALSE;
+ for(i=1; i<ulCount; i++)
+ {
+ if((ULONG_PTR)ahObj[auiIndices[i-1]] < (ULONG_PTR)ahObj[auiIndices[i]])
+ {
+ tmp = auiIndices[i-1];
+ auiIndices[i-1] = auiIndices[i];
+ auiIndices[i] = tmp;
+ bUnsorted = TRUE;
+ }
+ }
+ }
+
+ for(i=0;i<ulCount;i++)
+ apObj[auiIndices[i]] = GDIOBJ_LockObj(ahObj[auiIndices[i]], GDI_OBJECT_TYPE_DONTCARE);
+}
+
+
+/** PUBLIC FUNCTIONS **********************************************************/
+
+BOOL
+FASTCALL
+IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
+{
+ INT Index;
+ PGDI_TABLE_ENTRY Entry;
+/*
+ System Regions:
+ These regions do not use attribute sections and when allocated, use gdiobj
+ level functions.
+ */
+ // FIXME! HAX!!! Remove this once we get everything right!
+ Index = GDI_HANDLE_GET_INDEX(hRgn);
+ Entry = &GdiHandleTable->Entries[Index];
+ if (Entry->UserData) FreeObjectAttr(Entry->UserData);
+ Entry->UserData = NULL;
+ //
+ if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
+ {
+ return GDIOBJ_SetOwnership(hRgn, NULL);
+ }
+ if (OwnerMask == GDI_OBJ_HMGR_POWNED)
+ {
+ return GDIOBJ_SetOwnership((HGDIOBJ) hRgn, PsGetCurrentProcess() );
+ }
+ return FALSE;
+}
+
+BOOL
+FASTCALL
+IntGdiSetBrushOwner(PBRUSH pbr, DWORD OwnerMask)
+{
+ HBRUSH hBR;
+ PEPROCESS Owner = NULL;
+ PGDI_TABLE_ENTRY pEntry = NULL;
+
+ if (!pbr) return FALSE;
+
+ hBR = pbr->BaseObject.hHmgr;
+
+ if (!hBR || (GDI_HANDLE_GET_TYPE(hBR) != GDI_OBJECT_TYPE_BRUSH))
+ return FALSE;
+ else
+ {
+ INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hBR);
+ pEntry = &GdiHandleTable->Entries[Index];
+ }
+
+ if (pbr->flAttrs & GDIBRUSH_IS_GLOBAL)
+ {
+ GDIOBJ_ShareUnlockObjByPtr((POBJ)pbr);
+ return TRUE;
+ }
+
+ if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
+ {
+ // Set this Brush to inaccessible mode and to an Owner of NONE.
+// if (OwnerMask == GDI_OBJ_HMGR_NONE) Owner = OwnerMask;
+
+ if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, Owner))
+ return FALSE;
+
+ // Deny user access to User Data.
+ pEntry->UserData = NULL; // This hBR is inaccessible!
+ }
+
+ if (OwnerMask == GDI_OBJ_HMGR_POWNED)
+ {
+ if (!GDIOBJ_SetOwnership((HGDIOBJ) hBR, PsGetCurrentProcess() ))
+ return FALSE;
+
+ // Allow user access to User Data.
+ pEntry->UserData = pbr->pBrushAttr;
+ }
+ return TRUE;
+}
+
+BOOL
+FASTCALL
+IntGdiSetDCOwnerEx( HDC hDC, DWORD OwnerMask, BOOL NoSetBrush)
+{
+ PDC pDC;
+ BOOL Ret = FALSE;
+
+ if (!hDC || (GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_DC)) return FALSE;
+
+ if ((OwnerMask == GDI_OBJ_HMGR_PUBLIC) || OwnerMask == GDI_OBJ_HMGR_NONE)
+ {
+ pDC = DC_LockDc ( hDC );
+ MmCopyFromCaller(&pDC->dcattr, pDC->pdcattr, sizeof(DC_ATTR));
+ DC_vFreeDcAttr(pDC);
+ DC_UnlockDc( pDC );
+
+ if (!DC_SetOwnership( hDC, NULL )) // This hDC is inaccessible!
+ return Ret;
+ }
+
+ if (OwnerMask == GDI_OBJ_HMGR_POWNED)
+ {
+ pDC = DC_LockDc ( hDC );
+ ASSERT(pDC->pdcattr == &pDC->dcattr);
+ DC_UnlockDc( pDC );
+
+ if (!DC_SetOwnership( hDC, PsGetCurrentProcess() )) return Ret;
+
+ DC_AllocateDcAttr( hDC ); // Allocate new dcattr
+
+ DCU_SynchDcAttrtoUser( hDC ); // Copy data from dc to dcattr
+ }
+
+ if ((OwnerMask != GDI_OBJ_HMGR_NONE) && !NoSetBrush)
+ {
+ pDC = DC_LockDc ( hDC );
+ if (IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrFill, OwnerMask))
+ IntGdiSetBrushOwner((PBRUSH)pDC->dclevel.pbrLine, OwnerMask);
+ DC_UnlockDc( pDC );
+ }
+ return TRUE;
+}
+
+INT
+FASTCALL
+GreGetObjectOwner(HGDIOBJ Handle, GDIOBJTYPE ObjType)
+{
+ INT Ret = GDI_OBJ_HMGR_RESTRICTED;
+
+ if ( GDI_HANDLE_GET_INDEX(Handle) < GDI_HANDLE_COUNT )
+ {
+ PGDI_TABLE_ENTRY pEntry = &GdiHandleTable->Entries[GDI_HANDLE_GET_INDEX(Handle)];
+
+ if (pEntry->ObjectType == ObjType)
+ {
+ if (pEntry->FullUnique == (GDI_HANDLE_GET_UPPER(Handle) >> GDI_ENTRY_UPPER_SHIFT))
+ Ret = pEntry->ProcessId & ~1;
+ }
+ }
+ return Ret;
+}
+
+W32KAPI
+HANDLE
+APIENTRY
+NtGdiCreateClientObj(
+ IN ULONG ulType
+)
+{
+ POBJ pObject;
+ HANDLE handle;
+
+ /* Mask out everything that would change the type in a wrong manner */
+ ulType &= (GDI_HANDLE_TYPE_MASK & ~GDI_HANDLE_BASETYPE_MASK);
+
+ /* Allocate a new object */
+ pObject = GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_CLIOBJ | ulType);
+ if (!pObject)
+ {
+ return NULL;
+ }
+
+ /* get the handle */
+ handle = pObject->hHmgr;
+
+ /* Unlock it */
+ GDIOBJ_UnlockObjByPtr(pObject);
+
+ return handle;
+}
+
+W32KAPI
+BOOL
+APIENTRY
+NtGdiDeleteClientObj(
+ IN HANDLE h
+)
+{
+ /* We first need to get the real type from the handle */
+ ULONG type = GDI_HANDLE_GET_TYPE(h);
+
+ /* Check if it's really a CLIENTOBJ */
+ if ((type & GDI_HANDLE_BASETYPE_MASK) != GDILoObjType_LO_CLIENTOBJ_TYPE)
+ {
+ /* FIXME: SetLastError? */
+ return FALSE;
+ }
+ return GDIOBJ_FreeObjByHandle(h, type);
+}
+
+INT
+FASTCALL
+IntGdiGetObject(IN HANDLE Handle,
+ IN INT cbCount,
+ IN LPVOID lpBuffer)
+{
+ PVOID pGdiObject;
+ INT Result = 0;
+ DWORD dwObjectType;
+
+ pGdiObject = GDIOBJ_LockObj(Handle, GDI_OBJECT_TYPE_DONTCARE);
+ if (!pGdiObject)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return 0;
+ }
+
+ dwObjectType = GDIOBJ_GetObjectType(Handle);
+ switch (dwObjectType)
+ {
+ case GDI_OBJECT_TYPE_PEN:
+ case GDI_OBJECT_TYPE_EXTPEN:
+ Result = PEN_GetObject((PBRUSH) pGdiObject, cbCount, (PLOGPEN) lpBuffer); // IntGdiCreatePenIndirect
+ break;
+
+ case GDI_OBJECT_TYPE_BRUSH:
+ Result = BRUSH_GetObject((PBRUSH ) pGdiObject, cbCount, (LPLOGBRUSH)lpBuffer);
+ break;
+
+ case GDI_OBJECT_TYPE_BITMAP:
+ Result = BITMAP_GetObject((SURFACE *) pGdiObject, cbCount, lpBuffer);
+ break;
+ case GDI_OBJECT_TYPE_FONT:
+ Result = FontGetObject((PTEXTOBJ) pGdiObject, cbCount, lpBuffer);
+#if 0
+ // Fix the LOGFONT structure for the stock fonts
+ if (FIRST_STOCK_HANDLE <= Handle && Handle <= LAST_STOCK_HANDLE)
+ {
+ FixStockFontSizeW(Handle, cbCount, lpBuffer);
+ }
+#endif
+ break;
+
+ case GDI_OBJECT_TYPE_PALETTE:
+ Result = PALETTE_GetObject((PPALETTE) pGdiObject, cbCount, lpBuffer);
+ break;
+
+ default:
+ DPRINT1("GDI object type 0x%08x not implemented\n", dwObjectType);
+ break;
+ }
+
+ GDIOBJ_UnlockObjByPtr(pGdiObject);
+
+ return Result;
+}
+
+
+
+W32KAPI
+INT
+APIENTRY
+NtGdiExtGetObjectW(IN HANDLE hGdiObj,
+ IN INT cbCount,
+ OUT LPVOID lpBuffer)
+{
+ INT iRetCount = 0;
+ INT cbCopyCount;
+ union
+ {
+ BITMAP bitmap;
+ DIBSECTION dibsection;
+ LOGPEN logpen;
+ LOGBRUSH logbrush;
+ LOGFONTW logfontw;
+ EXTLOGFONTW extlogfontw;
+ ENUMLOGFONTEXDVW enumlogfontexdvw;
+ } Object;
+
+ // Normalize to the largest supported object size
+ cbCount = min((UINT)cbCount, sizeof(Object));
+
+ // Now do the actual call
+ iRetCount = IntGdiGetObject(hGdiObj, cbCount, lpBuffer ? &Object : NULL);
+ cbCopyCount = min((UINT)cbCount, (UINT)iRetCount);
+
+ // Make sure we have a buffer and a copy size
+ if ((cbCopyCount) && (lpBuffer))
+ {
+ // Enter SEH for buffer transfer
+ _SEH2_TRY
+ {
+ // Probe the buffer and copy it
+ ProbeForWrite(lpBuffer, cbCopyCount, sizeof(WORD));
+ RtlCopyMemory(lpBuffer, &Object, cbCopyCount);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ // Clear the return value.
+ // Do *NOT* set last error here!
+ iRetCount = 0;
+ }
+ _SEH2_END;
+ }
+ // Return the count
+ return iRetCount;
+}
+
+/* EOF */