-
Notifications
You must be signed in to change notification settings - Fork 444
/
override.cpp
1684 lines (1491 loc) · 53 KB
/
override.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// override.cpp - キレイなTextOut
// 2006/09/27
#include "override.h"
#include "ft.h"
#include "fteng.h"
#include "supinfo.h"
#include "undocAPI.h"
//#include "lrucache.hpp"
#include <malloc.h> // _alloca
#include <mbctype.h> // _getmbcp
#pragma comment(lib, "Gdi32.lib")
#pragma comment(lib, "User32.lib")
#pragma comment(lib, "WindowsCodecs.lib")
#pragma comment (lib, "dwrite.lib")
#if defined(_DEBUG)
void Dbg_TractGetTextExtent(LPCSTR lpString, int cbString, LPSIZE lpSize);
void Dbg_TractGetTextExtent(LPCWSTR lpString, int cbString, LPSIZE lpSize);
void Dbg_TraceExtTextOutW(int nXStart, int nYStart, UINT fuOptions, LPCWSTR lpString, int cbString, const int* lpDx);
void Dbg_TraceScriptItemize(const WCHAR* pwcInChars, int cInChars);
void Dbg_TraceScriptShape(const WCHAR* pwcChars, int cChars, const SCRIPT_ANALYSIS* psa, const WORD* pwOutGlyphs, int cGlyphs);
#else
#define Dbg_TraceExtTextOutW(x,y,f,s,c,p)
#define Dbg_TractGetTextExtent(s,c,p)
#define Dbg_TraceScriptItemize(s,c)
#define Dbg_TraceScriptShape(s,c,p,g,o)
#endif
#define CCH_MAX_STACK 256
typedef HRESULT (WINAPI * __D2D1CreateFactory)(
D2D1_FACTORY_TYPE factoryType,
REFIID riid,
const D2D1_FACTORY_OPTIONS *pFactoryOptions,
void **ppIFactory);
typedef HRESULT (WINAPI* __DWriteCreateFactory)(
__in DWRITE_FACTORY_TYPE factoryType,
__in REFIID iid,
__out IUnknown **factory
);
CFontCache FontCache;
CDCArray DCArray;
wstring nullstring;
BOOL g_ccbRender = true;
BOOL g_ccbCache = true;
HFONT g_alterGUIFont = NULL;
HFONT g_alterSysFont = NULL;
//BOOL FreeTypeGetTextExtentPoint(HDC hdc, LPCSTR lpString, int cbString, LPSIZE lpSize, const FREETYPE_PARAMS* params);
HFONT GetCurrentFont(HDC hdc)
{
HFONT hCurFont = (HFONT)GetCurrentObject(hdc, OBJ_FONT);
if (!hCurFont) {
// NULLの場合はSystemを設定しておく
hCurFont = (HFONT)GetStockObject(SYSTEM_FONT);
}
return hCurFont;
}
//判断是否是有效普通显示DC,用于跳过字幕
BOOL IsValidDC(HDC hdc)
{
if (GetDeviceCaps(hdc, TECHNOLOGY) != DT_RASDISPLAY) {
return FALSE;
}
return TRUE;
}
BOOL IsProcessExcluded()
{
// if (GetModuleHandle(NULL) == GetModuleHandle(_T("gdi++.exe"))) {
// return TRUE;
// }
const CGdippSettings* pSettings = CGdippSettings::GetInstanceNoInit();
if (pSettings->IsInclude()) {
if (pSettings->IsProcessIncluded()) {
return FALSE;
}
return TRUE;
}
if (pSettings->IsProcessExcluded()) {
return TRUE;
}
return FALSE;
}
BOOL IsProcessUnload()
{
// if (GetModuleHandle(NULL) == GetModuleHandle(_T("gdi++.exe"))) {
// return TRUE;
// }
const CGdippSettings* pSettings = CGdippSettings::GetInstanceNoInit();
if (pSettings->IsInclude()) {
if (pSettings->IsProcessIncluded()) {
return FALSE;
}
return TRUE;
}
if (pSettings->IsProcessUnload()) {
return TRUE;
}
return FALSE;
}
BOOL IsExeUnload(LPCTSTR lpApp)
{
const CGdippSettings* pSettings = CGdippSettings::GetInstanceNoInit();
if (pSettings->IsInclude()) {
if (pSettings->IsExeInclude(lpApp)) {
return FALSE;
}
return TRUE;
}
if (pSettings->IsExeUnload(lpApp)) {
return TRUE;
}
return FALSE;
}
//切り上げ除算
int div_ceil(int a, int b)
{
if(a % b)
return (a>0)? (a/b+1): (a/b-1);
return a / b;
}
template <typename _TCHAR> //修改这个函数,使它在失败的时候返回false,由调用者负责调用Windows原函数,实现线程安全。
BOOL _GetTextExtentPoint32AorW(HDC hdc, _TCHAR* lpString, int cbString, LPSIZE lpSize)
{
const CGdippSettings* pSettings = CGdippSettings::GetInstance();
if (pSettings->WidthMode() == SETTING_WIDTHMODE_GDI32
|| !IsValidDC(hdc) || !lpString || cbString <= 0) {
return false;
}
FREETYPE_PARAMS params(0, hdc);
if(FreeTypeGetTextExtentPoint(hdc, lpString, cbString, lpSize, ¶ms)) {
Dbg_TractGetTextExtent(lpString, cbString, lpSize);
return TRUE;
}
else
return false;
}
//firefox
/*
BOOL WINAPI IMPL_GetTextExtentPoint32A(HDC hdc, LPCSTR lpString, int cbString, LPSIZE lpSize)
{
//CThreadCounter __counter;
//CCriticalSectionLock __lock;
return _GetTextExtentPoint32AorW(hdc, lpString, cbString, lpSize) || ORIG_GetTextExtentPoint32A(hdc, lpString, cbString, lpSize);
}
BOOL WINAPI IMPL_GetTextExtentPoint32W(HDC hdc, LPCWSTR lpString, int cbString, LPSIZE lpSize)
{
//CThreadCounter __counter;
//CCriticalSectionLock __lock;
return _GetTextExtentPoint32AorW(hdc, lpString, cbString, lpSize) || ORIG_GetTextExtentPoint32W(hdc, lpString, cbString, lpSize);
}
BOOL WINAPI IMPL_GetTextExtentPointA(HDC hdc, LPCSTR lpString, int cbString, LPSIZE lpSize)
{
//CThreadCounter __counter;
//CCriticalSectionLock __lock;
return _GetTextExtentPoint32AorW(hdc, lpString, cbString, lpSize) || ORIG_GetTextExtentPoint32A(hdc, lpString, cbString, lpSize);
}
BOOL WINAPI IMPL_GetTextExtentPointW(HDC hdc, LPCWSTR lpString, int cbString, LPSIZE lpSize)
{
//CThreadCounter __counter;
//CCriticalSectionLock __lock;
return _GetTextExtentPoint32AorW(hdc, lpString, cbString, lpSize) || ORIG_GetTextExtentPoint32W(hdc, lpString, cbString, lpSize);
}
BOOL WINAPI IMPL_GetCharWidthW(HDC hdc, UINT iFirstChar, UINT iLastChar, LPINT lpBuffer)
{
//CThreadCounter __counter;
const CGdippSettings* pSettings = CGdippSettings::GetInstance();
if (pSettings->WidthMode() == SETTING_WIDTHMODE_GDI32
|| !IsValidDC(hdc) || !lpBuffer || !FreeTypeGetCharWidth(hdc, iFirstChar, iLastChar, lpBuffer)) {
return ORIG_GetCharWidthW(hdc, iFirstChar, iLastChar, lpBuffer);
}
return TRUE;
}
BOOL WINAPI IMPL_GetCharWidth32W(HDC hdc, UINT iFirstChar, UINT iLastChar, LPINT lpBuffer)
{
//CThreadCounter __counter;
TRACE(_T("GetCharWidth32W(%u, %u, {...})\n"), iFirstChar, iLastChar);
const CGdippSettings* pSettings = CGdippSettings::GetInstance();
if (pSettings->WidthMode() == SETTING_WIDTHMODE_GDI32
|| !IsValidDC(hdc) || !lpBuffer || !FreeTypeGetCharWidth(hdc, iFirstChar, iLastChar, lpBuffer)) {
return ORIG_GetCharWidth32W(hdc, iFirstChar, iLastChar, lpBuffer);
}
return TRUE;
}*/
/*
extern PFNLdrGetProcedureAddress LdrGetProcedureAddress;
int MyGetProcAddress(HMODULE dll, LPSTR funcname)
{
ANSI_STRING dumy;
dumy.Length = strlen(funcname);
dumy.MaximumLength = strlen(funcname);
dumy.Buffer = funcname;
int nRet;
LdrGetProcedureAddress(dll,&dumy,0,(void**)&nRet);
return nRet;
}*/
/*
LONG WINAPI IMPL_LdrLoadDll(IN PWCHAR PathToFile OPTIONAL, IN ULONG Flags OPTIONAL, IN UNICODE_STRING2* ModuleFileName, OUT HANDLE* ModuleHandle)
{
static bool bFisrtTimeHook = GetModuleHandle(_T("d2d1.dll"))!=0;
if (!bD2D1Loaded)
{
wstring filename = wstring(ModuleFileName->Buffer);
int last_slash=filename.find_last_of('\\');
if (last_slash!=-1)
filename.erase(0,last_slash+1); //删除路径
if (_wcsicmp(filename.c_str(), L"d2d1.dll")==0) //正在载入d2d1.dll
{
bD2D1Loaded = true;
LONG result = ORIG_LdrLoadDll(PathToFile, Flags, ModuleFileName, ModuleHandle);
HookD2D1((HMODULE)*ModuleHandle);
return result;
}
if (bFisrtTimeHook)
{
bFisrtTimeHook = false;
bD2D1Loaded = true;
HookD2D1(GetModuleHandle(_T("d2d1.dll")));
}
}
return ORIG_LdrLoadDll(PathToFile, Flags, ModuleFileName, ModuleHandle);
}*/
/*
BOOL WINAPI IMPL_CreateProcessInternalW( HANDLE hToken, LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, \
DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation , PHANDLE hNewToken)
{
//CThreadCounter __counter;
CCriticalSectionLock __lock;
return _CreateProcessInternalW(hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation, hNewToken, ORIG_CreateProcessInternalW);
}*/
/*
BOOL WINAPI IMPL_nCreateProcessA(LPCSTR lpApp, LPSTR lpCmd, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta, BOOL bInherit, DWORD dwFlags, LPVOID lpEnv, LPCSTR lpDir, LPSTARTUPINFOA psi, LPPROCESS_INFORMATION ppi)
{
//CThreadCounter __counter;
CCriticalSectionLock __lock;
TRACE(_T("CreateProcessA(\"%hs\", \"%hs\", ...)\n"), lpApp, lpCmd);
return _CreateProcessAorW(lpApp, lpCmd, pa, ta, bInherit, dwFlags, lpEnv, lpDir, psi, ppi, ORIG_nCreateProcessA);
}
BOOL WINAPI IMPL_nCreateProcessW(LPCWSTR lpApp, LPWSTR lpCmd, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta, BOOL bInherit, DWORD dwFlags, LPVOID lpEnv, LPCWSTR lpDir, LPSTARTUPINFOW psi, LPPROCESS_INFORMATION ppi)
{
//CThreadCounter __counter;
CCriticalSectionLock __lock;
TRACE(_T("CreateProcessW(\"%ls\", \"%ls\", ...)\n"), lpApp, lpCmd);
return _CreateProcessAorW(lpApp, lpCmd, pa, ta, bInherit, dwFlags, lpEnv, lpDir, psi, ppi, ORIG_nCreateProcessW);
}
BOOL WINAPI IMPL_CreateProcessAsUserA(HANDLE hToken, LPCSTR lpApp, LPSTR lpCmd, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta, BOOL bInherit, DWORD dwFlags, LPVOID lpEnv, LPCSTR lpDir, LPSTARTUPINFOA psi, LPPROCESS_INFORMATION ppi)
{
//CThreadCounter __counter;
CCriticalSectionLock __lock;
TRACE(_T("CreateProcessA(\"%hs\", \"%hs\", ...)\n"), lpApp, lpCmd);
return _CreateProcessAsUserAorW(hToken, lpApp, lpCmd, pa, ta, bInherit, dwFlags, lpEnv, lpDir, psi, ppi, ORIG_CreateProcessAsUserA);
}
BOOL WINAPI IMPL_CreateProcessAsUserW(HANDLE hToken, LPCWSTR lpApp, LPWSTR lpCmd, LPSECURITY_ATTRIBUTES pa, LPSECURITY_ATTRIBUTES ta, BOOL bInherit, DWORD dwFlags, LPVOID lpEnv, LPCWSTR lpDir, LPSTARTUPINFOW psi, LPPROCESS_INFORMATION ppi)
{
//CThreadCounter __counter;
CCriticalSectionLock __lock;
TRACE(_T("CreateProcessW(\"%ls\", \"%ls\", ...)\n"), lpApp, lpCmd);
return _CreateProcessAsUserAorW(hToken, lpApp, lpCmd, pa, ta, bInherit, dwFlags, lpEnv, lpDir, psi, ppi, ORIG_CreateProcessAsUserW);
}*/
/*
HOOK_DEFINE(user32.dll, DWORD, GetTabbedTextExtentA, (HDC hdc, LPCSTR lpString, int nCount, int nTabPositions, CONST LPINT lpnTabStopPositions), (hdc, lpString, nCount, nTabPositions, lpnTabStopPositions))
HOOK_DEFINE(user32.dll, DWORD, GetTabbedTextExtentW, (HDC hdc, LPCWSTR lpString, int nCount, int nTabPositions, CONST LPINT lpnTabStopPositions), (hdc, lpString, nCount, nTabPositions, lpnTabStopPositions))
HOOK_DEFINE(gdi32.dll, BOOL, GetTextExtentExPointA, (HDC hdc, LPCSTR lpszStr, int cchString, int nMaxExtent, LPINT lpnFit, LPINT lpDx, LPSIZE lpSize), (hdc, lpszStr, cchString, nMaxExtent, lpnFit, lpDx, lpSize))
HOOK_DEFINE(gdi32.dll, BOOL, GetTextExtentExPointW, (HDC hdc, LPCWSTR lpszStr, int cchString, int nMaxExtent, LPINT lpnFit, LPINT lpDx, LPSIZE lpSize), (hdc, lpszStr, cchString, nMaxExtent, lpnFit, lpDx, lpSize))
HOOK_DEFINE(gdi32.dll, BOOL, GetTextExtentExPointI, (HDC hdc, LPWORD pgiIn, int cgi, int nMaxExtent, LPINT lpnFit, LPINT lpDx, LPSIZE lpSize), (hdc, pgiIn, cgi, nMaxExtent, lpnFit, lpDx, lpSize))
HOOK_DEFINE(gdi32.dll, BOOL, GetTextExtentPointA, (HDC hdc, LPCSTR lpString, int cbString, LPSIZE lpSize), (hdc, lpString, cbString, lpSize))
HOOK_DEFINE(gdi32.dll, BOOL, GetTextExtentPointW, (HDC hdc, LPCWSTR lpString, int cbString, LPSIZE lpSize), (hdc, lpString, cbString, lpSize))
HOOK_DEFINE(gdi32.dll, BOOL, GetTextExtentPointI, (HDC hdc, LPWORD pgiIn, int cgi, LPSIZE lpSize), (hdc, pgiIn, cgi, lpSize))
*/
/*
HFONT WINAPI IMPL_CreateFontA(int nHeight, int nWidth, int nEscapement, int nOrientation, int fnWeight, DWORD fdwItalic, DWORD fdwUnderline, DWORD fdwStrikeOut, DWORD fdwCharSet, DWORD fdwOutputPrecision, DWORD fdwClipPrecision, DWORD fdwQuality, DWORD fdwPitchAndFamily, LPCSTR lpszFace)
{
LOGFONTA lf = {
nHeight,
nWidth,
nEscapement,
nOrientation,
fnWeight,
!!fdwItalic,
!!fdwUnderline,
!!fdwStrikeOut,
(BYTE)fdwCharSet,
(BYTE)fdwOutputPrecision,
(BYTE)fdwClipPrecision,
(BYTE)fdwQuality,
(BYTE)fdwPitchAndFamily,
};
if (lpszFace)
strncpy(lf.lfFaceName, lpszFace, LF_FACESIZE - 1);
return IMPL_CreateFontIndirectA(&lf);
}
HFONT WINAPI IMPL_CreateFontW(int nHeight, int nWidth, int nEscapement, int nOrientation, int fnWeight, DWORD fdwItalic, DWORD fdwUnderline, DWORD fdwStrikeOut, DWORD fdwCharSet, DWORD fdwOutputPrecision, DWORD fdwClipPrecision, DWORD fdwQuality, DWORD fdwPitchAndFamily, LPCWSTR lpszFace)
{
LOGFONTW lf = {
nHeight,
nWidth,
nEscapement,
nOrientation,
fnWeight,
!!fdwItalic,
!!fdwUnderline,
!!fdwStrikeOut,
(BYTE)fdwCharSet,
(BYTE)fdwOutputPrecision,
(BYTE)fdwClipPrecision,
(BYTE)fdwQuality,
(BYTE)fdwPitchAndFamily,
};
if (lpszFace)
wcsncpy(lf.lfFaceName, lpszFace, LF_FACESIZE - 1);
return IMPL_CreateFontIndirectW(&lf);
}
HFONT WINAPI IMPL_CreateFontIndirectA(CONST LOGFONTA *lplfA)
{
if(!lplfA) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
const CGdippSettings* pSettings = CGdippSettings::GetInstance();
if (pSettings->IsFontExcluded(lplfA->lfFaceName)) {
return ORIG_CreateFontIndirectA(lplfA);
}
LOGFONT lf = {
lplfA->lfHeight,
lplfA->lfWidth,
lplfA->lfEscapement,
lplfA->lfOrientation,
lplfA->lfWeight,
lplfA->lfItalic,
lplfA->lfUnderline,
lplfA->lfStrikeOut,
lplfA->lfCharSet,
lplfA->lfOutPrecision,
lplfA->lfClipPrecision,
lplfA->lfQuality,
lplfA->lfPitchAndFamily,
};
MultiByteToWideChar(CP_ACP, 0, lplfA->lfFaceName, LF_FACESIZE, lf.lfFaceName, LF_FACESIZE);
LOGFONT* lplf = &lf;
if (pSettings->CopyForceFont(lf, lf)) {
lplf = &lf;
}
HFONT hf = IMPL_CreateFontIndirectW(lplf);
// if(hf && lplf && !pSettings->LoadOnDemand()) {
// AddFontToFT(lplf->lfFaceName, lplf->lfWeight, !!lplf->lfItalic);
// }
return hf;
}
*/
//Snowie!!
LPCWSTR GetCachedFont(HFONT lFont)
{
CFontCache::const_iterator it= FontCache.find(lFont);
if (it==FontCache.end())
return NULL;
else
return it->second->lpRealName;
}
LPCWSTR GetCachedFontLocale(HFONT lFont)
{
CFontCache::const_iterator it= FontCache.find(lFont);
if (it==FontCache.end())
return NULL;
else
return it->second->lpGDIName;
}
void AddToCachedFont(HFONT lfont, LPWSTR lpFaceName, LPWSTR lpGDIName)
{
if (!lfont) return; //不可以添加空节点
CCriticalSectionLock __lock(CCriticalSectionLock::CS_CACHEDFONT);
if (GetCachedFont(lfont)) return; //已经存在的字体
FontCache[lfont] = new CFontSubResult(lpFaceName, lpGDIName);
}
void DeleteCachedFont(HFONT lfont)
{
if (!lfont) return; //不可以删除头结点
CCriticalSectionLock __lock(CCriticalSectionLock::CS_CACHEDFONT);
CFontCache::iterator it= FontCache.find(lfont);
if (it!=FontCache.end())
{
delete it->second;
FontCache.erase(it);
}
}
int WINAPI IMPL_GetTextFaceAliasW(HDC hdc, int nLen, LPWSTR lpAliasW)
{
//CThreadCounter __counter;
int bResult = ORIG_GetTextFaceAliasW(hdc, nLen, lpAliasW);
//LOGFONT lf, lf2;
//StringCchCopy(lf.lfFaceName, LF_FACESIZE, lpAliasW);
//LOGFONT * lplf = &lf;
LPCWSTR fontcache=GetCachedFont(GetCurrentFont(hdc));
if (fontcache){
if (lpAliasW)
StringCchCopy(lpAliasW, LF_FACESIZE, fontcache);
bResult = wcslen(fontcache)+1;
}
return bResult;
}
// Won't get any better for clipbox, obsolete.
/*
cache::lru_cache<HFONT, int> FontHeightCache(200); // cache 200 most frequently used fonts' height
const WCHAR TEST_ALPHABET_SEQUENCE[] = L"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int GetFontMaxAlphabetHeight(HDC dc, MAT2 *lpmt2) {
HFONT ft = GetCurrentFont(dc);
if (FontHeightCache.exists(ft))
return FontHeightCache.get(ft);
GLYPHMETRICS lppm = { 0 };
int nHeight = 0;
for (int i = 0; i < 26; ++i) {
ORIG_GetGlyphOutlineW(dc, TEST_ALPHABET_SEQUENCE[i], GGO_METRICS, &lppm, 0, 0, lpmt2);
if (lppm.gmptGlyphOrigin.y>nHeight)
nHeight = lppm.gmptGlyphOrigin.y;
}
FontHeightCache.put(ft, nHeight);
return nHeight;
}*/
DWORD WINAPI IMPL_GetGlyphOutlineW(__in HDC hdc, __in UINT uChar, __in UINT fuFormat, __out LPGLYPHMETRICS lpgm, __in DWORD cjBuffer, __out_bcount_opt(cjBuffer) LPVOID pvBuffer, __in CONST MAT2 *lpmat2)
{
const CGdippSettings* pSettings = CGdippSettings::GetInstance();
DWORD ret= ORIG_GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cjBuffer, pvBuffer, lpmat2);
if (pSettings->EnableClipBoxFix() && (!cjBuffer || !pvBuffer)) {
if (!(fuFormat & (GGO_BITMAP | GGO_GRAY2_BITMAP | GGO_GRAY4_BITMAP | GGO_GRAY8_BITMAP | GGO_NATIVE))) {
//lpgm->gmptGlyphOrigin.x -= 1;
//lpgm->gmptGlyphOrigin.y += 1;
//lpgm->gmBlackBoxX += 3;
//lpgm->gmBlackBoxY += 2;
static int n = (int)floor(1.5*pSettings->ScreenDpi() / 96);
int nDeltaY = n, nDeltaBlackY = n;
TEXTMETRIC tm = { 0 };
GetTextMetrics(hdc, &tm);
if (lpgm->gmptGlyphOrigin.y < tm.tmAscent) { // origin out of the top of the box
if (lpgm->gmptGlyphOrigin.y + nDeltaY>tm.tmAscent) {
nDeltaY = tm.tmAscent - lpgm->gmptGlyphOrigin.y; // limit the top position of the origin
}
}
else nDeltaY = 0;
lpgm->gmptGlyphOrigin.y += nDeltaY;
/*if (lpgm->gmptGlyphOrigin.x > 0)
lpgm->gmBlackBoxX += n; // increase blackbox width if it's not a ligature
if (lpgm->gmBlackBoxX > tm.tmMaxCharWidth) {
lpgm->gmBlackBoxX = tm.tmMaxCharWidth;
}*/
lpgm->gmBlackBoxY += nDeltaY;
if (tm.tmAscent - lpgm->gmptGlyphOrigin.y + lpgm->gmBlackBoxY - 1 < tm.tmHeight) // still has some room to scale up
{
if (tm.tmAscent - lpgm->gmptGlyphOrigin.y + lpgm->gmBlackBoxY + 1 + nDeltaBlackY > tm.tmHeight)
lpgm->gmBlackBoxY = tm.tmHeight - tm.tmAscent + lpgm->gmptGlyphOrigin.y + 1;
else
lpgm->gmBlackBoxY += nDeltaBlackY;
}
}
}
// TEXTMETRIC tm;
// GetTextMetrics(hdc, &tm);
return ret;
}
DWORD WINAPI IMPL_GetGlyphOutlineA(__in HDC hdc, __in UINT uChar, __in UINT fuFormat, __out LPGLYPHMETRICS lpgm, __in DWORD cjBuffer, __out_bcount_opt(cjBuffer) LPVOID pvBuffer, __in CONST MAT2 *lpmat2)
{
//fuFormat |= GGO_UNHINTED;
const CGdippSettings* pSettings = CGdippSettings::GetInstance();
DWORD ret= ORIG_GetGlyphOutlineA(hdc, uChar, fuFormat, lpgm, cjBuffer, pvBuffer, lpmat2);
// if (pSettings->EnableClipBoxFix())
// {
// lpgm->gmptGlyphOrigin.y+=1;
// lpgm->gmBlackBoxY+=1;
// }
if (pSettings->EnableClipBoxFix() && (!cjBuffer || !pvBuffer)) {
if (!(fuFormat & (GGO_BITMAP | GGO_GRAY2_BITMAP | GGO_GRAY4_BITMAP | GGO_GRAY8_BITMAP | GGO_NATIVE))) {
static int n = (int)floor(1.5*pSettings->ScreenDpi() / 96);
int nDeltaY = n, nDeltaBlackY = n;
TEXTMETRIC tm = { 0 };
GetTextMetrics(hdc, &tm);
if (lpgm->gmptGlyphOrigin.y < tm.tmAscent) { // origin out of the top of the box
if (lpgm->gmptGlyphOrigin.y + nDeltaY>tm.tmAscent) {
nDeltaY = tm.tmAscent - lpgm->gmptGlyphOrigin.y; // limit the top position of the origin
}
}
else nDeltaY = 0;
/*if (lpgm->gmptGlyphOrigin.x > 0)
lpgm->gmBlackBoxX += n; // increase blackbox width if it's not a ligature
if (lpgm->gmBlackBoxX > tm.tmMaxCharWidth) {
lpgm->gmBlackBoxX = tm.tmMaxCharWidth;
}*/
lpgm->gmptGlyphOrigin.y += nDeltaY;
lpgm->gmBlackBoxY += nDeltaY;
if (tm.tmAscent - lpgm->gmptGlyphOrigin.y + lpgm->gmBlackBoxY - 1 < tm.tmHeight)
{
if (tm.tmAscent - lpgm->gmptGlyphOrigin.y + lpgm->gmBlackBoxY + 1 + nDeltaBlackY > tm.tmHeight)
lpgm->gmBlackBoxY = tm.tmHeight - tm.tmAscent + lpgm->gmptGlyphOrigin.y + 1;
else
lpgm->gmBlackBoxY += nDeltaBlackY;
}
}
}
return ret;
}
int WINAPI IMPL_GetTextFaceW( __in HDC hdc, __in int c, __out_ecount_part_opt(c, return) LPWSTR lpName)
{
int nSize = ORIG_GetTextFaceW(hdc, c, lpName);
LPCWSTR fontcache=GetCachedFontLocale(GetCurrentFont(hdc));
if (fontcache){
if (lpName) {
int len = Min(LF_FACESIZE, c);
StringCchCopy(lpName, len, fontcache);
nSize = (int)wcslen(fontcache) > len ? len : wcslen(fontcache) + 1;
}
else {
// a request for the size of font
nSize = Min(LF_FACESIZE, (int)wcslen(fontcache)+1);
}
}
return nSize;
}
int WINAPI IMPL_GetTextFaceA( __in HDC hdc, __in int c, __out_ecount_part_opt(c, return) LPSTR lpName)
{
int nSize = ORIG_GetTextFaceA(hdc, c, lpName);
LPCWSTR fontcache=GetCachedFontLocale(GetCurrentFont(hdc));
if (fontcache){
//int len=Min(LF_FACESIZE, c);
size_t _Dsize = 2 * wcslen(fontcache) + 1;
char *_Dest = new char[_Dsize];
memset(_Dest,0,_Dsize);
int len =wcstombs(_Dest, fontcache, _Dsize);
if (lpName)
StringCchCopyA(lpName, LF_FACESIZE, _Dest);
delete[] _Dest;
nSize = len+1;
}
return nSize;
}
HGDIOBJ WINAPI IMPL_GetStockObject(__in int i)
{
switch (i)
{
case DEFAULT_GUI_FONT:
{
static const CGdippSettings* pSetting = CGdippSettings::GetInstance();
if (g_alterGUIFont)
return g_alterGUIFont;
else
return ORIG_GetStockObject(i);
}
/*
case SYSTEM_FONT:
{
if (g_alterSysFont)
return g_alterSysFont;
break;
}*/
default: return ORIG_GetStockObject(i);
}
return ORIG_GetStockObject(i);
}
BOOL WINAPI IMPL_BeginPath(HDC hdc)
{
//CThreadCounter __counter;
BOOL ret=ORIG_BeginPath(hdc);
if (ret)
{
DCArray.insert(hdc);
}
return ret;
}
BOOL WINAPI IMPL_EndPath(HDC hdc)
{
//CThreadCounter __counter;
BOOL ret=ORIG_EndPath(hdc);
if (ret)
{
DCArray.erase(hdc);
}
return ret;
}
BOOL WINAPI IMPL_AbortPath(HDC hdc)
{
//CThreadCounter __counter;
BOOL ret=ORIG_AbortPath(hdc);
if (ret)
{
DCArray.erase(hdc);
}
return ret;
}
int WINAPI IMPL_GetObjectA(__in HANDLE h, __in int c, __out_bcount_opt(c) LPVOID pv)
{
int ret = ORIG_GetObjectA(h, c, pv);
if (ret==sizeof(LOGFONTA))
{
LPCWSTR fontcache = GetCachedFont((HFONT)h);
if (fontcache && pv)
{
size_t _Dsize = 2 * wcslen(fontcache) + 1;
char *_Dest = new char[_Dsize];
memset(_Dest,0,_Dsize);
wcstombs(_Dest,fontcache,_Dsize);
StringCchCopyA(((LOGFONTA*)pv)->lfFaceName, LF_FACESIZE, _Dest);
delete []_Dest;
}
}
return ret;
}
int WINAPI IMPL_GetObjectW(__in HANDLE h, __in int c, __out_bcount_opt(c) LPVOID pv)
{
int ret = ORIG_GetObjectW(h, c, pv);
if (ret==sizeof(LOGFONTW))
{
LPCWSTR fontcache = GetCachedFont((HFONT)h);
if (fontcache && pv)
{
StringCchCopyW(((LOGFONTW*)pv)->lfFaceName, LF_FACESIZE, fontcache);
}
}
return ret;
}
HFONT WINAPI IMPL_CreateFontIndirectExW(CONST ENUMLOGFONTEXDV *penumlfex)
{
if (!penumlfex) return NULL;
TRACE(L"Creating font \"%s\"\n", penumlfex->elfEnumLogfontEx.elfLogFont.lfFaceName);
{
if (penumlfex->elfEnumLogfontEx.elfLogFont.lfClipPrecision == FONT_MAGIC_NUMBER)
{
TRACE(L"Engine font, Ignored, ");
((ENUMLOGFONTEXDV *)penumlfex)->elfEnumLogfontEx.elfLogFont.lfClipPrecision = 0;
return ORIG_CreateFontIndirectExW(penumlfex);
}
}
/*
GetEnvironmentVariableW(L"MACTYPE_FONTSUBSTITUTES_ENV", NULL, 0);
if (GetLastError()!=ERROR_ENVVAR_NOT_FOUND)
return ORIG_CreateFontIndirectExW(penumlfex);*/
if(!penumlfex) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
const CGdippSettings* pSettings = CGdippSettings::GetInstance();
if (pSettings->IsFontExcluded(penumlfex->elfEnumLogfontEx.elfLogFont.lfFaceName)) {
TRACE(L"Font exception! ");
return ORIG_CreateFontIndirectExW(penumlfex);
//TRACE(L"Handle = %x\n" , (int)h);
}
ENUMLOGFONTEXDV mfont(*penumlfex);
LOGFONT& lf = mfont.elfEnumLogfontEx.elfLogFont;
LOGFONT lfOrg(lf);
BOOL bForced = false;
if (bForced = pSettings->CopyForceFont(lf, lfOrg)) {
/*
mfont->elfEnumLogfontEx.elfLogFont.lfHeight = lf.lfHeight;
// mfont->elfEnumLogfontEx.elfLogFont.lfWidth = lfOrg.lfWidth;
mfont->elfEnumLogfontEx.elfLogFont.lfWidth = lf.lfWidth;
mfont->elfEnumLogfontEx.elfLogFont.lfEscapement = lf.lfEscapement;
mfont->elfEnumLogfontEx.elfLogFont.lfOrientation = lf.lfOrientation;
mfont->elfEnumLogfontEx.elfLogFont.lfWeight = lf.lfWeight;
mfont->elfEnumLogfontEx.elfLogFont.lfItalic = lf.lfItalic;
mfont->elfEnumLogfontEx.elfLogFont.lfUnderline = lf.lfUnderline;
mfont->elfEnumLogfontEx.elfLogFont.lfStrikeOut = lf.lfStrikeOut;
mfont->elfEnumLogfontEx.elfLogFont.lfCharSet = lf.lfCharSet;
mfont->elfEnumLogfontEx.elfLogFont.lfOutPrecision = 0;
mfont->elfEnumLogfontEx.elfLogFont.lfClipPrecision = 0;
mfont->elfEnumLogfontEx.elfLogFont.lfQuality = 0;
mfont->elfEnumLogfontEx.elfLogFont.lfPitchAndFamily = 0;
StringCchCopy(mfont->elfEnumLogfontEx.elfLogFont.lfFaceName, LF_FACESIZE, lf.lfFaceName);*/
TRACE(L"Font substitutes to \"%s\"\n", lf.lfFaceName);
}
else
TRACE(L"Normal font\n");
//bypass = true;
HFONT hf = ORIG_CreateFontIndirectExW(&mfont);
//ORIG_CreateFontIndirectExW(
//if(hf && lplf && !pSettings->LoadOnDemand()) {
// AddFontToFT(lplf->lfFaceName, lplf->lfWeight, !!lplf->lfItalic);
//}
if (hf && bForced) {
AddToCachedFont(hf, (WCHAR*)penumlfex->elfEnumLogfontEx.elfLogFont.lfFaceName, (WCHAR *)lfOrg.lfFaceName);
}
//bypass = false;
TRACE(L"Create font %s handle %x\n", lfOrg.lfFaceName, (int)hf);
return hf;
}
BOOL WINAPI IMPL_DeleteObject(HGDIOBJ hObject)
{
//CThreadCounter __counter;
if (hObject == g_alterGUIFont) //我的系统字体,不可以释放掉
return true;
BOOL bResult = ORIG_DeleteObject(hObject);
if (bResult) DeleteCachedFont((HFONT)hObject);
return bResult;
}
HFONT WINAPI IMPL_CreateFontIndirectW(CONST LOGFONTW *lplf) //重新启用这个hook,只为兼容搜狗输入法
{
ENUMLOGFONTEXDVW envlf = {0};
memcpy(&envlf.elfEnumLogfontEx.elfLogFont, lplf, sizeof(LOGFONTW));
return IMPL_CreateFontIndirectExW(&envlf);
}
/*
BOOL WINAPI IMPL_DrawStateA(HDC hdc, HBRUSH hbr, DRAWSTATEPROC lpOutputFunc, LPARAM lData, WPARAM wData, int x, int y, int cx, int cy, UINT uFlags)
{
//CThreadCounter __counter;
int cchW;
LPWSTR lpStringW;
if(lData && uFlags & DSS_DISABLED) {
switch(uFlags & 0x0f) {
case DST_TEXT:
case DST_PREFIXTEXT:
lpStringW = _StrDupAtoW((LPCSTR)lData, wData ? wData : -1, &cchW);
if(lpStringW) {
BOOL ret = IMPL_DrawStateW(hdc, hbr, lpOutputFunc, (LPARAM)lpStringW, cchW, x, y, cx, cy, uFlags);
free(lpStringW);
return ret;
}
break;
}
}
return ORIG_DrawStateA(hdc, hbr, lpOutputFunc, lData, wData, x, y, cx, cy, uFlags);
}
//灰色描画をDrawTextへ投げる
//DrawTextは内部でExtTextOutしてくれるので問題なし
BOOL WINAPI IMPL_DrawStateW(HDC hdc, HBRUSH hbr, DRAWSTATEPROC lpOutputFunc, LPARAM lData, WPARAM wData, int x, int y, int cx, int cy, UINT uFlags)
{
//CThreadCounter __counter;
if(lData && uFlags & DSS_DISABLED) {
switch(uFlags & 0x0f) {
case DST_TEXT:
case DST_PREFIXTEXT:
{
//wData==0の時に文字数自動計算
//他のAPIと違って-1の時ではない
if(wData == 0) {
wData = wcslen((LPCWSTR)lData);
}
RECT rect = { x, y, x + 10000, y + 10000 };
//どうやら3DHighLightの上に1pxずらして3DShadowを重ねてるらしい
int oldbm = SetBkMode(hdc, TRANSPARENT);
COLORREF oldfg = SetTextColor(hdc, GetSysColor(COLOR_3DHIGHLIGHT));
//DrawStateとDrawTextではprefixのフラグが逆(APIの設計ダメすぎ)
const UINT uDTFlags = DT_SINGLELINE | DT_NOCLIP | (uFlags & DST_PREFIXTEXT ? 0 : DT_NOPREFIX);
OffsetRect(&rect, 1, 1);
DrawTextW(hdc, (LPCWSTR)lData, wData, &rect, uDTFlags);
SetTextColor(hdc, GetSysColor(COLOR_3DSHADOW));
OffsetRect(&rect, -1, -1);
DrawTextW(hdc, (LPCWSTR)lData, wData, &rect, uDTFlags);
SetTextColor(hdc, oldfg);
SetBkMode(hdc, oldbm);
}
return TRUE;
}
}
return ORIG_DrawStateW(hdc, hbr, lpOutputFunc, lData, wData, x, y, cx, cy, uFlags);
}*/
class FreeTypeFontEngine;
extern FreeTypeFontEngine* g_pFTEngine;
BOOL __stdcall IMPL_RemoveFontResourceExW(__in LPCWSTR name, __in DWORD fl, __reserved PVOID pdv)
{
g_pFTEngine->RemoveFont(name);
return ORIG_RemoveFontResourceExW(name, fl, pdv);
}
/*
BOOL __stdcall IMPL_RemoveFontResourceW(__in LPCWSTR lpFileName)
{
g_pFTEngine->RemoveFont(lpFileName);
return ORIG_RemoveFontResourceW(lpFileName);
}*/
BOOL WINAPI IMPL_TextOutA(HDC hdc, int nXStart, int nYStart, LPCSTR lpString, int cbString)
{
//CThreadCounter __counter;
return IMPL_ExtTextOutA(hdc, nXStart, nYStart, NULL, NULL, lpString, cbString, NULL);
}
BOOL WINAPI IMPL_TextOutW(HDC hdc, int nXStart, int nYStart, LPCWSTR lpString, int cbString)
{
//CThreadCounter __counter;
return IMPL_ExtTextOutW(hdc, nXStart, nYStart, NULL, NULL, lpString, cbString, NULL);
}
void AnsiDxToUnicodeDx(LPCSTR lpStringA, int cbString, const int* lpDxA, int* lpDxW, int ACP)
{
LPCSTR lpEndA = lpStringA + cbString;
while(lpStringA < lpEndA) {
*lpDxW = *lpDxA++;
if(IsDBCSLeadByteEx(ACP, *lpStringA)) {
*lpDxW += *lpDxA++;
lpStringA++;
}
lpDxW++;
lpStringA++;
}
}
// ANSI->Unicodeに変換してExtTextOutWに投げるExtTextOutA
BOOL WINAPI IMPL_ExtTextOutA(HDC hdc, int nXStart, int nYStart, UINT fuOptions, CONST RECT *lprc, LPCSTR lpString, UINT cbString, CONST INT *lpDx)
{
//CThreadCounter __counter;
if (!hdc || !lpString || !cbString || !g_ccbRender || !(fuOptions & ETO_IGNORELANGUAGE)) {
return ORIG_ExtTextOutA(hdc, nXStart, nYStart, fuOptions, lprc, lpString, cbString, lpDx);
}
//However, if the ANSI version of ExtTextOut is called with ETO_GLYPH_INDEX,
//the function returns TRUE even though the function does nothing.
//とりあえずオリジナルに飛ばす
if (fuOptions & ETO_GLYPH_INDEX)
return ORIG_ExtTextOutA(hdc, nXStart, nYStart, fuOptions, lprc, lpString, cbString, lpDx);
//HDBENCHチート
// if (lpString && cbString == 7 && pSettings->IsHDBench() && (memcmp(lpString, "HDBENCH", 7) == 0 || memcmp(lpString, " ", 7) == 0))
// return ORIG_ExtTextOutA(hdc, nXStart, nYStart, fuOptions, lprc, lpString, cbString, lpDx);
LPWSTR lpszUnicode;
int bufferLength;
BOOL result;
WCHAR szStack[CCH_MAX_STACK];
int dxStack[CCH_MAX_STACK];
int nACP = GdiGetCodePage(hdc);//CP_ACP;
//DWORD nCharset = GetTextCharsetInfo(hdc, NULL, 0);
/*
switch (nCharset)
{
case 0:
{
break;
}
case SYMBOL_CHARSET:
{
nACP = CP_SYMBOL;
break;
}
case MAC_CHARSET:
{
nACP = CP_MACCP;
break;
}
case OEM_CHARSET:
{
nACP = CP_OEMCP;
break;
}
default:
{
CHARSETINFO Cs={0,CP_ACP,0};
TranslateCharsetInfo((DWORD*)nCharset, &Cs, TCI_SRCCHARSET);
nACP = Cs.ciACP;
}
}*/
lpszUnicode = _StrDupExAtoW(lpString, cbString, szStack, CCH_MAX_STACK, &bufferLength, nACP);
if(!lpszUnicode) {
//メモリ不足: 一応オリジナルに投げとく
return ORIG_ExtTextOutA(hdc, nXStart, nYStart, fuOptions, lprc, lpString, cbString, lpDx);
}
int* lpDxW = NULL;
result = FALSE;
if(lpDx && cbString && _getmbcp()) {
if (cbString < CCH_MAX_STACK) {
lpDxW = dxStack;
ZeroMemory(lpDxW, sizeof(int) * cbString);
} else {
lpDxW = (int*)calloc(sizeof(int), cbString);
if (!lpDxW) {
goto CleanUp;
}
}
if (nACP!=CP_SYMBOL)
{
AnsiDxToUnicodeDx(lpString, cbString, lpDx, lpDxW, nACP);
lpDx = lpDxW;
}
}
result = IMPL_ExtTextOutW(hdc, nXStart, nYStart, fuOptions, lprc, (LPCWSTR)lpszUnicode, bufferLength, lpDx);
CleanUp:
if (lpszUnicode != szStack)
free(lpszUnicode);
if (lpDxW != dxStack)
free(lpDxW);
return result;
}
typedef enum {
ETOE_OK = 0,
ETOE_CREATEDC = 1,
ETOE_SETFONT = 2,
ETOE_CREATEDIB = 3,
ETOE_FREETYPE = 4,
ETOE_INVALIDARG = 11,
ETOE_ROTATION = 12,
ETOE_LARGESIZE = 13,
ETOE_INVALIDHDC = 14,
ETOE_ROTATEFONT = 15,
ETOE_NOAREA = 16,
ETOE_GETTEXTEXTENT = 17,
ETOE_MONO = 18,
ETOE_GENERAL = 19,
} ExtTextOut_ErrorCode;
//例外モドキ
#define ETO_TRY() ExtTextOut_ErrorCode error = ETOE_OK; {
#define ETO_THROW(code) error = (code); goto _EXCEPTION_THRU
#define ETO_CATCH() } _EXCEPTION_THRU:
/*