This repository was archived by the owner on Jan 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
/
Copy pathutilcode.h
5527 lines (4660 loc) · 175 KB
/
utilcode.h
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
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//*****************************************************************************
// UtilCode.h
//
// Utility functions implemented in UtilCode.lib.
//
//*****************************************************************************
#ifndef __UtilCode_h__
#define __UtilCode_h__
#include "crtwrap.h"
#include "winwrap.h"
#include <wchar.h>
#include <stdio.h>
#include <malloc.h>
#include <ole2.h>
#include <oleauto.h>
#include <limits.h>
#include "clrtypes.h"
#include "safewrap.h"
#include "volatile.h"
#include <daccess.h>
#include "clrhost.h"
#include "debugmacros.h"
#include "corhlprpriv.h"
#include "winnls.h"
#include "check.h"
#include "safemath.h"
#include "new.hpp"
#ifdef PAL_STDCPP_COMPAT
#include <type_traits>
#else
#include "clr_std/type_traits"
#endif
#include "contract.h"
#include "entrypoints.h"
#include "clrnt.h"
// Values for the names of Watson
const WCHAR kWatsonName1[] = W("drwatson");
const WCHAR kWatsonName2[] = W("drwtsn32");
#include "random.h"
#define WINDOWS_KERNEL32_DLLNAME_A "kernel32"
#define WINDOWS_KERNEL32_DLLNAME_W W("kernel32")
#define CoreLibName_W W("System.Private.CoreLib")
#define CoreLibName_IL_W W("System.Private.CoreLib.dll")
#define CoreLibName_NI_W W("System.Private.CoreLib.ni.dll")
#define CoreLibName_TLB_W W("System.Private.CoreLib.tlb")
#define CoreLibName_A "System.Private.CoreLib"
#define CoreLibName_IL_A "System.Private.CoreLib.dll"
#define CoreLibName_NI_A "System.Private.CoreLib.ni.dll"
#define CoreLibName_TLB_A "System.Private.CoreLib.tlb"
#define CoreLibNameLen 22
#define CoreLibSatelliteName_A "System.Private.CoreLib.resources"
#define CoreLibSatelliteNameLen 32
#define LegacyCoreLibName_A "mscorlib"
class StringArrayList;
#if !defined(_DEBUG_IMPL) && defined(_DEBUG) && !defined(DACCESS_COMPILE)
#define _DEBUG_IMPL 1
#endif
#ifdef _TARGET_ARM_
// Under ARM we generate code only with Thumb encoding. In order to ensure we execute such code in the correct
// mode we must ensure the low-order bit is set in any code address we'll call as a sub-routine. In C++ this
// is handled automatically for us by the compiler. When generating and working with code generated
// dynamically we have to be careful to set or mask-out this bit as appropriate.
#ifndef THUMB_CODE
#define THUMB_CODE 1
#endif
// Given a WORD extract the bitfield [lowbit, highbit] (i.e. BitExtract(0xffff, 15, 0) == 0xffff).
inline WORD BitExtract(WORD wValue, DWORD highbit, DWORD lowbit)
{
_ASSERTE((highbit < 16) && (lowbit < 16) && (highbit >= lowbit));
return (wValue >> lowbit) & ((1 << ((highbit - lowbit) + 1)) - 1);
}
// Determine whether an ARM Thumb mode instruction is 32-bit or 16-bit based on the first WORD of the
// instruction.
inline bool Is32BitInstruction(WORD opcode)
{
return BitExtract(opcode, 15, 11) >= 0x1d;
}
template <typename ResultType, typename SourceType>
inline ResultType DataPointerToThumbCode(SourceType pCode)
{
return (ResultType)(((UINT_PTR)pCode) | THUMB_CODE);
}
template <typename ResultType, typename SourceType>
inline ResultType ThumbCodeToDataPointer(SourceType pCode)
{
return (ResultType)(((UINT_PTR)pCode) & ~THUMB_CODE);
}
#endif // _TARGET_ARM_
// Convert from a PCODE to the corresponding PINSTR. On many architectures this will be the identity function;
// on ARM, this will mask off the THUMB bit.
inline TADDR PCODEToPINSTR(PCODE pc)
{
#ifdef _TARGET_ARM_
return ThumbCodeToDataPointer<TADDR,PCODE>(pc);
#else
return dac_cast<PCODE>(pc);
#endif
}
// Convert from a PINSTR to the corresponding PCODE. On many architectures this will be the identity function;
// on ARM, this will raise the THUMB bit.
inline PCODE PINSTRToPCODE(TADDR addr)
{
#ifdef _TARGET_ARM_
return DataPointerToThumbCode<PCODE,TADDR>(addr);
#else
return dac_cast<PCODE>(addr);
#endif
}
typedef LPCSTR LPCUTF8;
typedef LPSTR LPUTF8;
#include "nsutilpriv.h"
#include "stdmacros.h"
/*
// This is for WinCE
#ifdef VERIFY
#undef VERIFY
#endif
#ifdef _ASSERTE
#undef _ASSERTE
#endif
*/
//********** Macros. **********************************************************
#ifndef FORCEINLINE
#if _MSC_VER < 1200
#define FORCEINLINE inline
#else
#define FORCEINLINE __forceinline
#endif
#endif
#ifndef DEBUG_NOINLINE
#if defined(_DEBUG)
#define DEBUG_NOINLINE __declspec(noinline)
#else
#define DEBUG_NOINLINE
#endif
#endif
#ifndef DBG_NOINLINE_X86__RET_INLINE
#if defined(_DEBUG) && defined(_TARGET_X86_)
// this exists to make scan work on x86.
#define DBG_NOINLINE_X86__RET_INLINE __declspec(noinline)
#else
#define DBG_NOINLINE_X86__RET_INLINE FORCEINLINE
#endif
#endif
#include <stddef.h> // for offsetof
#ifndef NumItems
// Number of elements in a fixed-size array
#define NumItems(s) (sizeof(s) / sizeof(s[0]))
#endif
#ifndef StrLen
// Number of characters in a string literal. Excludes terminating NULL.
#define StrLen(str) (NumItems(str) - 1)
#endif
#define IS_DIGIT(ch) ((ch >= W('0')) && (ch <= W('9')))
#define DIGIT_TO_INT(ch) (ch - W('0'))
#define INT_TO_DIGIT(i) ((WCHAR)(W('0') + i))
#define IS_HEXDIGIT(ch) (((ch >= W('a')) && (ch <= W('f'))) || \
((ch >= W('A')) && (ch <= W('F'))))
#define HEXDIGIT_TO_INT(ch) ((towlower(ch) - W('a')) + 10)
#define INT_TO_HEXDIGIT(i) ((WCHAR)(W('a') + (i - 10)))
// Helper will 4 byte align a value, rounding up.
#define ALIGN4BYTE(val) (((val) + 3) & ~0x3)
#ifdef _DEBUG
#define DEBUGARG(x) , x
#else
#define DEBUGARG(x)
#endif
#ifndef sizeofmember
// Returns the size of a class or struct member.
#define sizeofmember(c,m) (sizeof(((c*)0)->m))
#endif
//=--------------------------------------------------------------------------=
// Prefast helpers.
//
#include "safemath.h"
//=--------------------------------------------------------------------------=
// string helpers.
//
// given and ANSI String, copy it into a wide buffer.
// be careful about scoping when using this macro!
//
// how to use the below two macros:
//
// ...
// LPSTR pszA;
// pszA = MyGetAnsiStringRoutine();
// MAKE_WIDEPTR_FROMANSI(pwsz, pszA);
// MyUseWideStringRoutine(pwsz);
// ...
//
// similarily for MAKE_ANSIPTR_FROMWIDE. note that the first param does not
// have to be declared, and no clean up must be done.
//
// We'll define an upper limit that allows multiplication by 4 (the max
// bytes/char in UTF-8) but still remains positive, and allows some room for pad.
// Under normal circumstances, we should never get anywhere near this limit.
#define MAKE_MAX_LENGTH 0x1fffff00
#ifndef MAKE_TOOLONGACTION
#define MAKE_TOOLONGACTION ThrowHR(COR_E_OVERFLOW)
#endif
#ifndef MAKE_TRANSLATIONFAILED
#define MAKE_TRANSLATIONFAILED ThrowWin32(ERROR_NO_UNICODE_TRANSLATION)
#endif
// This version throws on conversion errors (ie, no best fit character
// mapping to characters that look similar, and no use of the default char
// ('?') when printing out unrepresentable characters. Use this method for
// most development in the EE, especially anything like metadata or class
// names. See the BESTFIT version if you're printing out info to the console.
#define MAKE_MULTIBYTE_FROMWIDE(ptrname, widestr, codepage) \
int __l##ptrname = (int)wcslen(widestr); \
if (__l##ptrname > MAKE_MAX_LENGTH) \
MAKE_TOOLONGACTION; \
__l##ptrname = (int)((__l##ptrname + 1) * 2 * sizeof(char)); \
CQuickBytes __CQuickBytes##ptrname; \
__CQuickBytes##ptrname.AllocThrows(__l##ptrname); \
BOOL __b##ptrname; \
DWORD __cBytes##ptrname = WszWideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, widestr, -1, (LPSTR)__CQuickBytes##ptrname.Ptr(), __l##ptrname, NULL, &__b##ptrname); \
if (__b##ptrname || (__cBytes##ptrname == 0 && (widestr[0] != W('\0')))) { \
MAKE_TRANSLATIONFAILED; \
} \
LPSTR ptrname = (LPSTR)__CQuickBytes##ptrname.Ptr()
// This version does best fit character mapping and also allows the use
// of the default char ('?') for any Unicode character that isn't
// representable. This is reasonable for writing to the console, but
// shouldn't be used for most string conversions.
#define MAKE_MULTIBYTE_FROMWIDE_BESTFIT(ptrname, widestr, codepage) \
int __l##ptrname = (int)wcslen(widestr); \
if (__l##ptrname > MAKE_MAX_LENGTH) \
MAKE_TOOLONGACTION; \
__l##ptrname = (int)((__l##ptrname + 1) * 2 * sizeof(char)); \
CQuickBytes __CQuickBytes##ptrname; \
__CQuickBytes##ptrname.AllocThrows(__l##ptrname); \
DWORD __cBytes##ptrname = WszWideCharToMultiByte(codepage, 0, widestr, -1, (LPSTR)__CQuickBytes##ptrname.Ptr(), __l##ptrname, NULL, NULL); \
if (__cBytes##ptrname == 0 && __l##ptrname != 0) { \
MAKE_TRANSLATIONFAILED; \
} \
LPSTR ptrname = (LPSTR)__CQuickBytes##ptrname.Ptr()
// Use for anything critical other than output to console, where weird
// character mappings are unacceptable.
#define MAKE_ANSIPTR_FROMWIDE(ptrname, widestr) MAKE_MULTIBYTE_FROMWIDE(ptrname, widestr, CP_ACP)
// Use for output to the console.
#define MAKE_ANSIPTR_FROMWIDE_BESTFIT(ptrname, widestr) MAKE_MULTIBYTE_FROMWIDE_BESTFIT(ptrname, widestr, CP_ACP)
#define MAKE_WIDEPTR_FROMANSI(ptrname, ansistr) \
CQuickBytes __qb##ptrname; \
int __l##ptrname; \
__l##ptrname = WszMultiByteToWideChar(CP_ACP, 0, ansistr, -1, 0, 0); \
if (__l##ptrname > MAKE_MAX_LENGTH) \
MAKE_TOOLONGACTION; \
LPWSTR ptrname = (LPWSTR) __qb##ptrname.AllocThrows((__l##ptrname+1)*sizeof(WCHAR)); \
if (WszMultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, ansistr, -1, ptrname, __l##ptrname) == 0) { \
MAKE_TRANSLATIONFAILED; \
}
#define MAKE_WIDEPTR_FROMANSI_NOTHROW(ptrname, ansistr) \
CQuickBytes __qb##ptrname; \
LPWSTR ptrname = 0; \
int __l##ptrname; \
__l##ptrname = WszMultiByteToWideChar(CP_ACP, 0, ansistr, -1, 0, 0); \
if (__l##ptrname <= MAKE_MAX_LENGTH) { \
ptrname = (LPWSTR) __qb##ptrname.AllocNoThrow((__l##ptrname+1)*sizeof(WCHAR)); \
if (ptrname) { \
if (WszMultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, ansistr, -1, ptrname, __l##ptrname) != 0) { \
ptrname[__l##ptrname] = 0; \
} else { \
ptrname = 0; \
} \
} \
}
#define MAKE_UTF8PTR_FROMWIDE(ptrname, widestr) CQuickBytes _##ptrname; _##ptrname.ConvertUnicode_Utf8(widestr); LPSTR ptrname = (LPSTR) _##ptrname.Ptr();
#define MAKE_UTF8PTR_FROMWIDE_NOTHROW(ptrname, widestr) \
CQuickBytes __qb##ptrname; \
int __l##ptrname = (int)wcslen(widestr); \
LPUTF8 ptrname = 0; \
if (__l##ptrname <= MAKE_MAX_LENGTH) { \
__l##ptrname = (int)((__l##ptrname + 1) * 2 * sizeof(char)); \
ptrname = (LPUTF8) __qb##ptrname.AllocNoThrow(__l##ptrname); \
} \
if (ptrname) { \
INT32 __lresult##ptrname=WszWideCharToMultiByte(CP_UTF8, 0, widestr, -1, ptrname, __l##ptrname-1, NULL, NULL); \
DWORD __dwCaptureLastError##ptrname = ::GetLastError(); \
if ((__lresult##ptrname==0) && (((LPCWSTR)widestr)[0] != W('\0'))) { \
if (__dwCaptureLastError##ptrname==ERROR_INSUFFICIENT_BUFFER) { \
INT32 __lsize##ptrname=WszWideCharToMultiByte(CP_UTF8, 0, widestr, -1, NULL, 0, NULL, NULL); \
ptrname = (LPSTR) __qb##ptrname .AllocNoThrow(__lsize##ptrname); \
if (ptrname) { \
if (WszWideCharToMultiByte(CP_UTF8, 0, widestr, -1, ptrname, __lsize##ptrname, NULL, NULL) != 0) { \
ptrname[__l##ptrname] = 0; \
} else { \
ptrname = 0; \
} \
} \
} \
else { \
ptrname = 0; \
} \
} \
} \
#define MAKE_WIDEPTR_FROMUTF8N(ptrname, utf8str, n8chrs) \
CQuickBytes __qb##ptrname; \
int __l##ptrname; \
__l##ptrname = WszMultiByteToWideChar(CP_UTF8, 0, utf8str, n8chrs, 0, 0); \
if (__l##ptrname > MAKE_MAX_LENGTH) \
MAKE_TOOLONGACTION; \
LPWSTR ptrname = (LPWSTR) __qb##ptrname .AllocThrows((__l##ptrname+1)*sizeof(WCHAR)); \
if (0==WszMultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8str, n8chrs, ptrname, __l##ptrname)) { \
MAKE_TRANSLATIONFAILED; \
} \
ptrname[__l##ptrname] = 0;
#define MAKE_WIDEPTR_FROMUTF8(ptrname, utf8str) CQuickBytes _##ptrname; _##ptrname.ConvertUtf8_Unicode(utf8str); LPCWSTR ptrname = (LPCWSTR) _##ptrname.Ptr();
#define MAKE_WIDEPTR_FROMUTF8N_NOTHROW(ptrname, utf8str, n8chrs) \
CQuickBytes __qb##ptrname; \
int __l##ptrname; \
LPWSTR ptrname = 0; \
__l##ptrname = WszMultiByteToWideChar(CP_UTF8, 0, utf8str, n8chrs, 0, 0); \
if (__l##ptrname <= MAKE_MAX_LENGTH) { \
ptrname = (LPWSTR) __qb##ptrname.AllocNoThrow((__l##ptrname+1)*sizeof(WCHAR)); \
if (ptrname) { \
if (WszMultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8str, n8chrs, ptrname, __l##ptrname) != 0) { \
ptrname[__l##ptrname] = 0; \
} else { \
ptrname = 0; \
} \
} \
}
#define MAKE_WIDEPTR_FROMUTF8_NOTHROW(ptrname, utf8str) MAKE_WIDEPTR_FROMUTF8N_NOTHROW(ptrname, utf8str, -1)
// This method takes the number of characters
#define MAKE_MULTIBYTE_FROMWIDEN(ptrname, widestr, _nCharacters, _pCnt, codepage) \
CQuickBytes __qb##ptrname; \
int __l##ptrname; \
__l##ptrname = WszWideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, widestr, _nCharacters, NULL, 0, NULL, NULL); \
if (__l##ptrname > MAKE_MAX_LENGTH) \
MAKE_TOOLONGACTION; \
ptrname = (LPUTF8) __qb##ptrname .AllocThrows(__l##ptrname+1); \
BOOL __b##ptrname; \
DWORD _pCnt = WszWideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, widestr, _nCharacters, ptrname, __l##ptrname, NULL, &__b##ptrname); \
if (__b##ptrname || (_pCnt == 0 && _nCharacters > 0)) { \
MAKE_TRANSLATIONFAILED; \
} \
ptrname[__l##ptrname] = 0;
#define MAKE_MULTIBYTE_FROMWIDEN_BESTFIT(ptrname, widestr, _nCharacters, _pCnt, codepage) \
CQuickBytes __qb##ptrname; \
int __l##ptrname; \
__l##ptrname = WszWideCharToMultiByte(codepage, 0, widestr, _nCharacters, NULL, 0, NULL, NULL); \
if (__l##ptrname > MAKE_MAX_LENGTH) \
MAKE_TOOLONGACTION; \
ptrname = (LPUTF8) __qb##ptrname .AllocThrows(__l##ptrname+1); \
DWORD _pCnt = WszWideCharToMultiByte(codepage, 0, widestr, _nCharacters, ptrname, __l##ptrname, NULL, NULL); \
if (_pCnt == 0 && _nCharacters > 0) { \
MAKE_TRANSLATIONFAILED; \
} \
ptrname[__l##ptrname] = 0;
#define MAKE_ANSIPTR_FROMWIDEN(ptrname, widestr, _nCharacters, _pCnt) \
MAKE_MULTIBYTE_FROMWIDEN(ptrname, widestr, _nCharacters, _pCnt, CP_ACP)
inline
LPWSTR DuplicateString(
LPCWSTR wszString,
size_t cchString)
{
STATIC_CONTRACT_NOTHROW;
LPWSTR wszDup = NULL;
if (wszString != NULL)
{
wszDup = new (nothrow) WCHAR[cchString + 1];
if (wszDup != NULL)
{
wcscpy_s(wszDup, cchString + 1, wszString);
}
}
return wszDup;
}
inline
LPWSTR DuplicateString(
LPCWSTR wszString)
{
STATIC_CONTRACT_NOTHROW;
if (wszString != NULL)
{
return DuplicateString(wszString, wcslen(wszString));
}
else
{
return NULL;
}
}
void DECLSPEC_NORETURN ThrowOutOfMemory();
inline
LPWSTR DuplicateStringThrowing(
LPCWSTR wszString,
size_t cchString)
{
STATIC_CONTRACT_THROWS;
if (wszString == NULL)
return NULL;
LPWSTR wszDup = DuplicateString(wszString, cchString);
if (wszDup == NULL)
ThrowOutOfMemory();
return wszDup;
}
inline
LPWSTR DuplicateStringThrowing(
LPCWSTR wszString)
{
STATIC_CONTRACT_THROWS;
if (wszString == NULL)
return NULL;
LPWSTR wszDup = DuplicateString(wszString);
if (wszDup == NULL)
ThrowOutOfMemory();
return wszDup;
}
//*****************************************************************************
// Placement new is used to new and object at an exact location. The pointer
// is simply returned to the caller without actually using the heap. The
// advantage here is that you cause the ctor() code for the object to be run.
// This is ideal for heaps of C++ objects that need to get init'd multiple times.
// Example:
// void *pMem = GetMemFromSomePlace();
// Foo *p = new (pMem) Foo;
// DoSomething(p);
// p->~Foo();
//*****************************************************************************
#ifndef __PLACEMENT_NEW_INLINE
#define __PLACEMENT_NEW_INLINE
inline void *__cdecl operator new(size_t, void *_P)
{
LIMITED_METHOD_DAC_CONTRACT;
return (_P);
}
#endif // __PLACEMENT_NEW_INLINE
/********************************************************************************/
/* portability helpers */
#ifdef _WIN64
#define IN_WIN64(x) x
#define IN_WIN32(x)
#else
#define IN_WIN64(x)
#define IN_WIN32(x) x
#endif
void * __cdecl
operator new(size_t n);
_Ret_bytecap_(n) void * __cdecl
operator new[](size_t n);
void __cdecl
operator delete(void *p) NOEXCEPT;
void __cdecl
operator delete[](void *p) NOEXCEPT;
#ifdef _DEBUG_IMPL
HRESULT _OutOfMemory(LPCSTR szFile, int iLine);
#define OutOfMemory() _OutOfMemory(__FILE__, __LINE__)
#else
inline HRESULT OutOfMemory()
{
LIMITED_METHOD_CONTRACT;
return (E_OUTOFMEMORY);
}
#endif
//*****************************************************************************
// Handle accessing localizable resource strings
//*****************************************************************************
// NOTE: Should use locale names as much as possible. LCIDs don't support
// custom cultures on Vista+.
// TODO: This should always use the names
#ifdef FEATURE_USE_LCID
typedef LCID LocaleID;
typedef LCID LocaleIDValue;
#else
typedef LPCWSTR LocaleID;
typedef WCHAR LocaleIDValue[LOCALE_NAME_MAX_LENGTH];
#endif
// Notes about the culture callbacks:
// - The language we're operating in can change at *runtime*!
// - A process may operate in *multiple* languages.
// (ex: Each thread may have it's own language)
// - If we don't care what language we're in (or have no way of knowing),
// then return a 0-length name and UICULTUREID_DONTCARE for the culture ID.
// - GetCultureName() and the GetCultureId() must be in sync (refer to the
// same language).
// - We have two functions separate functions for better performance.
// - The name is used to resolve a directory for MsCorRC.dll.
// - The id is used as a key to map to a dll hinstance.
// Callback to obtain both the culture name and the culture's parent culture name
typedef HRESULT (*FPGETTHREADUICULTURENAMES)(__inout StringArrayList* pCultureNames);
#ifdef FEATURE_USE_LCID
// Callback to return the culture ID.
const LCID UICULTUREID_DONTCARE = (LCID)-1;
#else
const LPCWSTR UICULTUREID_DONTCARE = NULL;
#endif
typedef int (*FPGETTHREADUICULTUREID)(LocaleIDValue*);
HMODULE CLRLoadLibrary(LPCWSTR lpLibFileName);
HMODULE CLRLoadLibraryEx(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
BOOL CLRFreeLibrary(HMODULE hModule);
// Prevent people from using LoadStringRC & LoadStringRCEx from inside the product since it
// causes issues with having the wrong version picked up inside the shim.
#define LoadStringRC __error("From inside the CLR, use UtilLoadStringRC; LoadStringRC is only meant to be exported.")
#define LoadStringRCEx __error("From inside the CLR, use UtilLoadStringRCEx; LoadStringRC is only meant to be exported.")
// Load a string using the resources for the current module.
STDAPI UtilLoadStringRC(UINT iResouceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax, int bQuiet=FALSE);
#if defined(ENABLE_DOWNLEVEL_FOR_NLS) || defined(FEATURE_USE_LCID)
STDAPI UtilLoadStringRCEx(LCID lcid, UINT iResourceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax, int bQuiet, int *pcwchUsed);
#endif
// Specify callbacks so that UtilLoadStringRC can find out which language we're in.
// If no callbacks specified (or both parameters are NULL), we default to the
// resource dll in the root (which is probably english).
void SetResourceCultureCallbacks(
FPGETTHREADUICULTURENAMES fpGetThreadUICultureNames,
FPGETTHREADUICULTUREID fpGetThreadUICultureId
);
void GetResourceCultureCallbacks(
FPGETTHREADUICULTURENAMES* fpGetThreadUICultureNames,
FPGETTHREADUICULTUREID* fpGetThreadUICultureId
);
#if !defined(DACCESS_COMPILE)
// Get the MUI ID, on downlevel platforms where MUI is not supported it
// returns the default system ID.
extern int GetMUILanguageID(LocaleIDValue* pResult);
extern HRESULT GetMUILanguageNames(__inout StringArrayList* pCultureNames);
#endif // !defined(DACCESS_COMPILE)
//*****************************************************************************
// Use this class by privately deriving from noncopyable to disallow copying of
// your class.
//*****************************************************************************
class noncopyable
{
protected:
noncopyable()
{}
~noncopyable()
{}
private:
noncopyable(const noncopyable&);
const noncopyable& operator=(const noncopyable&);
};
//*****************************************************************************
// Must associate each handle to an instance of a resource dll with the int
// that it represents
//*****************************************************************************
typedef HINSTANCE HRESOURCEDLL;
class CCulturedHInstance
{
LocaleIDValue m_LangId;
HRESOURCEDLL m_hInst;
BOOL m_fMissing;
public:
CCulturedHInstance()
{
LIMITED_METHOD_CONTRACT;
m_hInst = NULL;
m_fMissing = FALSE;
}
BOOL HasID(LocaleID id)
{
_ASSERTE(m_hInst != NULL || m_fMissing);
if (id == UICULTUREID_DONTCARE)
return FALSE;
#ifdef FEATURE_USE_LCID
return id == m_LangId;
#else
return wcscmp(id, m_LangId) == 0;
#endif
}
HRESOURCEDLL GetLibraryHandle()
{
return m_hInst;
}
BOOL IsSet()
{
return m_hInst != NULL;
}
BOOL IsMissing()
{
return m_fMissing;
}
void SetMissing(LocaleID id)
{
_ASSERTE(m_hInst == NULL);
SetId(id);
m_fMissing = TRUE;
}
void Set(LocaleID id, HRESOURCEDLL hInst)
{
_ASSERTE(m_hInst == NULL);
_ASSERTE(m_fMissing == FALSE);
SetId(id);
m_hInst = hInst;
}
private:
void SetId(LocaleID id)
{
#ifdef FEATURE_USE_LCID
m_LangId = id;
#else
if (id != UICULTUREID_DONTCARE)
{
wcsncpy_s(m_LangId, NumItems(m_LangId), id, NumItems(m_LangId));
m_LangId[NumItems(m_LangId)-1] = W('\0');
}
else
{
m_LangId[0] = W('\0');
}
#endif
}
};
#ifndef DACCESS_COMPILE
void AddThreadPreferredUILanguages(StringArrayList* pArray);
#endif
//*****************************************************************************
// CCompRC manages string Resource access for COM+. This includes loading
// the MsCorRC.dll for resources as well allowing each thread to use a
// a different localized version.
//*****************************************************************************
class CCompRC
{
public:
enum ResourceCategory
{
// must be present
Required,
// present in Desktop CLR and Core CLR + debug pack, an error
// If missing, get a generic error message instead
Error,
// present in Desktop CLR and Core CLR + debug pack, normal operation (e.g tracing)
// if missing, get a generic "resource not found" message instead
Debugging,
// present in Desktop CLR, optional for CoreCLR
DesktopCLR,
// might not be present, non essential
Optional
};
CCompRC()
{
// This constructor will be fired up on startup. Make sure it doesn't
// do anything besides zero-out out values.
m_bUseFallback = FALSE;
m_fpGetThreadUICultureId = NULL;
m_fpGetThreadUICultureNames = NULL;
m_pHash = NULL;
m_nHashSize = 0;
m_csMap = NULL;
m_pResourceFile = NULL;
#ifdef FEATURE_PAL
m_pResourceDomain = NULL;
#endif // FEATURE_PAL
}// CCompRC
HRESULT Init(LPCWSTR pResourceFile, BOOL bUseFallback = FALSE);
void Destroy();
BOOL ShouldUseFallback()
{
LIMITED_METHOD_CONTRACT;
return m_bUseFallback;
};
static void SetIsMscoree() {s_bIsMscoree = TRUE;}
HRESULT LoadString(ResourceCategory eCategory, UINT iResourceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax , int *pcwchUsed=NULL);
HRESULT LoadString(ResourceCategory eCategory, LocaleID langId, UINT iResourceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax, int *pcwchUsed);
void SetResourceCultureCallbacks(
FPGETTHREADUICULTURENAMES fpGetThreadUICultureNames,
FPGETTHREADUICULTUREID fpGetThreadUICultureId
);
void GetResourceCultureCallbacks(
FPGETTHREADUICULTURENAMES* fpGetThreadUICultureNames,
FPGETTHREADUICULTUREID* fpGetThreadUICultureId
);
HRESULT LoadMUILibrary(HRESOURCEDLL * pHInst);
// Get the default resource location (mscorrc.dll for desktop, mscorrc.debug.dll for CoreCLR)
static CCompRC* GetDefaultResourceDll();
// Get the generic messages dll (Silverlight only, mscorrc.dll)
static CCompRC* GetFallbackResourceDll();
static void ShutdownDefaultResourceDll();
static void GetDefaultCallbacks(
FPGETTHREADUICULTURENAMES* fpGetThreadUICultureNames,
FPGETTHREADUICULTUREID* fpGetThreadUICultureId)
{
WRAPPER_NO_CONTRACT;
m_DefaultResourceDll.GetResourceCultureCallbacks(
fpGetThreadUICultureNames,
fpGetThreadUICultureId);
}
static void SetDefaultCallbacks(
FPGETTHREADUICULTURENAMES fpGetThreadUICultureNames,
FPGETTHREADUICULTUREID fpGetThreadUICultureId)
{
WRAPPER_NO_CONTRACT;
// Either both are NULL or neither are NULL
_ASSERTE((fpGetThreadUICultureNames != NULL) ==
(fpGetThreadUICultureId != NULL));
m_DefaultResourceDll.SetResourceCultureCallbacks(
fpGetThreadUICultureNames,
fpGetThreadUICultureId);
m_FallbackResourceDll.SetResourceCultureCallbacks(
fpGetThreadUICultureNames,
fpGetThreadUICultureId);
}
#ifdef USE_FORMATMESSAGE_WRAPPER
DWORD
PALAPI
static
FormatMessage(
IN DWORD dwFlags,
IN LPCVOID lpSource,
IN DWORD dwMessageId,
IN DWORD dwLanguageId,
OUT LPWSTR lpBuffer,
IN DWORD nSize,
IN va_list *Arguments);
#endif // USE_FORMATMESSAGE_WRAPPER
private:
HRESULT GetLibrary(LocaleID langId, HRESOURCEDLL* phInst);
#ifndef DACCESS_COMPILE
HRESULT LoadLibraryHelper(HRESOURCEDLL *pHInst,
SString& rcPath);
HRESULT LoadLibraryThrows(HRESOURCEDLL * pHInst);
HRESULT LoadLibrary(HRESOURCEDLL * pHInst);
HRESULT LoadResourceFile(HRESOURCEDLL * pHInst, LPCWSTR lpFileName);
#endif
// We do not have global constructors any more
static LONG m_dwDefaultInitialized;
static CCompRC m_DefaultResourceDll;
static LPCWSTR m_pDefaultResource;
// fallback resources if debug pack is not installed
static LONG m_dwFallbackInitialized;
static CCompRC m_FallbackResourceDll;
static LPCWSTR m_pFallbackResource;
// We must map between a thread's int and a dll instance.
// Since we only expect 1 language almost all of the time, we'll special case
// that and then use a variable size map for everything else.
CCulturedHInstance m_Primary;
CCulturedHInstance * m_pHash;
int m_nHashSize;
CRITSEC_COOKIE m_csMap;
LPCWSTR m_pResourceFile;
#ifdef FEATURE_PAL
// Resource domain is an ANSI string identifying a native resources file
static LPCSTR m_pDefaultResourceDomain;
static LPCSTR m_pFallbackResourceDomain;
LPCSTR m_pResourceDomain;
#endif // FEATURE_PAL
// Main accessors for hash
HRESOURCEDLL LookupNode(LocaleID langId, BOOL &fMissing);
HRESULT AddMapNode(LocaleID langId, HRESOURCEDLL hInst, BOOL fMissing = FALSE);
FPGETTHREADUICULTUREID m_fpGetThreadUICultureId;
FPGETTHREADUICULTURENAMES m_fpGetThreadUICultureNames;
BOOL m_bUseFallback;
static BOOL s_bIsMscoree;
};
HRESULT UtilLoadResourceString(CCompRC::ResourceCategory eCategory, UINT iResouceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax);
int UtilMessageBox(
HWND hWnd, // Handle to Owner Window
UINT uText, // Resource Identifier for Text message
UINT uCaption, // Resource Identifier for Caption
UINT uType, // Style of MessageBox
BOOL displayForNonInteractive, // Display even if the process is running non interactive
BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
...); // Additional Arguments
int UtilMessageBoxNonLocalized(
HWND hWnd, // Handle to Owner Window
LPCWSTR lpText, // Resource Identifier for Text message
LPCWSTR lpTitle, // Resource Identifier for Caption
UINT uType, // Style of MessageBox
BOOL displayForNonInteractive, // Display even if the process is running non interactive
BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
...); // Additional Arguments
int UtilMessageBoxVA(
HWND hWnd, // Handle to Owner Window
UINT uText, // Resource Identifier for Text message
UINT uCaption, // Resource Identifier for Caption
UINT uType, // Style of MessageBox
BOOL displayForNonInteractive, // Display even if the process is running non interactive
BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
va_list args); // Additional Arguments
int UtilMessageBoxNonLocalizedVA(
HWND hWnd, // Handle to Owner Window
LPCWSTR lpText, // Text message
LPCWSTR lpCaption, // Caption
UINT uType, // Style of MessageBox
BOOL displayForNonInteractive, // Display even if the process is running non interactive
BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
BOOL * pInputFromUser, // To distinguish between user pressing abort vs. assuming abort.
va_list args); // Additional Arguments
int UtilMessageBoxNonLocalizedVA(
HWND hWnd, // Handle to Owner Window
LPCWSTR lpText, // Text message
LPCWSTR lpCaption, // Caption
LPCWSTR lpDetails, // Details that may be shown in a collapsed extended area of the dialog (Vista or higher).
UINT uType, // Style of MessageBox
BOOL displayForNonInteractive, // Display even if the process is running non interactive
BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
BOOL * pInputFromUser, // To distinguish between user pressing abort vs. assuming abort.
va_list args); // Additional Arguments
int UtilMessageBoxCatastrophic(
UINT uText, // Text for MessageBox
UINT uTitle, // Title for MessageBox
UINT uType, // Style of MessageBox
BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
...);
int UtilMessageBoxCatastrophicNonLocalized(
LPCWSTR lpText, // Text for MessageBox
LPCWSTR lpTitle, // Title for MessageBox
UINT uType, // Style of MessageBox
BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
...);
int UtilMessageBoxCatastrophicVA(
UINT uText, // Text for MessageBox
UINT uTitle, // Title for MessageBox
UINT uType, // Style of MessageBox
BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
va_list args); // Additional Arguments
int UtilMessageBoxCatastrophicNonLocalizedVA(
LPCWSTR lpText, // Text for MessageBox
LPCWSTR lpTitle, // Title for MessageBox
UINT uType, // Style of MessageBox
BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
va_list args); // Additional Arguments
// The HRESULT_FROM_WIN32 macro evaluates its arguments three times.
// <TODO>TODO: All HRESULT_FROM_WIN32(GetLastError()) should be replaced by calls to
// this helper function avoid code bloat</TODO>
inline HRESULT HRESULT_FROM_GetLastError()
{
WRAPPER_NO_CONTRACT;
DWORD dw = GetLastError();
// Make sure we return a failure
if (dw == ERROR_SUCCESS)
{
_ASSERTE(!"We were expecting to get an error code, but a success code is being returned. Check this code path for Everett!");
return E_FAIL;
}
else
return HRESULT_FROM_WIN32(dw);
}
inline HRESULT HRESULT_FROM_GetLastErrorNA()
{
WRAPPER_NO_CONTRACT;
DWORD dw = GetLastError();
// Make sure we return a failure
if (dw == ERROR_SUCCESS)